Showing posts with label wsadmin. Show all posts
Showing posts with label wsadmin. Show all posts

Wednesday, 20 April 2016

Stopping and starting WAS application modules separately via wsadmin

Allow starting and stopping an individual Web or EJB modules using an undocumented call to the ApplicationManager object.

Get a reference to the relevant ApplicationManager object in the usual way:
appManager = AdminControl.queryNames
('type=ApplicationManager,process=myClusterMember1,node=myNode,*')

List the operations available for the appManager object...
print Help.operations(appManager)

This results in the following output …
void startApplication(java.lang.String)  
java.lang.Boolean _canStopApplication(java.lang.String) 
void stopApplication(java.lang.String) 
void _startModule(java.lang.String, java.lang.String) 
void _stopModule(java.lang.String, java.lang.String) 
void _applicationInstalled(java.lang.String) 
void _applicationUninstalled(java.lang.String)

The two methods we're interested in are  _startModule and _stopModule, both of which take two arguments of type String.

True to form the IBM documentation was awful.
print Help.operations(appManager, '_startModule')


Provides the following following output:
void _startModule(java.lang.String, java.lang.String)
Description: Start Application Module - This method is intended for WebSphere internal use only.  Its function is undocumented and is subject to change at any time.

Parameters:
Type  java.lang.String
Name  applicationName
Description  Application Name

Type  java.lang.String
Name  moduleURI
Description  Module Name 


It took me a while to work out how to format the arguments, here's the correct form:
AdminControl.invoke(<reference to app manager>, '<action>', '<app name> <module name>')

For example:
AdminControl.invoke(appManager,  '_startModule',  'MyApp  MyWebModule' )

As you can see, there are three arguments as follows:
- The reference to the ApplicationManager object
- The action
- A string which is the application name concatenated with the module name (separated by a space)



So, a nice easy way to do this would be:
appManager = AdminControl.queryNames('type=ApplicationManager,process=server1,node=node1,*')
appName = 'MyApp'
moduleName = 'MyWebModule'
args = appName + '  ' + moduleName
adminControl.invoke(appManager,  '_startModule',  args )


I also found out that if you're using a later wsadmin client (e.g. the one that ships with WAS 8.5 and above) that the third argument can be an array:
AdminControl.invoke(appManager,  '_startModule' ,  ['MyApp' , 'MyWebModule'] )

Here's an example of how I used this in the real world when I needed to start a WebModule after hot deploying it. 

Thursday, 19 March 2015

Configure JVM heap for WAS cluster members

Nice and simple if you have many JVM's in your cluster.
Note the wildcard feature when listing AdminConfig types (Line 24), very handy.

#=================================================================
# Setup
#=================================================================
import sys
clusterName = sys.argv[0]
min = sys.argv[1]
max = sys.argv[2]

#=================================================================
# Subs
#=================================================================
def getJvms(clusterName):
        # Get the cluster ID
        cluster = AdminConfig.list('ServerCluster', '*'+clusterName+'*')

        # Get a list of the clusters members
        members = AdminConfig.showAttribute(cluster, 'members')
        memberArray = members.split('[')[1].split(']')[0].split(' ')

        # Detemine JVM's
        jvms = []
        for member in memberArray:
                memberName = AdminConfig.showAttribute(member, 'memberName')
                jvms.append(AdminConfig.list('JavaVirtualMachine', '*'+memberName+'*'))
        return jvms

 

def setHeap(jvms, min, max):
        for jvm in jvms:
                print 'Setting '+jvm+' heap sizes of '+str(min)+' and '+str(max)
                AdminConfig.modify(jvm, [['initialHeapSize', min]])
                AdminConfig.modify(jvm, [['maximumHeapSize', max]])


#=================================================================
# Main
#=================================================================
jvms = getJvms(clusterName)
setHeap(jvms, min, max)
AdminConfig.save()

Thursday, 5 March 2015

wsadmin AdminApp.install with wildcards (and what on earth were they thinking with the nested argument structure?)

This always used to drive me bonkers because of the parameters needed for 
-MapModulesToServers
-MapWebModToVH
-CtxRootForWebMod.  

Then I realised these could be wild-carded. The result still looks a bit archaic but it's a big improvement.
import sys

war = sys.argv[0]
name = sys.argv[1]
cluster = sys.argv[2]
cr = sys.argv[3]
cellId = AdminConfig.list('Cell')
cell = AdminConfig.showAttribute(cellId, 'name')

 AdminApp.install(war, '[ -appname '+name+' -contextroot '+cr+' 
        -MapModulesToServers [[ .* .* WebSphere:cell='+cell+',cluster='+cluster+' ]] 
        -MapWebModToVH [[ .* .* default_host ]] 
        -CtxRootForWebMod [[ .* .* '+cr+' ]]]' )

AdminConfig.save()

It's worth noting that only -MapWebModToVH and -MapModulesToServer are required, therefore a if you're in a hurry you can use a shorter version:
import sys

war = sys.argv[0]
cluster = sys.argv[1]

AdminApp.install(war, '[-MapWebModToVH [[ .* .* default_host ]] 
        -MapModulesToServers [[ .* .* WebSphere:cluster='+cluster+']]]')

AdminConfig.save()

If you chose this simpler method the Application name is chosen for you and the context root is set to /

Lastly (and this is where my OCD really kicked in) ... I really didn't like the way the second argument to AdminApp.install was just a long string, so I worked out that you can also do it like this...  (not really sure if it's any simpler though)


import sys

war = sys.argv[0]
cluster = sys.argv[1]

AdminApp.install( 
    war, [
        '-MapWebModToVH', 
        [ [ '.*', '.*', 'default_host'] ],  
        '-MapModulesToServers', 
        [ [ '.*', '.*', 'WebSphere:cluster='+cluster ] ] 
    ]
)
AdminConfig.save()

Friday, 6 February 2015

wsadmin script to create a datasource (and of course a JDBC provider and auth alias) on WebSphere

Just a quicky so I can remember this.
Will need to modify the provider if you want to use something other than Oracle.

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Set up
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import sys

