Pattern-type (Part 2): Create step-by-step a Master-Slave pattern-type with SmartCloud Application Workload Services

After having created the Create step-by-step a simple pattern-type with SmartCloud Application Workload Services” article, I challenged myself to create a Master-Slave pattern-type. The main difference consist of creating a link between both servers from the Master to the Slave, and retrieve some information from the Slave (ie: IP address) to configure the Master.

I would like to stress the difference between pattern-type and pattern. A pattern-type provides all components, links, scalability rules… to build a pattern. The best example is the pattern-type for Web-Application (see demo) which provides Enterprise Application, Database components and scalability rules to design your own pattern which you will be able to deploy multiple time. So in this article we show how to create a pattern-type which requires more effort than create a pattern based on a pattern-type. ISV and/or company with home made application which not fit one of the existing pattern-type would be interested in this as pattern-type allows to put all the infrastructure intelligence in the pattern-type in order to deliver the best pattern for your customer.

Don’t forget also that next to virtual application pattern with their pattern-type you have to capability to create virutal system pattern, which allows you to deploy topology with your own images and scripts.

So, the appmodel we are looking for is:

I will not focus more on the creation of the two components are it was already explained in the part 1 of this serie. One of the component will be the Master and the other Slave. Let’s focus on the link between the Master and Slave.

Application Model:

The appmodel.json becomes:

[
    {
        "id": "Master",
        "label": "Master component",
        "description": "Master component",
        "thumbnail": "appmodel/images/thumbnail/HCenter.png",
        "image": "appmodel/images/HCenter.png",
        "type": "component",
        "attributes":[
            {
               "id":"Mattr1",
               "label":"Master Attribute 1",
               "sampleValue":"master str",
               "type":"string",
               "required": true
            }
         ]
    },
    {
        "id": "Slave",
        "label": "Slave component",
        "description": "Slave component",
        "thumbnail": "appmodel/images/thumbnail/HCenter.png",
        "image": "appmodel/images/HCenter.png",
        "type": "component",
        "attributes":[
            {
               "id":"Sattr1",
               "label":"Slave Attribute 1",
               "sampleValue":"slave str",
               "type":"string",
               "required": true
            }
         ]
    },
    {
        "id": "MasterSlaveLink",
        "label": "MasterSlave link",
        "description": "MasterSlave link",
        "type": "link",
	    "source":[
    	   "Master"
      	],
        "target":[
           "Slave"
      	],
        "attributes":[
            {
               "id":"MSattr1",
               "label":"MasterSlave Attribute 1",
               "sampleValue":"master-slave str",
               "type":"string",
               "required": true
            }
         ]
    }
]

The last the element has been added in to appmodel, his type is ‘link’ and it specifies a source and a target. The source is the Master element and the target the Slave element.

Physical model:

The Master looks like:

{
    "vm-templates": [
        {
            "name": "${prefix}-MasterSlave",
            "roles": [
                {
                    "parms": {
                        "Attr1": "$attributes.Mattr1"
                    },
                    "type": "Master",
                    "name": "Master"
                }
            ],
            "packages":["Master"]
        }
    ]
}

The Slave looks like:

{
    "vm-templates": [
        {
            "name": "${prefix}-MasterSlave",
            "roles": [
                {
                    "parms": {
                        "Attr1": "$attributes.Sattr1"
                    },
                    "type": "Slave",
                    "name": "Slave"
                }
            ],

            "packages":["Slave"]
        }
    ]
}

and the most importante, the MasterSlave.vm looks like:

## Link templates render the depends objects to be added to the source role.

## sourceRole is required to locate the source of the link.  Value is the type of the source role.
#set( $sourceRole = "Master" )

## Obtain a tuple related to the matching target role:  target.template == vm-template that holds the target role; target.role == role
## String argument is the type of the target role.
#set( $target = $provider.getMatchedRole($targetFragment, "Slave") )
[
    {
        "role": "${target.template.name}.${target.role.name}",
        "type": "Slave",
        "parms": {
            "Attr1": "$attributes.MSattr1"
        }
    }
]

There is some conventions here:

1) The role must be ${target.template.name}.${target.role.name}

2) The type must be the type of the target element.

The OSGI directory must be updated too with a new file specifying to velocity to transform this new physical model.

and of course the MANIFEST.MF must be updated too:

Manifest-Version: 1.0
Bundle-ManifestVersion: 2
Bundle-Name: com.itdove.mydemo
Bundle-SymbolicName: com.itdove.mydemo
Bundle-Version: 1.0.0
Import-Package:  com.ibm.json.java,
 com.ibm.maestro.common.http,
 com.ibm.maestro.common.utils,
 com.ibm.maestro.model.transform,
 com.ibm.maestro.model.transform.template,
 com.ibm.maestro.plugin.services,
 com.ibm.websphere.ras,
 com.ibm.websphere.ras.annotation,
 com.ibm.ws.ffdc
Bundle-RequiredExecutionEnvironment: JavaSE-1.6
Service-Component: OSGI-INF/MasterTransform.xml,OSGI-INF/SlaveTransform.xml,OSGI-INF/MasterSlaveLinkTransform.xml

Now, how the parts must be structured. As the Master has a dependency on Slave, the structure should be:

All these scripts will run in a certain order, please refer to IWD User Guide for more information.

The ‘changed.py’ scripts will run on the Master node and use the IP address of the Slave. How this is done?

First in the configure.py of the Slave, I added the following line:

maestro.export[‘Slave_IP’] = maestro.node[‘instance’][‘private-ip‘];

This will copy the Slave IP address into the maestro environment of the current role.

In the changed.py and not in another file, I added:

import maestro
...
deps = maestro.deps
added = maestro.added
myrole = added[0]
HOST = deps[myrole]['Slave_IP'];
logger = logging.getLogger("configure.py")
logger.debug("Configure MasterSlaveLink with SlaveIP=%s" % HOST);

This will read the value of the ‘Slave_IP’ attribute in the first dependend role of the Master vm-templates. The dependend role is automatically added to the Master vm-template at run-time.

After deploying this new pattern-type in my environment, I can run the test.

Final Test:

and we can see in the Master log file that the Slave IP is available:

You can see we have a message ‘Configure MasterSlaveLink with SlaveIP=170.225.184.208’.

Conclusion:

It is quite easy to create a link between two component if we respect the naming convention.

Source of information:

– IWD infocenter

Plug-in Developer’s Guide IBM Workload Deployer (needs an ibm.com id which can be created online).