Thursday, February 26, 2009

Do Not Step On Other's Feet [WLST scripting Best Practices (Part-2)]

This post is a continuation of my previous post - in a series of posts about WLST scripting best practices. When using WLST script for performing configuration changes always check whether someone else is making changes. WebLogic support configuration changes using many methods but not limited to:
  • Administration Console
  • Interactive WLST
  • WLST SCripts
  • JMX
  • Ant Scripts
  • 3rd Party Tools
So it is always better to check whether someone else is making changes while you are ready to start a change session. WebLogic Server will allow only one change session at a time no matter which one of the above methods you use for configuration management. Especially environments with multiple administrators the best practice is to have individual logins for each administrator so that you can have more controlled environment. If you are interested in configuration auditing to find out who is responsible for what, see this post.

Use the Configuration Manager to find out information about existing change sessions. You can find out whether someone else had already started a change session, if so who is making changes, are there any unactivated changed, if so what changes are unactivated etc. from the configuration manager. The following example illustrates a code snippet which checks for existing sessions using configuration manager:


...
### Get the Configuration Manager and check for existing session
cfgManager = getConfigManager()
try:
cfgManager.getChanges()
print '===> Someone else is making changes'
except:
print '===> No one else is making changes'
...


The following example illustrates a code snippet which checks for the number of unactivated changes using configuration manager:


...
### Get the Configuration Manager and check for existing session
cfgManager = getConfigManager()
try:
cfgManager.getChanges()
print '===> Someone else is making changes'
noOfChanges = cfgManager.getUnactivatedChanges().__len__()
print 'There are ' + noOfChanges + ' unactivated pending changes in the current edit session'
except:
print '===> No one else is making changes'
...

The above code snippet may work only if you are the user who is making the changes. The following example illustrates a code snippet which checks and prints the user who is currently making changes using configuration manager:


...
### Get the Configuration Manager and check for existing session
cfgManager = getConfigManager()
try:
cfgManager.getChanges()
print '===> User ' + configmanager.getCurrentEditor() + ' is making changes'
except:
print '===> No one else is making changes'
...


The following example is a complete script which checks for an existing session and if one doesn't exists then it will create a new managed server by starting a new session. If a session already exists then it will simply display that information and will exit.



from weblogic.management.mbeanservers.edit import NotEditorException

### CreateMgdServer.py
### Define all the requried variable
username = 'braman'
password = 'weblogic'
url = 't3://localhost:7001'
mgdServerName = 'mgdserver1'
resourceType = 'Server'
listenAddress = 'egmgd1'
listenPort = 2001

### Connect to the Administration Server
connect(username, password, url)

### Get the Configuration Manager
cfgManager = getConfigManager()
try:
cfgManager.getChanges()
print '===> Currently there is a Session'
if cfgManager.isEditor() == true:
### You are making changes!!!
print '===> Looks like you started that session'
print '===> You can check the console for any pending changes'
print '===> Try rerunning this script after you release or commit the pending changes'
exit()

except NotEditorException, e:
if cfgManager.getCurrentEditor() is None:
### No session
pass
else:
### Someone else is making changes
userWithSession = cfgManager.getCurrentEditor().replace(' ', '')
print '===> Currently there is a Session'
print '===> User \"' +userWithSession+'\" is making the changes'
print '===> Wait until \"' +userWithSession+'\" complete the current session'
exit()
pass
except Exception:
### Other Errors
print '===> Error, see log for more info'
exit()


### Start a change session
edit()
startEdit()

### Create the Managed Server
create(mgdServerName, resourceType)
cd('/Servers/' + mgdServerName)
cmo.setListenPort(listenPort)
cmo.setListenAddress(listenAddress)
print '===> Created Managed Server - ' + mgdServerName

### Activate the changes
save()
activate()

### Disconnect from the Administration Server
disconnect()
exit()

To explain some tricky parts of the above script:

This is line of code is used to import the exception class
from weblogic.management.mbeanservers.edit import NotEditorException

To check whether you are holding on to a session currently you can use the following method on the configuration manager
cfgManager.isEditor()

To get the user who is currently making changes you use the getCurrentEditor method on the configuration manager
cfgManager.getCurrentEditor()

To get rid of all the white spaces you can use a replace method from the string class (this is Jython)
userWithSession = cfgManager.getCurrentEditor().replace(' ', '')


The above example works if you don't have a managed server named egmdg1. But if you already have a managed server in your domain with the same name then the script will fail with the following error:

weblogic.descriptor.BeanAlreadyExistsException: Bean already exists

You can handle that situation in couple of different ways. I shall continue on how to tackle that in my next post.

WLST-BP-2 Check for existing session before you start one

Wednesday, February 25, 2009

Variable Definitions In The Preamble [WLST scripting Best Practices (Part-1)]

With WLST becoming popular among WebLogic Administrator, there is an unsaid need to discuss the best practices with respect to WLST scripting. I am being asked to share information about WLST like an introductory/101 post. But I decided to start a series of post which might help WebLogic Administrators with some of the must follow best practices rather than writing some introductory post which might duplicate the documentation. For WLST documentation see here.