cellName = AdminConfig.list('Cell')
dsName=sys.argv[0]
userName=sys.argv[1]
password=sys.argv[2]
driverPath=sys.argv[3]
dbHost=sys.argv[4]
dbPort=sys.argv[5]
dbSid=sys.argv[6]

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Subs
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
def createProvider():
      print "Creating JDBC Provider"
      provider = AdminTask.createJDBCProvider('[-scope Cell='+cellName+' 
        -databaseType Oracle -providerType "Oracle JDBC Driver" 
        -implementationType "XA data source" -name "Oracle JDBC Driver (XA)" -description "" 
        -classpath ['+driverPath+'] -nativePath "" ]') 
 return(provider)

def createAuthAlias():
      print "Creating Auth Alias"
      security = AdminConfig.getid('/Security:/')
      alias = ['alias', dsName+'_alias']
      userid = ['userId', userName]
      pw = ['password', password]
      jaasAttrs = [alias, userid, pw]
      aliasId = AdminConfig.create('JAASAuthData', security, jaasAttrs)
      return(aliasId)

def createDataSource(provider, aliasId):
      print "Creating DataSource"
      aliasName =  AdminConfig.showAttribute(aliasId, 'alias') 
      ds = AdminTask.createDatasource(provider, '[-name '+dsName+' -jndiName jdbc/'+dsName+' 
        -dataStoreHelperClassName   com.ibm.websphere.rsadapter.Oracle11gDataStoreHelper 
        -containerManagedPersistence true -componentManagedAuthenticationAlias 
        -xaRecoveryAuthAlias '+aliasName+' 
        -configureResourceProperties [[URL java.lang.String jdbc:oracle:thin:@'+dbHost+':'+dbPort+':'+dbSid+']]]')
      AdminConfig.create('MappingModule', ds, '[[authDataAlias '+aliasName+'] [mappingConfigAlias ""]]')

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Main program
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
provider = createProvider()
aliasId = createAuthAlias()
createDataSource(provider, aliasId)

Monday, 5 January 2015

wsadmin - list methods of a Python module

This can be quite handy.

To see a list of references (to modules, strings, arrays etc) type dir() from the wsadmin prompt as follows...

wsadmin>dir()

The response will be something like...
['AdminApp', 'AdminApplication', 'AdminAuthorizations', 'AdminBLA', 'AdminClusterManagement', 'AdminConfig', 'AdminControl', 'AdminJ2C', 'AdminJDBC', 'AdminJMS', 'AdminLibHelp', 'AdminNodeGroupManagement', 'AdminNodeManagement', 'AdminResources', 'AdminServerManagement', 'AdminTask', 'AdminUtilities', 'ApplyPerfTuning', 'Help', 'LTPA_LDAPSecurityOff', 'LTPA_LDAPSecurityOn', 'TypedProxy', '__builtin__', '__doc__', '__name__', 'bsf', 'cellName', 'checkuserpw', 'doAuthenticationMechanism', 'doGlobalSecurity', 'doGlobalSecurityDisable', 'doLDAPUserRegistry', 'domainHostname', 'exportLTPAKey', 'flag', 'foo', 'forceSync', 'generateLTPAKeys', 'getLDAPUserRegistryId', 'getLTPAId', 'getSecId', 'getSecurityAdminMbean', 'imp', 'java', 'ldapPassword', 'ldapPort', 'ldapServer', 'ldapServerId', 'ldapUserRegistryId', 'lineSeparator', 'ltpaId', 'main', 'nodeName', 'osgiApplicationConsole', 'secMbean', 'securityId', 'securityoff', 'securityon', 'sleep', 'sys', 'whatEnv'] 

For those that are python modules (for example AdminResources is a module) you can run dir(<module name>) to list the methods within the function, fot exmaple...

wsadmin>dir(AdminResources)

Produces the following output...
['AdminUtilities', '__doc__', '__file__', '__name__', 'bundleName', 'createCompleteMailProvider', 'createCompleteMailProviderAtScope', 'createCompleteResourceEnvProvider', 'createCompleteResourceEnvProviderAtScope', 'createCompleteURLProvider', 'createCompleteURLProviderAtScope', 'createJAASAuthenticationAlias', 'createLibraryRef', 'createMailProvider', 'createMailProviderAtScope', 'createMailSession', 'createMailSessionAtScope', 'createProtocolProvider', 'createProtocolProviderAtScope', 'createResourceEnvEntries', 'createResourceEnvEntriesAtScope', 'createResourceEnvProvider', 'createResourceEnvProviderAtScope', 'createResourceEnvProviderRef', 'createResourceEnvProviderRefAtScope', 'createScheduler', 'createSchedulerAtScope', 'createSharedLibrary', 'createSharedLibraryAtScope', 'createURL', 'createURLAtScope', 'createURLProvider', 'createURLProviderAtScope', 'createWorkManager', 'createWorkManagerAtScope', 'help', 'resourceBundle', 'sys']

You'll see that one of the methods is createJAASAuthenticationAlias, which means you can run

wsadmin>AdminResources.createJAASAuthenticationAlias( authAlias, uid, password)

NOTE: I found out the args by running AdminResources.help('createJAASAuthenticationAlias')

Here's an example of importing a python module and querying/using it accordingly ...

wsadmin>import time

wsadmin>dir()
['AdminApp', 'AdminApplication', 'AdminAuthorizations', 'AdminBLA', 'AdminClusterManagement', 'AdminConfig', 'AdminControl', 'AdminJ2C', 'AdminJDBC', 'AdminJMS', 'AdminLibHelp', 'AdminNodeGroupManagement', 'AdminNodeManagement', 'AdminResources', 'AdminServerManagement', 'AdminTask', 'AdminUtilities', 'ApplyPerfTuning', 'Help', 'LTPA_LDAPSecurityOff', 'LTPA_LDAPSecurityOn', 'TypedProxy', '__builtin__', '__doc__', '__name__', 'bsf', 'cellName', 'checkuserpw', 'doAuthenticationMechanism', 'doGlobalSecurity', 'doGlobalSecurityDisable', 'doLDAPUserRegistry', 'domainHostname', 'exportLTPAKey', 'flag', 'foo', 'forceSync', 'generateLTPAKeys', 'getLDAPUserRegistryId', 'getLTPAId', 'getSecId', 'getSecurityAdminMbean', 'imp', 'java', 'ldapPassword', 'ldapPort', 'ldapServer', 'ldapServerId', 'ldapUserRegistryId', 'lineSeparator', 'ltpaId', 'main', 'nodeName', 'osgiApplicationConsole', 'secMbean', 'securityId', 'securityoff', 'securityon', 'sleep', 'sys', 'time', 'whatEnv']
 

