Share:|

Unlike the other object types we've looked at in listallthethings so far, there does not seem to be a Component.listAllByGroup type of blcli command available.  But the pattern is going to be similar as we've found with the other workspace objects.  With the other object types the listAllByGroup command contained calls to convert a group path to id, use that id with one of the findAll commands in the namespace and then get the name or DBKey of the returned objects.  We look in the Component namespace and see a findAllByComponentGroup which takes the ComponentGroup id.  Let's check the ComponentGroup namespace (or SmartComponentGroup) for the groupNameToId command and we see it's there.  Great.  The namespaces usually contain the basics like getName, getDBKey, getId.  Putting together the series of blcli commands:

 

blcli_execute SmartComponentGroup groupNameToId "/Workspace/All Components"
# or ComponentGroup.groupNameToId
blcli_storelocal componentGroupId
blcli_execute Component findAllByComponentGroup ${componentGroup} false
blcli_execute Component getDBKey
blcli_execute Utility setTargetObject
blcli_execute Utility listPrint
blcli_storelocal componentKeys

 

That was pretty easy.  Components are like Servers in that they don't need to exist in a workspace folder (unlike Jobs, DepotObjects and Templates).  However they are associated with Templates and Servers and sometimes we want to list all the Components associated with a server, regardless of template or list all the components associated with a template.  We might also want to list if the Component is "valid" which means the discovery conditions are met.  A component becomes invalid if the Component was discovered on a server and then later something changed on the server or in the discovery conditions and that component (server) no longer meets the discovery conditions.  For example - you run discovery for one of the out-of-the-box compliance templates, like the DISA STIG, for your Windows 2008 servers.  A number of components are created, one for each of your 2008 servers.  Later, you upgrade a handful of the 2008 servers to 2012.  You re-run discovery for the 2008 Windows STIG template and the components of that template for the now 2012 servers should be flagged as invalid because the discovery condition is that the server is Windows 2008 and now it's Windows 2012.  We will also get the full name, and associated device (normally the component name includes the device).  Also remember that it's possible to have more than one component for a template on a single server - in the event you are using Components to model an application that has multiple instances on a single system, eg the BladeLogic Application Server or an Oracle Database.  The point of the training session here on components is to provide some examples of what information I might want to retrieve about a component in my script.  Let's get into the examples.

 

I'll look in my trust Unreleased blcli commands and documentation  reference in the Component namespace and see if there are some commands that look like they will do what I want.  I'm really just reading the name, looking at the inputs and trying it to see if I get what I want.

 

First I want to pass a server name and get all the components and the associated templates.  I need something in the Server space to convert the name to an id or DBKey - yes that exists.  Now in the Component namespace I need to see if there's something to list the components by server.  I see a couple: findAllLatestByDevice and findAllLatestDBKeysByDevice.  Those look pretty good.  The first one returns the component objects, I'd have to run a Component.getDBKey and then dump the list.  That's not too bad. The second one returns a message Command execution failed. java.lang.IllegalStateException: Must be on app server.  Well I am on an appserver so I'm not sure why that's happening.  Welcome to the unreleased commands.  So I'll use the first one.  I want to get the template; I see a Component.getTemplateKey and I can feed that into some of the commands I used in  List All The Component Templates to get the group path to the template, and I see a Component.getName, and I see Component.isValid.  I'll script all that up:

blcli_execute Server getServerIdByName ${serverName}
blcli_storelocal serverId
blcli_execute Component findAllLatestByDevice ${serverId}
blcli_execute Utility storeTargetObject components
blcli_execute Utility listLength
blcli_storelocal listLength
for i in {0..$((${listLength}-1))}
        do
        blcli_execute Utility setTargetObject components
        blcli_execute Utility listItemSelect ${i}
        blcli_execute Utility setTargetObject
        blcli_execute Component getName
        blcli_storelocal componentName
        blcli_execute Component isValid
        blcli_storelocal isValid
        blcli_execute Component getTemplateKey
        blcli_storelocal templateKey
        blcli_execute Template findByDBKey ${templateKey}
        blcli_execute Template getName
        blcli_storelocal templateName
        blcli_execute Template getGroupId
        blcli_storelocal templateGroupId
        blcli_execute Group getQualifiedGroupName 5008 ${templateGroupId}
        blcli_storeenv templateGroupPath
        echo "${componentName},${isValid},${templateGroupPath}/${templateName}"
done

 

Now for the list of Components and their associated servers for a template.  I see a couple versions of Component.findAllByTemplate - one takes the template key, the other the template id.  Since I already know how to get the template key (Template.getDBKeyByGroupAndName).  Then I'll follow pretty much the same pattern as above with whatever blcli calls I need to get the component and associated server info.

template="/Workspace/MyTemplates/TestTemplate1"
blcli_execute Template getDBKeyByGroupAndName "${template%/*}" "${template##*/}"
blcli_storelocal templateKey
blcli_execute Component findAllByTemplate ${templateKey}
blcli_execute Utility storeTargetObject components
blcli_execute Utility listLength
blcli_storelocal listLength
for i in {0..$((${listLength}-1))}
        do
        blcli_execute Utility setTargetObject components
        blcli_execute Utility listItemSelect ${i}
        blcli_execute Utility setTargetObject
        blcli_execute Component getName
        blcli_storelocal componentName
        blcli_execute Component isValid
        blcli_storelocal isValid
        blcli_execute Component getDeviceId
        blcli_storelocal deviceId
        blcli_execute Server getServerNameById ${deviceId}
        blcli_storelocal serverName
        echo "${componentName},${isValid},${serverName}"
done

 

Since this is starting to get repetitive (which is good that we can follow the same patters between workspaces) I like to throw in something new here and there to keep it interesting.  At the top I have:

template="/Workspace/MyTemplates/TestTemplate1"

blcli_execute Template getDBKeyByGroupAndName "${template%/*}" "${template##*/}"

What's going on with that second line ?  The Template.getDBKeyByGroupAndName command takes the template group and name as inputs.  I have a variable named template and I passed in some gibberish to my blcli command.  If you recall NSH (what BSA uses for its command line shell) is based on ZSH, which is a Unix shell like bash, tcsh, csh, etc.  What's happening here is parameter expansion.   From the article:

${name#pattern}

${name##pattern}

If the pattern matches the beginning of the value of name, then substitute the value of name with the matched portion deleted; otherwise, just substitute the value of name. In the first form, the smallest matching pattern is preferred; in the second form, the largest matching pattern is preferred.

${name%pattern}

${name%%pattern}

If the pattern matches the end of the value of name, then substitute the value of name with the matched portion deleted; otherwise, just substitute the value of name. In the first form, the smallest matching pattern is preferred; in the second form, the largest matching pattern is preferred.

So the first one is matching the /* in the string /Workspace/MyTemplates/TestTemplate1 from the end so just '/TestTemplate1' and removing that substring from the overall string and returns just the folder path (/Workspace/MyTemplates).  The second one is matching */ out of the string from the beginning and because of the ## it's matching everything, so '/Workspace/MyTemplates' and deleting that from the string.  If there was just one # then it would return 'Workspace/MyTemplates/TestTemplate'.  This is the same thing as using the dirname and basename commands from the Unix shell.  The advantage of using the parameter substitution is you don't need to spawn off a child process to use it and it's cool.

 

Hopefully that was a quick and fun diversion into shell scripting since we are seeing a lot of the same kind of command sequences when we are listing out the various objects.