The common steps involved in a WLST script that is used to configure WebLogic Server are as follows:

1. Connect to server
2. Navigate to the respective location (MBean)
3. Modify the required properties
4. If more configuration needs to be modified continue Step-2
5. Else disconnect
6. Exit

The first of the series of best practices in authoring a WLST script is to define all the required variables at the beginning before connecting to the server. That way if any modifications must be done in the future it will be as easy as changing the variables defined at the beginning of the script. In the coming posts, I will talk about more of other best practices like writing a reusable WLST script, consuming information from the environment variables, exception handling, defensive scripting, avoiding to hard code critical information like username, password, url etc.

The usual variables are the username, password, url, resource names, attribute values etc. The following is an example of a script that defines all the required values as script variables which can avoid hardcoding and will also facilitate simple way to modify them in the future if required.


#CreateServer.py
#Define all the requried variable
username = 'system'
password = 'weblogic'
url = 't3://egAdm:7001'
serverName = 'mgdserver1'
listenAddress = 'egmgd1'
listenPort = '2001'

#Connect to the Administration Server
connect(username, password, url)

#Start a change session
edit()
startEdit()

#Create the Managed Server
create(serverName, 'Server')
cd('/Servers/' + serverName')
cmo.setListenPort(listenPort)
cmo.setListenAddress(listenAddress)

#Activate the changes
save()
activate()

#Disconnect from the Administration Server
disconnect()
exit()


The above script may not be authored using all the best practices now. But I will eventually build on the same example of creating a new Managed Server in my subsequent posts to address the other best practices as well. My next post will talk about how to check for existing change session before you start one with WLST.

WLST-BP-1 Define all the variables in the preamble

Wednesday, December 17, 2008

Easy Syntax with WLST

WLST is a powerful scripting solution for managing and administering WebLogic Server and resources deployed on them. WLST is built on the Java implementation of the scripting language Python called as Jython. All the commands in WLST are implemented as Jython functions and they require a set of parentheses for passing any arguments. Even any commands that do not require any arguments are supposed to be suffixed with parentheses. For example the command "ls" is used to list all the child MBeans and/or attributes of the current MBean you are at.

ls() - lists all the child MBeans and attributes
ls('a') - lists all the attribute names and values only
ls('c') - lists all the child MBeans only

So even if you want to invoke "ls" with no arugments you must use "ls()". This might not be an issue when you are building scripts that you might want to run many times. But while connected to a server and working with WLST in interactive mode, it might get a little frustated to type the parentheses everytime you want to run some simple commands with no arguments. To ease this pain there is a hidden option in WLST which can be used to ease the syntax for WLST commands - easeSyntax().



You can supply the "easeSyntax()" command to ease the syntax but this is not recommended for script mode and especially when using loop constructs. You can also use the regular Jython syntax with parentheses even after you enabled the easy syntax. To turn off the easy syntax mode simply issue the command again "easeSyntax".

Bye Bye parentheses!

Monday, October 20, 2008

How To Encrypt Clear Text Passwords With WebLogic Server

WebLogic Server encrypts all the plain text passwords stored in its domain configuration XML file(s). This is to prevent access to sensitive information. When passwords are entered using administration console or scripting tools, it will automatically get encrypted before they are stored in the configuration XML files(s).

Prior to WebLogic Server 9.0

If those passwords need to be reset either the configuration tools (Console or scripting tools) can be used which will automatically re-encrypt the passwords or by directly changing the configuration files using a text editor. When files are directly modified using a text editor the passwords will get encrypted during the subsequent restart.

Starting from WebLogic Server 9.0

Using clear text passwords in the configuration files are supported only for Development domain and it will not re-encrypt the passwords. If the domain is a Production domain then you cannot set the passwords in clear text. You have to either use a dedicated command-line utility or WLST to encrypt the clear text passwords. If the server encounters a clear text password when parsing the configuration file(s) while starting in Production Mode, then you will get an error similar to the following:

<Oct 20, 2008 9:05:35 PM EDT> <Critical> <WebLogicServer> <BEA-000362> <Server failed. Reason: [Management:141266]Parsing Failure in config.xml: java.lang.IllegalArgumentException: In production mode, it's not allowed to set a clear text value to the property: PasswordEncrypted of ServerStartMBean>


Depending on the configuration the MBean name value of the error message may change. In this case the ServerStartMBean has clear text value for a password property. Either the dedicated Java utility to encrypt clear text values can be used or WLST cant be used to re-encrypt. To run the encrypt utility follow the instructions below:

  1. Change directory to your domain's bin folder (For Eg. cd c:\bea\user_projects\domains\mydomain\bin)
  2. Execute the setDomainEnv script (For Eg. setDomainEnv.cmd)
  3. Execute java weblogic.security.Encrypt which will prompt for the password and will print the encrypted value in stdout.
The following are some sample output from running the utility

C:\bea\user_projects\domains\mydomain>java weblogic.security.Encrypt
Password:
{3DES}9HWsf87pJTw=

You should execute this utility from the domain folder as it requires the domain's password salt file (SerializedSystemIni.dat) for encrypting the clear text string. You can also pass the clear text string as an argument

C:\bea\user_projects\domains\mydomain>java weblogic.security.Encrypt testpwd
{3DES}9HWsf87pJTw=


You can also use WLST to encrypt clear text strings as below:

C:\bea\user_projects\domains\mydomain>java weblogic.WLST

Initializing WebLogic Scripting Tool (WLST) ...

Welcome to WebLogic Server Administration Scripting Shell

Type help() for help on available commands

wls:/offline> es = encrypt('testpwd')
wls:/offline> print es
{3DES}9HWsf87pJTw=
wls:/offline>

When running WLST from a location different than the domain folder you can pass in an argument to specify the domain directory. Once you have the encrypted value, the configuration files can be modified to include this encrypte value instead of clear text passwords. These features will make your domain to operate when resetting the encrypted passwords on a Production domain's configuration XML files. These methods not only can be used to encrypt configuration XML (config.xml) but also the JDBC or JMS descriptor XML files.

Wednesday, September 24, 2008

Encrypt the credentials when running WLST in interactive or script mode

One of the common request I hear from administrators is that they want to get away from providing user name and password in plain text when using WLST. WebLogic Server provides a way to encrypt the credentials for server start up. You can create a password file "boot.properties" (called as Boot Identity File) with plain text credentials in a folder named security under the server root directory. This file will be automatically detected during the server start up and the server will encrypt the information in this file for subsequent use. Until WebLogic Server 9.x this file should be placed under the DOMAIN folder. So servers sharing the same file system share the same boot identity file and cannot be configured to use different files.

This boot identity file can also be used by WLST only when started from the domain folder. This is mainly because the domain's password key (SerializedSystemIni.dat) is used to encrypt this file. If you are using WLST from a different location or from a remote machine to connect to the server or if you want to run WLST script you can use a different technique. You can use WLST to generate a User Configuration file which will have encrypted user name and password using storeUserConfig() command. A key file that will be used to encrypt the data will also get generated along with the user config file. The key file is important as it is required to decrypt the values back from the user config file. This is an online WLST command. So you should be connected to a running WebLogic Server or a Node Manager to issue this command.

When you use this command with no arguments the user configuration file for the current user will be generated within the current OS user's home folder.


wls:/testdomain/serverConfig>storeUserConfig()


You can also specify the location and name for the key file and the userconfig file if you want them to be created elsewhere.

wls:/testdomain/serverConfig>storeUserConfig('/usr/home/user1/configfile.secure', '/usr/home/user1/keyfile.secure')


If the files are stored with the default name (osusername-WebLogicConfig.properties & osusername-WebLogicKey.properties) you can simply connect without specifying the username and password in the connect() command.

wls:/offline> connect(url='t3://host:port')


If the files are stored in a different location or with a different name, then they can be passed as an argument to the connect() command.

wls:/offline> connect(userConfigFile='/usr/home/user1/configfile.secure', userKeyFile='/usr/home/user1/keyfile.secure', url='t3://host:port')


No more plain text user name and password in when using WLST. Have a safe and secure scripting!

Friday, September 5, 2008

New differences between development domain and production domain in 10gR3

During domain creation you can specify the start up mode for your domain either as development mode of production mode. Most of you who work with WebLogic Server for the past few releases should know that there are few differences between a development domain and production domain. (http://e-docs.bea.com/common/docs103/confgwiz/newdom.html#wp1097267)

Development Mode
The default JDK for development domain is Sun Hotspot
You can use the demo certificates for SSL
Auto deployment is enabled
Server instances rotate their log files on startup
Admin Server uses an automatically created boot.properties during startup
The default maximum capacity for JDBC Datasource is 15
The debugFlag which is used to start the WebLogic Workshop Debugger is enabled

Production Mode
The default JDK for production domain is JRockit
If you use the demo certificates for SSL a warning is displayed
Auto deployment is disabled
Server instances rotate their log files when it reaches 5MB
Admin Server prompts for username and password during startup
The default maximum capacity for JDBC Datasource is 25
The debugFlag which is used to start the WebLogic Workshop Debugger is disabled

In addition to the above WebLogic Server 10gR3 adds a few more default configurations depending on whether the domain is started in development or production mode.

Thursday, August 28, 2008

Add your own commands to WLST

Do you want to add your own commands to the already rich set of WLST commands?

You can do so by building your own *.py file and adding them to WL_HOME/common/wlst/lib folder. Any *.py file added to this folder will be automatically compiled and imported by WLST when started on that machine. So the custom commands built as definitions inside these modules can be used by calling them on the respective module names.

If you have a TestLib.py stored under WL_HOME/common/wlst/lib folder:

TestLib.py
----------
def testCmd():
print 'This is a test command'



And if there is a definition called testCmd() defined in it then you can call it as follows:

wls:/offline>TestLib.testCmd()

What you waiting for? Go and add you command to WLST now.