wsadmin>time
<jclass org.python.modules.time at -1272186292>


wsadmin>type(time)
<jclass org.python.core.PyJavaClass at -779978699>


wsadmin>dir(time)
['__doc__', 'accept2dyear', 'altzone', 'asctime', 'classDictInit', 'clock', 'ctime', 'daylight', 'gmtime', 'localtime', 'mktime', 'sleep', 'strftime', 'time', 'timezone', 'tzname']


wsadmin>time.ctime()
'Tue Jan 06 10:20:33 2015'


Thursday, 4 September 2014

Create JNDI entries for scalars with wsadmin

# createJndiEntry.py
# Author: Bob Clarke
# Date: 28/08/2014

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Define subs
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

def repExists(repName):
        print 'Checking if Resource Env Provider '+repName+' exists'
        rep = AdminConfig.getid('/ResourceEnvironmentProvider:'+repName+'/')
        return rep

def createRep(repName):
        print 'Creating Resource Env Provider with name '+repName
        rep = AdminConfig.create('ResourceEnvironmentProvider', cellId, [['name',repName]] )
        # Not sure why I need this "Referencable", seems to be a requirement
        AdminConfig.create('Referenceable', rep, [['factoryClassname', 'fClass1'],['classname', 'Class1']])
        return rep

def reeExists(key):
        print 'Checking if jndi entry of salsa/'+key+' exists'
        ree = AdminConfig.getid('/ResourceEnvEntry:'+key+'/')
        return ree

def createJndiRef(rep,key):
        print 'Creating JNDI entry salsa/'+key
        ree = AdminConfig.create('ResourceEnvEntry', rep, [['name', key], ['jndiName', 'salsa/'+key]])
        return ree

def createPropSet(ree,key):
        print 'Creating an empty property set'
        propSet = AdminConfig.create('J2EEResourcePropertySet',ree, [])
        return propSet

def createProp(propSet,key):
        print 'Creating property, key='+key+' : value='+val
        AdminConfig.create('J2EEResourceProperty', propSet, [['name', key], ['type', 'java.lang.String'], ['value', val], ['required', 'false']])
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Setup
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

repName = sys.argv[0]
key = sys.argv[1]
val = sys.argv[2]
cellId = AdminConfig.getid('/Cell:/')
rep=""
ree=""

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Main program
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
existingRep=repExists(repName)
if existingRep:
        print repName+' exists'
        print 'Setting rep to '+str(existingRep)
        rep=existingRep
else:
        rep=createRep(repName)

existingRee=reeExists(key)

if existingRee:
        print 'salsa/'+key+' exists'
        print 'Setting ree to '+str(existingRee)
        ree=existingRee
else:
        ree=createJndiRef(rep,key)

propSet=createPropSet(ree,key)
createProp(propSet,key)
AdminConfig.save()



Avoid getting tied in knots with nested jython lists

I usually get tied in knots trying to use nested lists when creating / modifying config with wsadmin.       

Consider this example:
AdminConfig.create( 'J2EEResourceProperty', propSet, 
    '[[name "key"] 
     [type "java.lang.String"] 
     [description "My property"] 
     [value "Hello"] 
     [required "false"]]' )
       
When you add some passed in params to the mix it gets messy:
AdminConfig.create( 'J2EEResourceProperty', propSet, 
    '[[name " ’ + keyParam + ’ "] 
     [type "java.lang.String"] 
     [description "My property"] 
     [value " ’ + valueParam + ’ "] 
     [required "false"]]' )

The above looks fiddly to me, much better to use the following approach:
AdminConfig.create( 'J2EEResourceProperty', propSet, 
    [['name', keyParam], 
    ['type', 'java.lang.String'], 
    ['description', 'My property'], 
    ['value', valueParam], 
    ['required', 'false']] )

Monday, 9 June 2014

AdminTask help using wildcards

Quite handy ... in this example I'm searching for AdminTask commands that contain the string SDK

wsadmin> print AdminTask.help('-commands', '*SDK*')

Friday, 16 May 2014

wsadmin script to gather Dynacache stats


# dynaCacheMon.py
# Author: Bob Clarke
# Date: 05/01/2015
#

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Set up
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
import time
count = 0
month = time.ctime().split()[1]
day = time.ctime().split()[2]
year = time.ctime().split()[4]
timeStamp = time.ctime().split()[3]
logFile='/tmp/dynaCacheMon_'+timeStamp+'_'+month+'_'+day+'_'+year+'.log'
file = open(logFile,'a')

if(len(sys.argv) == 2):
        maxLoops = float(sys.argv[0])
        waitTime = float(sys.argv[1])
else:
        # Default values
        maxLoops = 3
        waitTime = 10

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Main program
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
print '\nRunning '+str(maxLoops)+' loops with '+str(waitTime)+' seconds delay. Logging results to '+logFile

while (count < maxLoops):
        print "Loop number "+str(count)
        mBeans = AdminControl.queryNames('type=DynaCache,*')
        for mBean in mBeans.splitlines():
                process = mBean.split(',')[1]
                jvm = AdminControl.queryNames('type=JVM,'+process+',*')
                freeHeap = AdminControl.invoke(jvm, 'getFreeMemory')
                maxHeap = AdminControl.invoke(jvm, 'getMaxMemory')
                file.write('------------------- JVM Details --------------------\n')
                file.write('Loop: '+str(count)+'\n')
                file.write('Time: '+str(time.ctime())+'\n')
                file.write('JVM: '+process+'\n')
                file.write('Max heap: '+maxHeap+'\n')
                file.write('Free heap: '+freeHeap+'\n')
                file.write('---------- Cache instances for this JVM ------------\n')

                for cacheInstance in AdminControl.invoke(mBean, 'getCacheInstanceNames').splitlines():
                        #stats = AdminControl.invoke(mBean, 'getCacheStatistics', cacheInstance+' [MemoryCacheSizeInMB  MemoryCacheEntries]')
                        stats = AdminControl.invoke(mBean, 'getAllCacheStatistics', cacheInstance)
                        file.write('### Instance Name: '+cacheInstance+' ###\n')
                        file.write(stats+',\n\n')
        file.flush()
        count = count+1
        sleep(waitTime)
                                             

