Multiple PS_CFG_HOMEs with the DPK

Aug 10, 2016

Dan Iverson

One of my biggest criticisms of the DPK is that it doesn’t support multiple PS_CFG_HOME’s for app server and process scheduler domains. This has been the biggest roadblock for me as I attempt to use the DPK to deploy an 8.55 infrasturcture. Currently (as of 8.55.08), all Tuxedo domains are created under a single folder.

Tuxedo expects the PS_CFG_HOME environment variables to be set to know where to create domains. If you don’t set PS_CFG_HOME, Tuxedo’s default setting will create the domains under %USER%\psft\pt\8.xx.

With the DPK, there are parameters to set PS_CFG_HOME environment variable at the app server, process scheduler, and web server sections in psft_customizations.yaml. Use the ps_config_home: value to populate the value for all domains. Or, you can set different values for each domain using the ps_cfg_home_dir: inside the appserver_domain_list, prcs_domain_list, and pia_domain_list section.

When the DPK runs, it takes these values and sets up environment variables. If you have more than one PS_CFG_HOME specified for Tuxedo domains, the current DPK will only set environment variables once. The last PS_CFG_HOME specified will be the environment variable value when Tuxedo domains are created.

This is why the DPK only uses 1 PS_CFG_HOME for all Tuxedo domains; it doesn’t manage environment variables properly.

Setting PS_CFG_HOME for Every Domain

To fix this, we need to set the PS_CFG_HOME environment variable each time a Tuxedo domain is created (or booted). Puppet Providers handle the comamnd line calls to Tuxedo and setup programs. So a code change in the provider for Tuxedo domains where we need to make our change.

The Puppet Providers for Tuxedo are located under puppet\etc\modules\pt_config\lib\puppet\provider\. In the providers, when a command line command is built, a function execute_command() is used to handle the OS-level command line calls. Unfortunately, only the app server provider uses this function, because execute_command() takes two parameters: command and env. The env parameter lets us set environment variables for the command’s environment. Instead, we’ll use the Ruby syntaxt ENV[] set an environment variable before the command is executed.

App Servers

There are two base files for app server domains: psftdomain.rb and psftdomainboot.rb. They are parents objects to the pt_app_domain\app_domain.rb provider. The changes for application server domains can be made in the two parent files.

We’ll insert this code block before each command line call:

# PS_CFG_HOME Fix Begin 
if Facter.value(:osfamily) == 'windows' 
    ps_cfg_home_dir_norm = resource[:ps_cfg_home_dir].gsub('/', '\\') 
else 
    ps_cfg_home_dir_norm = resource[:ps_cfg_home_dir] 
end

ENV['PS_CFG_HOME'] = ps_cfg_home_dir_norm
Puppet.notice("     PS_CFG_HOME=#{ps_cfg_home_dir_norm}")
# PS_CFG_HOME Fix End

In psftdomain.rb, we’ll insert the code in the create() method before the begin code block:

def create pre_create()

  domain_name = resource[:domain_name]
  domain_type = get_domain_type()
  template_type = get_template_type()

  Puppet.debug("Creating domain: #{domain_name}")
  Puppet.debug("     with attributes #{resource.to_hash.inspect}")

  # PS_CFG_HOME Fix Begin
  if Facter.value(:osfamily) == 'windows'
    ps_cfg_home_dir_norm = resource[:ps_cfg_home_dir].gsub('/', '\\')
  else
    ps_cfg_home_dir_norm = resource[:ps_cfg_home_dir]
  end

  ENV['PS_CFG_HOME'] = ps_cfg_home_dir_norm
  Puppet.notice("     PS_CFG_HOME=#{ps_cfg_home_dir_norm}")
  # PS_CFG_HOME Fix End

  begin
    psadmin_cmd = File.join(resource[:ps_home_dir], 'appserv', 'psadmin')
    if Facter.value(:osfamily) == 'windows'

      command = "#{psadmin_cmd} #{domain_type} create -d #{domain_name} #{template_type} #{get_startup_settings} #{get_env_settings}"
      execute_command(command)
    else 
      domain_cmd('-m', '-s', '/bin/bash', '-l',  resource[:os_user], '-c',
                 "#{psadmin_cmd} #{domain_type} create -d #{domain_name} " +
                 "#{template_type} #{get_startup_settings} #{get_env_settings}")
    end

  rescue Puppet::ExecutionFailure => e
    raise Puppet::Error,
        "Unable to create domain #{domain_name}: #{e.message}"
  end

  post_create()
  @property_hash[:ensure] = :present

