Wednesday, November 25, 2009

Understanding WLST built-in variables . . .[WLST scripting Best Practices (Part-5)]

This post is a continuation of my previous post - in a series of posts about WLST scripting best practices.

Managed Beans (MBeans) are used to represent all the configuration and runtime information about WebLogic Domain, Servers, the applications and services deployed on a WebLogic Server Domain. While you can get all the information from WebLogic MBeans, WLST simplifies the task of building scripts by providing some built-in variables. These WLST variables are initialized and/or modified when you change to online mode (connect to a server), start an edit session etc. to appropriate values.

One of the very useful WLST variable is cmo. cmo stands for current management object. When navigating in WLST you can use cmo to reference the current MBean (object) instance you are navigating into. The cmo value is changed when you navigate to different hierarchy of MBeans under different MBean trees in WebLogic (except jndi tree). The following illustrates the use of cmo.



...
connect(username, password, url)
edit()
startEdit()
cd('/Servers/server1')
s1=cmo
cd('/Servers/server2')
s2=cmo
print 'Listenport of server1 -> ' + s1.getListenPort()
print 'Listenport of server2 -> ' + s2.getListenPort()
...


Notice the use of cmo can for invoking operations on the respective MBean object. There are many such variables that will help you to write better and efficient WLST scripts. See here for the list of all the WLST variables.

If you know a variable name you can simply use it in you script. dumpVariables() command can be used to list all the variables and their values.


wls:/testdomain/serverConfig> dumpVariables()
adminHome weblogic.rmi.internal.BasicRemoteRef - hostID: '328889774891021637S:127.0.0.1:[7001,7001,-1,-1,-1,-1,-1]:testdomain:AdminServer',oid: '259', channel: 'null'
cmgr [MBeanServerInvocationHandler]com.bea:Name=ConfigurationManager,Type=weblogic.management.mbeanservers.edit.ConfigurationManagerMBean
cmo [MBeanServerInvocationHandler]com.bea:Name=testdomain,Type=Domain
connected true
domainName testdomain
...



In addition you should also be aware of these WLST variables in order to NOT use them to store your own information. If you do so then WLST will overwrite these variables during your interaction like connect, startEdit etc. So make sure you understand these WLST variables, use them in your scripts and do not use them to store your information.

Monday, November 23, 2009

Force confidentiality for Web Applications

Usually there are requirements for web based applications to use SSL when serving sensitive data between the client browser and WebLogic server. You can enable SSL port for WebLogic Server and disable the plain text port. This will force all the communication through the SSL port enabled on the target server. But if you have a mix of applications that require secured access and that doesn't then you can use the standard JEE web application descriptor to enable confidentiality. If you enable trasport guarantee configuration for the Web Applications, WebLogic Server will force the application or selective URL patternts to be accessed through the SSL port on WebLogic Server.

The following shows an example of transport guaranetee entry from web.xml:


...


CONFIDENTIAL