Wednesday, 16 April 2014

AdminControl invoke with multiple arguments


Basic syntax:
AdminControl.invoke( <MBean string>, '<method>', '<arg1>  <arg2>' )

So it seems that AdminControl.invoke needs the third argument to be a string (I've often seen the error message "Third argument cannot be coerced into a string")

Here's an example of running getCacheStatistics on a DynaCache mbean:
AdminControl.invoke(
    myBean, 
    'getCacheStatistics',
    '/services/cache/appdata CacheHits'
)

The third argument in the command above is providing the cache instance name (/services/cache/appdata) followed by a space and then the name of the metric we're after (CacheHits)

In the case of <DynaCache MBean>.getCacheStatistics you can provide multiple metrics to retrieve by providing an array as follows:
AdminControl.invoke(
    myBean,
    'getCacheStatistics',
    '/services/cache/appdata [CacheHits DiskCacheSizeInMB]'
)

Taken from the following article...

Thursday, 14 November 2013

A quick guide to using the WebSphere app server AdminControl object

When I need to monitor some realtime stats on WAS using wsadmin, this is the process I go through....

  • Fire up a wsadmin command line, you'll now be at the wsadmin> prompt
  • Grab an array full of the particular objects you want to monitor. In this example I need to get stats from ThreadPools, so I run   tps = AdminControl.queryNames('type=ThreadPool,*').splitlines()
  • tps is now a PyList containing a shed load of ThreadPool objects
  • So let's pull a random one out for investigation by running  tp = tps[1]
  • if you type tp the object will be printed to the screen.. it'll look something like this ...
'WebSphere:name=BPESchedulerWorkManager.Alarm Pool,process=PSUAT003.AppTarget_2.plbpmu07psuat003node001.0,platform=dynamicproxy,node=plbpmu07psuat003node001,version=7.0.0.25,type=ThreadPool,mbeanIdentifier=BPESchedulerWorkManager.Alarm Pool,cell=psuat003cell001,spec=1.0'

  • Let's see what type of attributes this type of object has by running print Help.attributes(tp). This gives the following output...
Attribute                       Type                            Access
name                            java.lang.String                RO
maximumSize                     int                             RW
minimumSize                     int                             RW
inactivityTimeout               long                            RW
growable                        boolean                         RW
stats                           javax.management.j2ee.statistics.Stats  RO

  • Let's also see what type of operations we can invoke on this type of object has by running print Help.operations(tp). This gives the following output...
java.lang.String getName()
int getMaximumPoolSize()
void setMaximumPoolSize(int)
int getMinimumPoolSize()
void setMinimumPoolSize(int)
long getKeepAliveTime()
void setKeepAliveTime(long)
boolean isGrowAsNeeded()
void setGrowAsNeeded(boolean)
javax.management.j2ee.statistics.Stats getStats()

  • Seems to me that the stats attribute might be interesting... we can take a look with print AdminControl.getAttribute(tp, 'stats')
  • This will return a horibly formatted PyString simiolar to the one below. Put this through a splash of regex to pull out the stats you need and you're done.

'\n
Stats 
name=BPESchedulerWorkManager.Alarm Pool, type=threadPoolModule\n
{
\n
name=ActiveCount, 
ID=3, 
description=The number of concurrently active threads.,
unit=N/A, 
type=BoundedRangeStatistic,
lowWaterMark=0,
highWaterMark=1, 
current=0, 
integral=10121.0, 
lowerBound=0, 
upperBound=0
\n\n
name=PoolSize, 
ID=4, 
description=The average number of threads in a pool., 
unit=N/A, 
type=BoundedRangeStatistic, 
lowWaterMark=1, 
highWaterMark=10, 
current=1, 
integral=0.0, 
lowerBound=10, 
upperBound=10\n
}'

Friday, 4 October 2013

wsadmin - passing arguments when usng execfile()

I understand the correct way to execute a script with arguments from within wsadmin is to use the subprocess as follows

wsadmin>import subprocess
wsadmin>subprocess.call([sys.executable, 'abc.py', 'argument1', 'argument2'])

However, I can't seem to successfully import the subprocess module

This being the case I'm using the following approach...

wsadmin>import sys
wsadmin>sys.argv = ['argument1', 'argument2']
wsadmin>execfile('abc.py')

Monday, 30 September 2013

wsadmin automatic arrays

Probably obvious and common in many languages but I hadn't realised how helpful jython was in this area.  If you run a command that returns an array, and assign whats returned to a variable, that variable will automatically be an array as is demonstrated below:

wsadmin>perfList = AdminControl.queryNames('type=Perf,*').split(lineSeparator)

Now perfList can be accessed as an array, for example

wsadmin>print perfList[3]

or

wsadmin>for p in perfList:
wsadmin>        print p



Thursday, 19 September 2013

A very quick way to get wsadmin to reference a different SSL truststore


There may be occasion when you want to run wsadmin from a single host and connect to multiple remote Cells to gather stats or run-time data. If you do this you'll need to trust the SSL certificates of these other Cells.

All pretty straight forward but if you're OCD (like me) you won't want to add all of those signer certificates to the CellDefaultTrustStore of the environment where you're running wsadmin..... it's far too untidy.  Much better to have a custom truststore that you create yourself and add the signers to that.. nice and tidy :)

Of course you'll need to point wsadmin at this new SSL truststore and here's how to do it

  • Make a copy of wsadmin.sh - ( I just copied it to my scripts directory /opt/bpm/scripts/inventory)
  • As above for setupCmdLine.sh
  • Edit the copy of wsadmin.sh to overide the CLIENTSSL var. I advise you insert this just above the line where java get's invoked as follows ...