end

In psftdomainboot.rb, we’ll insert the code block in the execute_psadmin_action() method before the begin code block:

def execute_psadmin_action(action) 
  domain_name = resource[:domain_name] domain_type = get_domain_type()

  Puppet.debug("Performing action #{action} on domain #{domain_name}")

  # PS_CFG_HOME Fix Begin
  if Facter.value(:osfamily) == 'windows'
    ps_cfg_home_dir_norm = resource[:ps_cfg_home_dir].gsub('/', '\\')
  else
    ps_cfg_home_dir_norm = resource[:ps_cfg_home_dir]
  end

  ENV['PS_CFG_HOME'] = ps_cfg_home_dir_norm
  Puppet.notice("     PS_CFG_HOME=#{ps_cfg_home_dir_norm}")
  # PS_CFG_HOME Fix End

  begin
    psadmin_cmd = File.join(resource[:ps_home_dir], 'appserv', 'psadmin')
    if Facter.value(:osfamily) == 'windows'

      db_type = get_db_type()
      if db_type == 'ORACLE'
        set_user_env()
      end
      command = "#{psadmin_cmd} #{domain_type} #{action} -d #{domain_name}"
      command_output = execute_command(command)

    else
      os_user = resource[:os_user]
      if os_user_exists?(os_user) == false
        command_output="ERROR: os user #{os_user} does not exists"
      else
        command_output = domain_cmd('-m', '-s', '/bin/bash', '-',  os_user, '-c',
          "#{psadmin_cmd} #{domain_type} #{action} " + "-d #{domain_name}")
      end
    end
    return command_output

  rescue Puppet::ExecutionFailure => e
    raise Puppet::ExecutionFailure, "Unable to perform action #{action}: #{e.message}"
  end

end

Process Schedulers

For process scheduler domains, we need to modify the pt_prcs_domain\prcs_domain.rb provider file. We’ll insert the code block in the pre_create() method.

def pre_create 
  super()

  domain_name = resource[:domain_name]
  cfg_home_dir = resource[:ps_cfg_home_dir]

  # PS_CFG_HOME Fix Begin
  if Facter.value(:osfamily) == 'windows'
    ps_cfg_home_dir_norm = resource[:ps_cfg_home_dir].gsub('/', '\\')
  else
    ps_cfg_home_dir_norm = resource[:ps_cfg_home_dir]
  end

  ENV['PS_CFG_HOME'] = ps_cfg_home_dir_norm
  Puppet.notice("     PS_CFG_HOME=#{ps_cfg_home_dir_norm}")
  # PS_CFG_HOME Fix End

  domain_dir = File.join(cfg_home_dir, 'appserv', 'prcs', domain_name)
  if File.exist?(domain_dir)
    Puppet.debug("Removing Process Scheduler domain directory: #{domain_dir}")
    FileUtils.rm_rf(domain_dir)
  end

end

Closing Thoughts

Fixing the limitation of one PS_CFG_HOME with the DPK was the last hurdle for me to start using the DPK for all of my environment builds. With the DPK, and some custom Puppet code to extend the DPK, we are working on automating our environment builds. I posted the code changes on GitHub if you want to get the fix from there.

I have an SR open for this issue, but I also have an Idea on the Oracle Community site. If you would like to see this change incorporated into the delivered DPK, go vote for the idea.

 


Note: This was originally posted by Dan Iverson and has been transferred from a previous platform. There may be missing comments, style issues, and possibly broken links. If you have questions or comments, please contact [email protected].