/*


...


Even if the client is accessing through plain text port, WLS container will automatically redirect the request to the SSL port if enabled or to any other Network Channel enabled with SSL. This will ensure that certain applications or requests to be always accessed through SSL. Setting the transport guarantee to be NONE will relax the requirements and will not force SSL for the applications. But if there are SSL enabled network channels or SSL port is enabled on the server then the application can still be accessed using SSL. If the value for transport guarantee is set to be INTEGRAL then the requirement is that the data sent between the client and server be sent in such a way that it can't be changed in transit.

Needless to say that this configuration can also be configured through deployment plans. If the application you are deploying on WebLogic Server is already packaged for deployment or third-party application then deployment plan will solve the purpose of overriding the application's configuration through external means. See here for more information on deployment plans with WebLogic Server.

Thursday, October 22, 2009

More ways to check the existense of a resource with WLST

In one of my previous post, I discussed a couple of ways with which you can find out whether a particular configuration already exists before you create them. The methods are not just limited to the one on that post. So now I am here to discuss couple more way to do the same check. But just for completeness I shall also include the methods I discussed in my previous post. I am taking a sample use case to check whether a particular WebLogic Server instance exists in the domain or not. But you can extrapolate these technique for any other resource like JDBC Data Source, JMS Server, JMS Queue etc.

Goal - Check whether a server with the name 'mymanagedserver' exists in the domain

Method-1 Using "cd"

A simple approach is to use the "cd" command to navigate into that configuration MBean. If the "cd" command throws an exception then you can safely assume that the resource/configuration doesn't exists and you can continue with your task.


...
mgdServerName = 'mymanagedserver'
### Checking for the server
try:
cd('/Servers/' + mgdServerName)
print '===> Server \"' +mgdServerName+'\" already exists'
print '===> No action was performed'
exit()
except:
pass
### Continue to create the server
...


Method-2 Catch "BeanAlreadyExistsException"

Another approach is to catch the "BeanAlreadyExistsException" when creating the resource and safely exiting the script.


...
mgdServerName = 'mymanagedserver'
### Create the Managed Server
edit()
startEdit()
try:
create(mgdServerName, resourceType)
print '===> Created Managed Server - ' + mgdServerName
pass
except BeanAlreadyExistsException:
print '===> Server \"' +mgdServerName+'\" already exists'
print '===> No action was performed'
cancelEdit('y')
exit()
...


But with this approach you are starting an edit session and creating the server to find out it's existence. So you have to cancel the edit session once you find out that the resource that you are creating already exists if not you might get a warning message similar to the following:

You have an edit session open and you will lose all outstanding changes and your edit session will be stopped if you exit. Are you sure you would like to exit? (y/n)

So canceling the edit session with a response 'y' will make WLST not to prompt for the user response.


Method-3
Using "getMBean"

There is a WLST command called getMBean which will return the MBean object when you specify the appropriate path. If the instance is not found then it will return None. But getMBean command does not throw an exception when an instance is not found. So you have explicitly check result of the getMBean.


...
mgdServerName = 'mymanagedserver'
ref = getMBean('/Servers/' + mgdServerName)
if(ref != None):
print 'Server ' + servername + 'already exists'
disconnect()
exit()
else:
pass
### Continue to create the server
...


Method-4 Using "ls"

You can simply navigate to the resource type and execute ls. This will return the list of all the instances as a string when you assign the output to a variable. Then you can use the find method on that string variable to check whether your server exists. The find method returns a "0" on success or "-1" on failure.


...
mgdServerName = 'mymanagedserver'
cd('/Servers')
servers = ls()
if (servers.find(servername) != -1):
print 'Server ' + servername + ' already exists'
disconnect()
exit()
else:
pass
### Continue to create the server
...

Wednesday, September 16, 2009

Don't want to get prompted for confirmation in WebLgic Console?

If you are using WebLogic Admin console frequently to configure resources or to manage the life cycle of the servers, you might have seen a confirmation prompt. This prompt will show not up when you are running the domain in development mode. When the domain is running in production mode they will ask confirmation for all the operations. There used to be no way to disable this confirmation page prior WebLogic Server 10.3. Now in WebLogic Server 10.3 and higher you can set a console user preference that can disable these confirmation pages.

Use the tool bar at the center (top) of the console to go to the "Preferences". Under the "User Preferences" tab you will find an option called "Ask for confirmation in operations". By default it will be enabled in production domains and you can disable it to avoid that annoying confirmation pages where will have to click either "Yes" or "No". While you are there explore the other useful preferences like "Show Inline Help" and "Show Advanced Sections" which can buy some real-estate space in the console and save you some clicks.




Friday, August 28, 2009

Change in WebLogic Server HTTP Session Failover Logic With Proxy Plug-ins

When using HTTP Sessions with WebLogic Cluster, you can ensure high availability for your session by configuring HTTP Session Replication. For the replication strategy, you have many options to select from like In-memory, file, JDBC, Cookie etc. When you are using in-memory replication with a web server to front WebLogic Server Cluster, the proxy plug-in must be configured on the web servers. The proxy plug-ins are intelligent enough to stick the request from a client to the same server where the session is hosted. A secondary copy of the session will be sent to a backup server by the primary server. This information will be written to a cookie or encoded in the URL depending on the client's configuration to support cookies.



In the past, during failure of the primary server, the proxy plug-in on the web server will redirect the request to the secondary/backup server. This resulted in increased traffic to the secondary/backup server. So somewhere during the Weblogic Server 9.x the plug-ins are updated to do a random routing incase of failures. The proxy server will randomly distribute all the requests from the failed server to different servers that are still running in the cluster. When the request from the existing clients (with valid session id) gets redirected to servers that are not secondary server then that server will connect to the secondary server for that client and will pull the session to become primary server. This ensures that one server will not get overloaded when a server in a cluster fails.




The same exact strategy was used when you front a WebLogic cluster with a load balancing hardware as not all the load balancing hardware understand the WebLogic cluster configuration. Now the same strategy is applied to the WebLogic Cluster front by a proxy plug-in hosted on a web server. This make the failover strategy consistent whether you have hardware or a software based proxy in front a WebLogic Cluster.

WebLogic Server documentation is still not updated to reflect this change under the "Proxy Failover Procedure" section. If you are running WebLogic Cluster with 9.x and you are not seeing this behavior then you can contact Oracle Support to find out whether there is a patch that can you can apply for your current WebLogic implementation.

Monday, June 1, 2009

Use definitions for Reuse [WLST scripting Best Practices (Part-4)]

This post is a continuation of my previous post - in a series of posts about WLST scripting best practices. When you are authoring WLST scripts for automating WebLogic administration tasks, you can reuse or extend an existing logic written in WLST or Jython scripts. You can also leverage or extend logic written in Java which I will discuss later in a different post. Definition are reusable code blocks in Jython. Think of definitions as methods or functions. You can pass parameters into definitions. You can reuse definitions from the same script or from a different script. A script that contains definitions for other scripts to use is usually called as a 'Module'. If you are using a definition from a module then you should import it in your script. The definition should be defined before they get called in the script.

Let us see an example of a using definition in the same script.


#Definition for connecting to a server
def connectToServer():
username = 'weblogic'
password = 'weblogic'
url = 't3://egAdm:7001'
connect(username, password, url)

#Definition to print a running servers heap details
def printHeapDetails(server_name):
domainRuntime()
cd('/')
cd('ServerRuntimes/'+server_name+'/JVMRuntime/'+server_name)
hf = float(get('HeapFreeCurrent'))/1024
hs = float(get('HeapSizeCurrent'))/1024
hf = hf/1024
hs = hs/1024
print 'HeapFreeCurrent - ' + `hf` + 'MB'
print 'HeapSizeCurrent - ' + `hs` + 'MB'

#Definition to disconnect from a server
def disconnectFromServer():
disconnect()
exit()

#Calling connectToServer definition with no arguments
connectToServer()

#Calling printHeapDetails with arguments
printHeapDetails('AdminServer')
printHeapDetails('mgds1')
printHeapDetails('mgds2')

#Calling disconnectFromServer definition with no arguments
disconnectFromServer()


In the above script we are connecting to the administration server of a domain and then printing the heap details for the admin server and 2 other managed servers. The logic to navigate to the respective runtime mbean and printing the heap related attributes is being defined as reusable definition and called multiple times.

WLST-BP-4 Use definitions for Reuse

Monday, March 23, 2009

Reading csv File in WLST Script

One of the comment for an earlier post was about creating domain(s) from csv file with WLST. Creating domain using WLST is a fairly simple and straight forward process. So I decided to explain the simple concept of reading a csv file and creating a domain using an example.

The main trick is to use the Jython language libraries to perform some of the required operations. In my example I shall illustrate how to read command-line arguments, open and read files using Jython. I am also using some local function definitions to create some modular script here. The following is an example of a comma seperated value file that our WLST script can read to create one or more domains:


#domainName,domainLocation,adminUser,adminPassword,adminServerAddress,adminServerPort
testDomain,/home/oracle/domains,system,weblogic,localhost,8998
anotherDomain,/home/oracle/domains,system,weblogic,localhost,7887


Comment lines start with # and each line that is not a comment line represent values for a domain such as domain name, location etc. The script to read the csv file and create the domain can be something like this:


### Script to create WebLogic Domain(s) from csv file
### Reusable Definitions
def buildDomain():
### Read Basic Template
readTemplate(WL_HOME+"/common/templates/domains/wls.jar")
cd('Servers/AdminServer')
set('ListenAddress', adminServerAddress)
set('ListenPort', int(adminServerPort))

### Create Admin User
cd('/')
cd('Security/base_domain/User')
delete('weblogic','User')
create(adminUser,'User')
cd(adminUser)
set('Password',adminPassword)
set('IsDefaultAdmin',1)

### Write Domain
setOption('OverwriteDomain', 'true')
writeDomain(domainLocation+'/'+domainName)
closeTemplate()

def printConfirmation():
### Print Confirmation
print ""
print "Created Domain With Following Values"
print "Domain Name = %s " % domainName
print "Domain Location = %s " % domainLocation
print "Admin User = %s " % adminUser
print "Admin Password = %s " % adminPassword
print "Admin Server Address = %s " % adminServerAddress
print "Admin Server port = %s " % adminServerPort

### Executable Script
### CreateDomain.py
import sys

### Define constants
WL_HOME = "/products/beaSB/wlserver_10.0"

### Read the command-line arguments
argslength = len(sys.argv)
if argslength < 2 :
print '==>Insufficient arguments'
print '==>Syntax: java weblogic.WLST CreateDomain.py csv.file'
exit()
else:
### Read the csv file
fileName = sys.argv[1]
print('Reading File \"' + fileName + '\"' )
f = open(fileName)
try:
for line in f.readlines():
### Strip the comment lines
if line.strip().startswith('#'):
continue
else:
### Split the comma seperated values
items = line.split(',')
items = [item.strip() for item in items]
if len(items) != 6:
print "==>Bad line: %s" % line
print "==>Syntax: domainName, domainLocation, adminUser, adminPassword, adminServerAddress, adminServerPort"
else:
(domainName, domainLocation, adminUser, adminPassword, adminServerAddress, adminServerPort) = items

### Call the definition buildDomain
buildDomain()

### Call the definition printConfirmation
printConfirmation()

except Exception, e:
print "==>Error Occured"
print e
exit()


The executable part of the script is something that is not marked as a definition and in this case it start with the import statement. Any command-line or program arguments passed to WLST are available through sys.argv array. The array is zero indexed and the first element of the array sys.argv[0] is the script file itself. In our script we check to make sure that atleast 2 arguments including the script filename exists.


...
### Read the command-line arguments
argslength = len(sys.argv)
if argslength < 2 :
print '==>Insufficient arguments'
print '==>Syntax: java weblogic.WLST CreateDomain.py csv.file'
exit()
else:
...


Built-in functions are then used to open and read the csv file.


...
f = open(fileName)
try:
for line in f.readlines():
...


We are Using the startswith to eliminate the comment lines and then using the split and strip string function to create a list of all the items passed from the command-line. Later after checking the number of values in each line the list is assigned to a tuple of variable names (tuple is immutable in Jython where as Lists are mutable).


(domainName, domainLocation, adminUser, adminPassword, adminServerAddress, adminServerPort) = items


Once we have all values read and stored in the respective variables then it is pretty straight forward to create a domain which in this case was built as function definition (buildDomain). Later all the values were sent to standard output for user's attention. Also any exception will be reported with the try...except block.

Monday, March 2, 2009

Check for resource/configuration existence [WLST scripting Best Practices (Part-3)]

This post is a continuation of my previous post in a series of posts about WLST scripting best practices. When you are authoring WLST scripts to create new resource/configuration in WebLogic domain then check for its existence. If the resource/configuration already exists then you might get an error similar to the following:

weblogic.descriptor.BeanAlreadyExistsException: Bean already exists

A simple approach is to use the "cd" command to navigate into that configuration MBean. If the "cd" command throws an exception then you can safely assume that the resource/configuration doesn't exists and you can continue creating.

...
### Check for the server
try:
cd('/Servers/' + mgdServerName)
print '===> Server \"' +mgdServerName+'\" already exists'
print '===> No action was performed'
exit()
except:
pass
...


The other approach is to catch the "BeanAlreadyExistsException" while creating the resource and safely exiting the script.


...
### Create the Managed Server
edit()
startEdit()
try:
create(mgdServerName, resourceType)
print '===> Created Managed Server - ' + mgdServerName
pass
except BeanAlreadyExistsException:
print '===> Server \"' +mgdServerName+'\" already exists'
print '===> No action was performed'
cancelEdit('y')
exit()
...

But with this approach you are starting an edit session and creating the server to find out it's existence. So you have to cancel the edit session once you find out that the resource that you are creating already exists if not you might get a warning message similar to the following:

You have an edit session open and you will lose all outstanding changes and your edit session will be stopped if you exit. Are you sure you would like to exit? (y/n)

So cancelling the edit session with a responce 'y' will make WLST not to prompt for user response. I shall discuss how to streamline the outputs from WLST and redirect them to an output file or log file in a later post.

WLST-BP-3 Check for the resource or configuration existence before creating them

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