CLIENTSSL=-Dcom.ibm.SSL.ConfigURL=file:/opt/bpm/scripts/inventory2/props/ssl.client.props

"$JAVA_EXE" \
-Xbootclasspath/p:"$WAS_BOOTCLASSPATH" \
$EXTRA_X_ARGS \
$CONSOLE_ENCODING \
$javaOption \
$WAS_DEBUG \
"$OSGI_INSTALL" "$OSGI_CFG" \
"$CLIENTSAS" \
"$CLIENTSSL" \


The new line is the CLIENTSSL one. This points to your custom ssl.client.props file (you need to create this) which in turn points to your custom SSL truststore

Here's my ssl.client.props file

com.ibm.ssl.performURLHostNameVerification=false
com.ibm.ssl.validationEnabled=false
com.ibm.security.useFIPS=false
com.ibm.ssl.defaultCertReqAlias=default
com.ibm.ssl.defaultCertReqSubjectDN=cn=${hostname},o=IBM,c=US
com.ibm.ssl.defaultCertReqDays=365
com.ibm.ssl.defaultCertReqKeySize=1024
com.ibm.jsse2.checkRevocation=false
com.ibm.security.enableCRLDP=false
com.ibm.ssl.alias=DefaultSSLSettings
com.ibm.ssl.protocol=SSL_TLS
com.ibm.ssl.securityLevel=HIGH
com.ibm.ssl.trustManager=IbmPKIX
com.ibm.ssl.keyManager=IbmX509
com.ibm.ssl.contextProvider=IBMJSSE2
com.ibm.ssl.enableSignerExchangePrompt=gui
com.ibm.ssl.keyStoreProvider=IBMJCE
com.ibm.ssl.keyStoreFileBased=true
com.ibm.ssl.trustStore=/opt/bpm/scripts/inventory2/certs/myTrust.p12
com.ibm.ssl.trustStorePassword={xor}Not included for security reasons
com.ibm.ssl.trustStoreType=PKCS12
com.ibm.ssl.trustStoreProvider=IBMJCE
com.ibm.ssl.trustStoreFileBased=true
com.ibm.ssl.trustStoreReadOnly=false
#-------------------------------------------------------------------------
# Additional stuff for getting thin client to work
#-------------------------------------------------------------------------
ssl.SocketFactory.provider=com.ibm.websphere.ssl.protocol.SSLSocketFactory
ssl.ServerSocketFactory.provider=com.ibm.websphere.ssl.protocol.SSLServerSocketFactory



The important line is com.ibm.ssl.trustStore which points at my SSL truststore which contains signers for all of the environments I need to connect to (I imported these manually using ikeycmd)

Lastly, in setupCmdLine.sh you need to force $WAS_HOME to point at your WAS install dir (it tries to work it out intelligently based on where you're running it from but becasue you've made a copy you need to overide this) .. and you're done


Wednesday, 18 September 2013

Obtaining detailed WebSphere version information from wsadmin


