
List All The Components
Posted by Bill Robinson
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.
Comments