Manage your WebLogic JMS config with Puppet

Puppet code WebLogic is a rich JEE container. There is a lot of stuff you can define and settings you need to manage. In the blog post “Using Puppet to install and manage your WebLogic infrastructure”, we used Puppet to install the basic WebLogic software and create a simple WebLogic domain. In this blog post we are going to show you how to use the custom types provided by the wls_config module, to extend this domain and add JMS servers, queues, and topics.

The example

We are going to use the JMS setup code that is provided in the reference implementation. You can find the reference implementation here, at our github account.

The focus of this blog post will be the JMS setup. You can easily follow along. In the reference implementation, the JMS code is provided in one Puppet file.

The Puppet class

Before we dive into the code itself, let’s see how we named the Puppet class and how we included it into the configuration.

class profile::wls::wlsonly::jms(
  Hash    $servers,
  String  $domain_name,
  String  $cluster_name,
)
{
...
}

The class is called profile::wls::wlsonly::jms and it has three parameters:

  • $servers is a hash containing all managed servers and their properties
  • $domain_name is a string containing the name
  • $cluster_name is the string containing the name of the cluster

In the connect configuration for this module, we replace in these variables with the actual values we need.

To make this code part of the configuration, we included this class inside the profile profile::wls::wlsonly

class profile::wls::wlsonly
{
  contain profile::wls::wlsonly::domain
  contain profile::wls::wlsonly::jms

  Class['profile::wls::wlsonly::domain']
  -> Class['profile::wls::wlsonly::jms']
}

Another place to include it, is in the role. We choose to include it in the wlsonly profile because we need this configuration to create a valid wlsonly domain.

To ensure the domain is created before we start with the JMS settings, we create the dependency between Class['profile::wls::wlsonly::domain'] and Class['profile::wls::wlsonly::jms'].

The -> at the begin?

Some of you might look strange at the -> at the beginning of the line. Most of the published Puppet code puts these -> at the end of a line. We have noticed that when you are debugging, sometimes it is convenient to comment out a class. Using this syntax, it is easy. Specially when your role or profile contains a lot of classes. Just comment out the contain statement and the line containing the dependency. Then you are done. No need to edit the lines. This is very convenient. When you put the -> at the end of a line however, you have to edit more.

When you use Geppetto, you cannot use this trick. Geppetto auto formats the line to have the -> at the end of the line.

The JMS server

Before you can add JMS objects. One or more JMS servers need to exist. In this sample, we create a JMS server for every managed server in our domain. Let’s see how we do this.

$server_array = $servers.keys
$server_array.each | $index, $server | {
  #
  # Create a JMS server for every managed server and target the JMS server to the managed server.
  # because the set of managed servers, is a variable, this code works if you have 1 or more servers.
  #
  wls_jmsserver { "${domain_name}/jmsServer${index}":
    ensure                      => 'present',
    allows_persistent_downgrade => '0',
    bytes_maximum               => '-1',
    target                      => [$server],
    targettype                  => ['Server'],
  }

The $servers variable is a Hash. It looks like this when passed to the Puppet class:

{
  wls1 => {
    machine_name:  'wls_machine_1',
    listenaddress: '10.10.10.30',
  }
  wls2 => {
    machine_name:  'wls_machine_2',
    listenaddress: '10.10.10.31,
  }
}

Because we want to target the JMS servers at the managed servers that are defined in this data structure, we need to extract the node names from this data. We use the keys function for this. This code:

$server_array = $servers.keys

returns an array containing the names of the managed servers. We can use this array to iterate over and create a JMS server for every managed server.

$server_array.each | $index, $server | {
  ...
  wls_jmsserver { "${domain_name}/jmsServer${index}":
    ...
    target                      => [$server],
    targettype                  => ['Server'],
    ...
  }

Puppet and WebLogic require unique resource names. Therefore we use a number in the name to create different JMS servers names for every server.

Because we want to target the JMS server at the managed server, we fill the target and targettype properties.

Two subdeployments

Now we have the JMS servers up and running. Next we start by creating subdeployments. Two in fact. The first subdeployment we create is a subdeployment targeted at JMS servers we created in the last paragraph.

wls_jms_subdeployment { "${domain_name}/jmsClusterModule:jmsServers":
  ensure     => 'present',
  target     => $jms_targets,
  targettype => $jms_target_types,
}

The resource title

You can see that in the resource name we use .../jmsClusterModule:jmsServers. Every resource in the wls_config module has a naming scheme like that. We start with the optional domain name. Then we use a slash (\) as separator and follow with all the elements of the resource name separated by a double colon. In essence, this naming schema tells you that the later part of the name is a child of the part before. There is, however, no need to explicitly require the parent resource. The custom types in wls_config, all use autorequire for the parent types used in the Puppet title.

We would also like to have a subdeployment targets at the running WebLogic cluster.

wls_jms_subdeployment { "${domain_name}/jmsClusterModule:wlsServers":
  ensure     => 'present',
  target     => [$cluster_name],
  targettype => ['Cluster'],
}

Different than the previous subdeployment, this JMS subdeployment is targeted at the WebLogic cluster.

The JMS objects

Finally, we have finished building the context for JMS queues, topics and connection factories. Now we can start setting up the real JMS stuff. For all the JMS definitions, we use the same pattern. If we define more than one JMS object of a certain type, we first define a set of default attributes. Check out the Puppet documentation if you would like to know more about this.

Wls_jms_connection_factory {
  ensure                    => 'present',
  attachjmsxuserid          => '0',
  clientidpolicy            => 'Restricted',
  defaultdeliverymode       => 'Persistent',
  ...
}

Warning

Overuse of defaults

Although these defaults keeps you object definitions DRY, they also can make your code difficult to read. Use defaults only for sets of attributes that are real defaults for certain types of objects.

These defaults allow us to keep the actual object definitions as concise as possible. Here is the definition of a JMS queue:

wls_jms_queue { "${domain_name}/jmsClusterModule:Queue1":
  errordestination  => 'ErrorQueue',
  expirationpolicy  => 'Redirect',
  jndiname          => 'jms/Queue1',
  subdeployment     => 'jmsServers',
}

The reference implementation contains more queues, topics and connection factories. But they all use the same pattern. With this code done, we have implemented our total JMS setup in Puppet. We have done it in a way that is very good maintainable and extensible.

NOW it is your turn!

We hope this article has shown you how easy it is to setup a JMS configuration for your systems. After you have created your base setup with JMS servers and JMS modules, it becomes extremely easy to add queues or topics or change attributes of existing JMS objects.

Check out the documentation of wls_config for more information about this module and all the possibilities you have for creating JMS objects and setting their attributes. If you are just starting, check out our FREE trial license to get going.