If you need to get full patch level details of the WAS installs but need this via wsadmin (i.e because you have an inventory system based on wsadmin and you wan't to keep it standard)

Very simple this one, although typically the information available from official sources is not great

Your jython should look as follows...

wsadmin> import com.ibm.websphere.product.VersionInfo as vInfo
wsadmin> vInfo.main(['-maintenancePackages'],0) 


The second argument is important (i.e the zero) as it'll prevent your wsadmin shell from exiting when vInfo.main completes

Wednesday, 4 September 2013

wsadmin discovery that will save me hours - maybe it was just me!


For years if I did something like...

for server in AdminConfig.list('Server').splitlines(): 
    print AdminConfig.showAttribute(server, "services") 
    print

.. which would return result like this ...  

[services [(cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#PMIService_1) (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#AdminService_1) (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#TraceService_1) (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#DiagnosticProviderService_1) (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#RASLoggingService_1) (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#CoreGroupBridgeService_1) (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#ObjectRequestBroker_1) (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#TransportChannelService_1) (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#ThreadPoolManager_1) (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#HTTPAccessLoggingService_1)]] [stateManagement (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#StateManageable_1)] [statisticsProvider (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#StatisticsProvider_1)] ..

I would have had to do some horrible parsing to split out all the services, maybe something like this ...     
    expString = property.split()[5].split('.]')[0] 

  .. and as I was coding this I would be cursing IBM for such a crap implementation of python etc etc ...

BUT THEN I REALISED IT WAS ME WHO WAS AT FAULT.. there was a much better way to get this information.

Looking at the list of services above, you'll see there are things like PMIService and AdminService and TransportChannelService. (highlighted in blue above)

Well, these can be used as follows 

AdminConfig.list('PMIService', server) 
 
Which gives you something like this
(cells/gcbpmu03cell001/nodes/gcbpmu01psadv001node001/servers/PSSIT001.AppTarget.gcbpmu01psadv001node001.0|server.xml#PMIService_1332968737720) (cells/gcbpmu03cell001/nodes/gcbpmu03psadv001node001/servers/PSSIT001.AppTarget.gcbpmu03psadv001node001.0|server.xml#PMIService_1332968730407) (cells/gcbpmu03cell001/nodes/gcbpmu01psadv001node001/servers/PSSIT001.Messaging.gcbpmu01psadv001node001.0|server.xml#PMIService_1332968750266) (cells/gcbpmu03cell001/nodes/gcbpmu03psadv001node001/servers/PSSIT001.Messaging.gcbpmu03psadv001node001.0|server.xml#PMIService_1332968746809) (cells/gcbpmu03cell001/nodes/gcbpmu01psadv001node001/servers/PSSIT001.Support.gcbpmu01psadv001node001.0|server.xml#PMIService_1332968744147) (cells/gcbpmu03cell001/nodes/gcbpmu03psadv001node001/servers/PSSIT001.Support.gcbpmu03psadv001node001.0|server.xml#PMIService_1332968740583) 
 
.. i.e. a nice pre-parsed entry for each server

From here you can continue onwards with a feeling that you're using a proper user friendly language :)  

I had to celebrate with a cup of tea when I discovered this .. save me hours !

wsadmin discovery that will save me hours - maybe it was just me!


For years if I did something like...

for server in AdminConfig.list('Server').splitlines(): 
    print AdminConfig.showAttribute(server, "services") 
    print

.. which would return result like this ...  

[services [(cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#PMIService_1) (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#AdminService_1) (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#TraceService_1) (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#DiagnosticProviderService_1) (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#RASLoggingService_1) (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#CoreGroupBridgeService_1) (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#ObjectRequestBroker_1) (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#TransportChannelService_1) (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#ThreadPoolManager_1) (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#HTTPAccessLoggingService_1)]] [stateManagement (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#StateManageable_1)] [statisticsProvider (cells/gcbpmu03cell001/nodes/gcbpmu03cellmgr001/servers/dmgr|server.xml#StatisticsProvider_1)] ..

I would have had to do some horrible parsing to split out all the services, maybe something like this ...     
    expString = property.split()[5].split('.]')[0] 

  .. and as I was coding this I would be cursing IBM for such a crap implementation of python etc etc ...

BUT THEN I REALISED IT WAS ME WHO WAS AT FAULT.. there was a much better way to get this information.

Looking at the list of services above, you'll see there are things like PMIService and AdminService and TransportChannelService. (highlighted in blue above)

Well, these can be used as follows 

AdminConfig.list('PMIService', server) 
 
Which gives you something like this
(cells/gcbpmu03cell001/nodes/gcbpmu01psadv001node001/servers/PSSIT001.AppTarget.gcbpmu01psadv001node001.0|server.xml#PMIService_1332968737720) (cells/gcbpmu03cell001/nodes/gcbpmu03psadv001node001/servers/PSSIT001.AppTarget.gcbpmu03psadv001node001.0|server.xml#PMIService_1332968730407) (cells/gcbpmu03cell001/nodes/gcbpmu01psadv001node001/servers/PSSIT001.Messaging.gcbpmu01psadv001node001.0|server.xml#PMIService_1332968750266) (cells/gcbpmu03cell001/nodes/gcbpmu03psadv001node001/servers/PSSIT001.Messaging.gcbpmu03psadv001node001.0|server.xml#PMIService_1332968746809) (cells/gcbpmu03cell001/nodes/gcbpmu01psadv001node001/servers/PSSIT001.Support.gcbpmu01psadv001node001.0|server.xml#PMIService_1332968744147) (cells/gcbpmu03cell001/nodes/gcbpmu03psadv001node001/servers/PSSIT001.Support.gcbpmu03psadv001node001.0|server.xml#PMIService_1332968740583)
.. i.e. a nice pre-parsed entry for each server

From here you can continue onwards with a feeling that you're using a proper user friendly language :)  

I had to celebrate with a cup of tea when I discovered this .. save me hours !

Tuesday, 20 August 2013

Configure mutual auth (2-way SSL) on specific WebSphere transports



In this example I've set up 2 way SSL for WC_default_secure inbound on the AppTarget and WebApp cluster members

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
# Add MutualAuthSSLSettings at Cell level and client auth to True 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
cell = AdminConfig.list('Cell') 
cellName = AdminConfig.showAttribute(cell, 'name') 
print "Creating new SSLConfiguration  at Cell scope with name of MutualAuthSSLSettings" 
AdminTask.createSSLConfig('[-alias MutualAuthSSLSettings -type JSSE -scopeName (cell):'+cellName+' -keyStoreName CellDefaultKeyStore -keyStoreScopeName (cell):'+cellName+' -trustStoreName CellDefaultTrustStore -trustStoreScopeName (cell):'+cellName+' -serverKeyAlias default -clientKeyAlias default ]') 

print "Setting MutualAuthSSLSettings for client auth = 'required'" 
AdminTask.modifySSLConfig('[-alias MutualAuthSSLSettings -scopeName (cell):'+cellName+' -keyStoreName CellDefaultKeyStore -keyStoreScopeName (cell):'+cellName+' -trustStoreName CellDefaultKeyStore -trustStoreScopeName (cell):'+cellName+' -jsseProvider IBMJSSE2 -sslProtocol SSL_TLS -clientAuthentication true -securityLevel HIGH -enabledCiphers ]') 

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
# Now iterate around each server and set WC_default_secure 
# inbound to use the new MutualAuthSSLSettings 
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 
nodes = AdminConfig.list('Node') 
for node in nodes.splitlines(): 
        nodeName =  AdminConfig.showAttribute(node, 'name') 

        servers = AdminConfig.list('Server', node) 
        for server in servers.splitlines(): 
                serverName =  AdminConfig.showAttribute(server, 'name') 
                if(serverName.find('AppTarget') != -1): 
                        print "Setting "+serverName+" WC_default_secure_inbound to use MutualAuthSSLSettings" 
                        AdminTask.createSSLConfigGroup('[-name WC_defaulthost_secure -scopeName (cell):'+cellName+':(node):'+nodeName+':(server):'+serverName+':(endpoint):WC_defaulthost_secure -direction inbound -certificateAlias default -sslConfigAliasName MutualAuthSSLSettings -sslConfigScopeName (cell):'+cellName+' ]') 
                elif(serverName.find('WebApp') != -1): 
                        print "Setting "+serverName+" WC_default_secure_inbound to use MutualAuthSSLSettings" 
                        AdminTask.createSSLConfigGroup('[-name WC_defaulthost_secure -scopeName (cell):'+cellName+':(node):'+nodeName+':(server):'+serverName+':(endpoint):WC_defaulthost_secure -direction inbound -certificateAlias default -sslConfigAliasName MutualAuthSSLSettings -sslConfigScopeName (cell):'+cellName+' ]') 
        print 

Thursday, 4 July 2013

Wsadmin thin client

Here's how to write a cut down wsadmin.sh 

Thanks to the author of the Clever Monkey blog (http://ksoni-java.blogspot.co.uk/2010/03/wsadmin-thin-client.html) for this one.

The key advantage of this is that you can run it anywhere so long as you have Java installed ... i.e. you don't need WebSphere, instead you need just two jars

  • com.ibm.ws.admin.client_7.0.0.jar (you can find this under $WAS_HOME/runtimes)
  • com.ibm.ws.security.crypto.jar (you can find this under deploytool/itp/plugins/com.ibm.websphere.v7*/plugins)


 You might wonder why you need to set $WAS_HOME.... I don't know the answer but I do know that $WAS_HOME only needs to point to the directory that contains your wsadmin.sh script, I guess it's just a hard coded throwback.

NOTE: I did have one problem whereby I was unable to import the regular expression package (import re). I thought I'd be able to find a jar with everything I needed but in the end I just copied the following py files from an existing WAS install  ($WAS_HOME/optionalLibraries/jython/Lib) to the same dir as my wsadmin.sh script (couldn't work out how to use them if they were placed in a different directory)

  • copy_reg.py  
  • javaos.py  
  • javapath.py  
  • re.py  
  • sre_compile.py  
  • sre_constants.py 
  • sre_parse.py  
  • sre.py  
  • string.py  
  • UserDict.py


Here's my wsadmin.sh



#!/bin/sh

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Set paths
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
WAS_HOME=/opt/bpm/scripts/certCheck
USER_INSTALL_ROOT=${WAS_HOME}
JAVA_HOME=/opt/bpm/bpm751/java
JAVA_EXE=${JAVA_HOME}/bin/java
CLASSPATH=${WAS_HOME}/lib/com.ibm.ws.admin.client_7.0.0.jar:${WAS_HOME}/lib/com.ibm.ws.security.crypto.jar

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Set location of properties files
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
SOAPURL=-Dcom.ibm.SOAP.ConfigURL=file:${WAS_HOME}/props/soap.client.props
CLIENTSSL=-Dcom.ibm.SSL.ConfigURL=file:${WAS_HOME}/props/ssl.client.props

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Trace settings
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
wsadminTraceString=-Dcom.ibm.ws.scripting.traceString=*=off
wsadminTraceFile=-Dcom.ibm.ws.scripting.traceFile=wsadmin.traceout
wsadminValOut=-Dcom.ibm.ws.scripting.validationOutput=wsadmin.valout

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Process command line arguments
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
isJavaOption=false
nonJavaOptionCount=1
for option in "$@" ; do
        if [ "$option" = "-javaoption" ] ; then
                isJavaOption=true
        else
                if [ "$isJavaOption" = "true" ] ; then
                        javaOption="$javaOption $option"
                        isJavaOption=false
                else
                        nonJavaOption[$nonJavaOptionCount]="$option"
                        nonJavaOptionCount=$((nonJavaOptionCount+1))
                fi
        fi
done

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Run the command
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
${JAVA_EXE} \
-classpath "$CLASSPATH" \
-Duser.install.root=$USER_INSTALL_ROOT \
-Dwas.install.root=$USER_INSTALL_ROOT \
$CLIENTSSL \
$SOAPURL \
$wsadminValOut \
$wsadminTraceString \
-Dcom.ibm.websphere.thinclient=true \
com.ibm.ws.scripting.WasxShell ${nonJavaOption[@]}

Use wsadmin to monitoring WebSphere App Server SSL certificate expiry

A Jython script to check all certificates that are stored in keystores under Cell management. At my client's site I added IHS, Plugin and CACerts keystores to the Cell so that they too can be checked.
If you have access to an SMTP service this script will send an email when a cert is due to expire in less than X days. I run this from a bourne wrapper (I'll place the code for this at the end of this post) which also sends an email if it can't run the AdminTask methods it needs to for any reason.

Here's the Jython code

# --------------------------------------------------------------------------------
# checkCertificates.py
# Author: Bob Clarke (IBM)
# Date: 19/06/2013
# --------------------------------------------------------------------------------

# --------------------------------------------------------------------------------
# Setup
# --------------------------------------------------------------------------------
import re
import sys
import time
import os
import javaos
from java.text import SimpleDateFormat ;
dateFormat = SimpleDateFormat("dd-MMM-yyyy");
emailRecipients = "bob.clarke@stack1.com"
emailContent = "props/email.content"
smtpUrl = "smtp=smtp://smtphub.stack1.com"

# --------------------------------------------------------------------------------
# Define Subroutines 
# --------------------------------------------------------------------------------
def dateDiff(keystoreName, issuedTo, expString, scopeName):
        todayString =  time.strftime("%d-%b-%Y", time.gmtime())
        todayDate = dateFormat.parse(todayString)
        expiryDate = dateFormat.parse(expString)
        e = expiryDate.getTime()
        t = todayDate.getTime()
        d = e - t
        days = d / (1000 * 60 * 60 * 24)
        print "\tExpires "+expString
        if(days < 31):
                if(re.search("blueworks",  issuedTo)):
                        print "\tIgnoring BlueworksLive cert"
                else:
                        print "\tALERT - this certificate will expire in "+str(days)+" days"
                        file = open('props/email.content','w')
                        file.write('ACTION REQUIRED : The following certificate will expire in '+str(days)+' days\n\n')
                        file.write('- Environment '+env+'\n\n')
                        file.write('- Expiry Date '+expString+'\n\n')
                        file.write('- '+str(issuedTo)+'\n\n')
                        file.write('- Keystore name '+str(keystoreName)+'\n\n')
                        file.write('- Keystore scope '+str(scopeName)+'\n')
                        file.close()
                        sendEmail()

def sendEmail():
        os.system('cat '+emailContent+' | mailx -v -s "Certificate expiry notice for '+env+'" -S '+smtpUrl+' -S from="smtp@stack1.com" '+emailRecipients+' >> logs/smtp.log 2>&1')

# ---------------------------------------------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------------------------------------------

env = sys.argv[0]
print
print 'Obtaining keystore information for '+env

# Iterate through all keystores, print each cert with expiry dates and ask user if they want to replace
for ks in AdminTask.listKeyStores('[-all true -keyStoreUsage SSLKeys ]').splitlines():
        keystoreName =  AdminConfig.showAttribute(ks, 'name')
        ms = AdminConfig.showAttribute(ks, 'managementScope')
        scopeName = AdminConfig.showAttribute(ms, 'scopeName')

        print '\n## START '+keystoreName +' in scope '+scopeName+'##'

        print '\n\t## START personal certificates ##'
        personalCertsFound=0
        for cert in AdminTask.listPersonalCertificates('[-keyStoreName '+keystoreName+' -keyStoreScope '+scopeName+']').splitlines():
                personalCertsFound=1
                issuedTo=""
                for property in re.split("\] \[", cert):
                        if(re.search("\[\[",  property)):
                                tmp = property
                                property = re.split("\[\[",tmp)[1]
                        if(re.search("] ]",  property)):
                                tmp = property
                                property = re.split("] ]",tmp)[0]
                        if(re.search("alias", property)):
                                alias = re.split("\s+", property)[1]
                                print "\n\t"+property
                        if(re.search("issuedTo", property)):
                                issuedTo=property
                                print "\t"+property
                        if(re.search("issuedBy", property)):
                                print "\t"+property
                        if(re.search("validity", property)):
                                expString = property.split()[5].split('.]')[0]
                                #dateDiff(expString)
                                dateDiff(keystoreName, issuedTo, expString, scopeName)


        if(personalCertsFound==0):
                print '\tNo personal certificates found in '+keystoreName+' in scope '+scopeName
        print '\n\t## END personal certificates ##'

        print '\n\t## START signer certificates ##'
        signerCertsFound=0
        for cert in AdminTask.listSignerCertificates('[-keyStoreName '+keystoreName+' -keyStoreScope '+scopeName+']').splitlines():
                signerCertsFound=1
                issuedTo=""
                for property in re.split("\] \[", cert):
                        if(re.search("\[\[",  property)):
                                tmp = property
                                property = re.split("\[\[",tmp)[1]
                        if(re.search("] ]",  property)):
                                tmp = property
                                property = re.split("] ]",tmp)[0]
                        if(re.search("alias", property)):
                                alias = re.split("\s+", property)[1]
                                print "\n\t"+property
                        if(re.search("issuedTo", property)):
                                issuedTo=property
                                print "\t"+property
                        if(re.search("issuedBy", property)):
                                print "\t"+property
                        if(re.search("validity", property)):
                                expString = property.split()[5].split('.]')[0]
                                #dateDiff(expString)
                                dateDiff(keystoreName, issuedTo, expString, scopeName)

        if(signerCertsFound==0):
                print '\tNo signer certificates found in '+keystoreName+' in scope '+scopeName
        print '\n\t## END signer certificates ##'

        print '\n## END '+keystoreName +' in scope '+scopeName+'##'



And here's the wrapper script to run it. NOTE: This uses a cutdown version of wadmin.sh (which I've renamed to wsAdminLite.sh - see this post) which I will describe in an upcoming post. They key advantage of this for me is that I was able to point the wsadmin client at my own keystore in which I'd loaded the cell signers for each environment rather than loading all of these (untidily) into the Cell default trust store of another WAS environment.
You'll notice that this script writes a new soap.client.props for each environment, in this way you can XOR encode each password (better than plain text).


#!/bin/sh
# -----------------------------------------------------------------------------
# run.sh
# Author: Bob Clarke (IBM)
# Date: 01/07/2013
# -----------------------------------------------------------------------------
wsaCmd="./wsAdminLite.sh -lang jython"
envProps="props/env.props"
soapProps="props/soap.client.props"
run_log="logs/run.log"
emailRecipients="bob.clarke@stack1.com"
pwd=`pwd`
timestamp=`date "+%d/%m/%y %H:%M:%S"`
scripthost=`hostname`

cat $envProps | grep -v '^#' | while read line
do
        # Parse props
        env=`echo $line | awk -F: '{print $1}'`
        host=`echo $line | awk -F: '{print $2}'`
        port=`echo $line | awk -F: '{print $3}'`
        user=`echo $line | awk -F: '{print $4}'`
        pw=`echo $line | awk -F: '{print $5}'`

        # Write soap.client.props
        echo "com.ibm.SOAP.loginUserid=admin" > ${soapProps}
        echo "com.ibm.SOAP.loginPassword={xor}"${pw} >> ${soapProps}
        echo "com.ibm.ssl.alias=DefaultSSLSettings" >> ${soapProps}

        echo >> $run_log
        echo ENV is $env >> $run_log
        echo Timestamp is $timestamp >> $run_log
        echo "Running: $wsaCmd -host $host -port $port -f checkCertificates.py $env using $soapProps" >> $run_log
        out=`$wsaCmd -host $host -port $port -f checkCertificates.py $env`
        echo "Command output is: $out" >> $run_log

        # Check if we successfully connected to the deployment manager and obtained cert details
        echo $out | grep "END signer certificates" 2>&1 > /dev/null
        if [ $? -ne 0 ]; then
                echo
                echo "It seems the attempt to run checkCertificates.py on environment (${env}) has failed"
                echo "Invocation of checkCertificates.py on host (${scripthost}) to check certificates on environment (${env}) has failed, please check ${pwd}/${run_log}" | mailx -v -s "ACTION REQUIRED :Certificate check for $env has failed" -S smtp=smtp://smtphub.stack1.com -S from="smtp@stack1.com" $emailRecipients >> logs/smtp.log 2>&1
                echo
        fi
done


.... and here's an example env.props file


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# NOTE: The first column is a simple flag that is passed
# to wsadmin so that it can print out a meaningful
# string to describe the environment being checked
# It's up to the person who edits this file to ensure it's accurate
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
PNL_PERF002:jupiter.stack1.com:11005:admin:gfe8Shm1sPSjy
PNL_DEV001:pluto.stack1.com:8887:admin:HQ8SbhdsS8y
PNL_PROC_CENTRE:saturn.stack1.com::12005:admin:Lhjhju98zxubW==
PNL_SIT001:mars.stack1.com::8879:admin:HQ8Sjkj654kjk==
PNL_PERF001:venus.stack1.com::11005:admin:t65hhjtPS8y=