You are viewing
bikedreamer's journal
| bikedreamer's Journal 20 most recent entries |
I’m writing my own small project on Google app engine using Java, GWT, Spring and JDO. Originally published at Dreamer's thoughts. Please leave any comments there.
Hudson CI server provides plug-in for automated deployment to Tomcat or JBoss servers. But on my current job we use IBM WebSphere as application server in cluster environment. To implement nightly builds with automated testing we had to figure out way to automate deployment. Usual deployment procedure for IBM WebSphere cluster is: 1. Stop cluster All these steps could take 10-15 minutes depending on environment, was security enabled or not, etc. In order to use wsadmin remotely, several files need to be copied from IBM Websphere node manager.
#!/bin/bash
#set -x
# example wsadmin launcher
binDir=`dirname "$0"`
# WAS_HOME should point to the directory for the thin client
WAS_HOME="$binDir"
USER_INSTALL_ROOT="$WAS_HOME"
# JAVA_HOME should point to where java is installed for the thin client
WAS_LOGGING="-Djava.util.logging.manager=com.ibm.ws.bootstrap.WsLogManager -Djava.util.logging.configureByServer=true"
if [ -f ${JAVA_HOME}/bin/java ]; then
JAVA_EXE="${JAVA_HOME}/bin/java"
else
JAVA_EXE="${JAVA_HOME}/jre/bin/java"
fi
CLIENTSOAP=-Dcom.ibm.SOAP.ConfigURL=file:"$USER_INSTALL_ROOT"/properties/soap.client.props
CLIENTSAS=-Dcom.ibm.CORBA.ConfigURL=file:"$USER_INSTALL_ROOT"/properties/sas.client.props
CLIENTSSL=-Dcom.ibm.SSL.ConfigURL=file:"$USER_INSTALL_ROOT"/properties/ssl.client.props
wsadminTraceString=-Dcom.ibm.ws.scripting.traceString=com.ibm.*=all=enabled
wsadminTraceFile=-Dcom.ibm.ws.scripting.traceFile="$USER_INSTALL_ROOT"/logs/wsadmin.traceout
wsadminValOut=-Dcom.ibm.ws.scripting.validationOutput="$USER_INSTALL_ROOT"/logs/wsadmin.valout
# For debugging the utility itself
WAS_DEBUG="-Djava.compiler=NONE -Xdebug -Xnoagent"
#-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=7777"
SHELL=com.ibm.ws.scripting.WasxShell
# Parse the input 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
DELIM=" "
C_PATH="$WAS_HOME/com.ibm.ws.admin.client_6.1.0.jar:$WAS_HOME/com.ibm.ws.security.crypto_6.1.0.jar"
#Platform specific args...
PLATFORM='/bin/uname'
case $PLATFORM in
AIX | Linux | SunOS | HP-UX)
CONSOLE_ENCODING=-Dws.output.encoding=console ;;
OS/390)
EXTRA_D_ARGS="-Dfile.encoding=ISO8859-1 $DELIM-Djava.ext.dirs="$JAVA_EXT_DIRS""
EXTRA_X_ARGS="-Xnoargsconversion" ;;
esac
# Set java options for performance
PLATFORM=`/bin/uname`
case $PLATFORM in
AIX)
PERF_JVM_OPTIONS="-Xms256m -Xmx256m -Xquickstart" ;;
Linux)
PERF_JVM_OPTIONS="-Xms256m -Xmx256m -Xj9 -Xquickstart" ;;
SunOS)
PERF_JVM_OPTIONS="-Xms256m -Xmx256m -XX:PermSize=40m" ;;
HP-UX)
PERF_JVM_OPTIONS="-Xms256m -Xmx256m -XX:PermSize=40m" ;;
OS/390)
PERF_JVM_OPTIONS="-Xms256m -Xmx256m" ;;
esac
"$JAVA_EXE" \
$EXTRA_X_ARGS \
$CONSOLE_ENCODING \
$javaOption \
$WAS_DEBUG \
"$CLIENTSAS" \
"$CLIENTSSL" \
"$CLIENTSOAP" \
${JAASSOAP:+"$JAASSOAP"} \
-Dconfig_consistency_check="$CONFIG_CONSISTENCY_CHECK" \
-Dwas.install.root="$WAS_HOME" \
-Duser.install.root="$USER_INSTALL_ROOT" \
$EXTRA_D_ARGS \
$PERF_JVM_OPTIONS \
$WAS_LOGGING \
$wsadminTraceFile \
$wsadminTraceString \
$wsadminValOut \
$wsadminHost \
$wsadminConnType \
$wsadminPort \
$wsadminLang \
-classpath "$C_PATH" \
$SHELL "${nonJavaOption[@]}"
exit $?
Since we want use in on Hudson, probably on other server and locally, we need Ant script.
<?xml version="1.0"?>
<project basedir=".">
<property environment="env"/>
<property value="./wsIntegration.py"/>
<property value="APPLICATION"/>
<property value="CELL"/>
<property value="CLUSTER"/>
<property value="HOST"/>
<property value="PORT"/>
<property value="PATH_TO_EAR"/>
<property value="${basedir}/wsadmin.sh"/>
<target >
<exec dir="." executable="${wsadmin}" outputproperty="currentState">
<arg value="-conntype"/>
<arg value="SOAP"/>
<arg value="-lang"/>
<arg value="jython"/>
<arg value="-host"/>
<arg value="${host}"/>
<arg value="-port" />
<arg value="${port}"/>
<arg value="-f"/>
<arg value="${was.python.script}"/>
<arg value="clusterState"/>
<arg value="${application.cell}"/>
<arg value="${application.cluster}"/>
</exec>
</target>
<target >
<exec dir="." executable="${wsadmin}">
<arg value="-conntype"/>
<arg value="SOAP"/>
<arg value="-lang"/>
<arg value="jython"/>
<arg value="-host"/>
<arg value="${host}"/>
<arg value="-port" />
<arg value="${port}"/>
<arg value="-f"/>
<arg value="${was.python.script}"/>
<arg value="clusterStart"/>
<arg value="${application.cell}"/>
<arg value="${application.cluster}"/>
</exec>
</target>
<target >
<exec dir="." executable="${wsadmin}">
<arg value="-conntype"/>
<arg value="SOAP"/>
<arg value="-lang"/>
<arg value="jython"/>
<arg value="-host"/>
<arg value="${host}"/>
<arg value="-port" />
<arg value="${port}"/>
<arg value="-f"/>
<arg value="${was.python.script}"/>
<arg value="clusterStop"/>
<arg value="${application.cell}"/>
<arg value="${application.cluster}"/>
</exec>
</target>
<target >
<exec dir="." executable="${wsadmin}">
<arg value="-conntype"/>
<arg value="SOAP"/>
<arg value="-lang"/>
<arg value="jython"/>
<arg value="-host"/>
<arg value="${host}"/>
<arg value="-port" />
<arg value="${port}"/>
<arg value="-f"/>
<arg value="${was.python.script}"/>
<arg value="undeployApplication"/>
<arg value="${application.name}"/>
</exec>
</target>
<target >
<exec dir="." executable="${wsadmin}">
<arg value="-conntype"/>
<arg value="SOAP"/>
<arg value="-lang"/>
<arg value="jython"/>
<arg value="-host"/>
<arg value="${host}"/>
<arg value="-port" />
<arg value="${port}"/>
<arg value="-javaoption" />
<arg value="-Dwdm.http.host=${host}" />
<arg value="-f"/>
<arg value="${was.python.script}"/>
<arg value="redeployApplication"/>
<arg value="${application.ear}"/>
<arg value="${application.cell}"/>
<arg value="${application.cluster}"/>
<arg value="${application.name}"/>
</exec>
</target>
<target>
<antcall target="clusterStopt"/>
<exec dir="." executable="./waitForState.sh">
<arg value="Cluster State: websphere.cluster.stopped"/>
<arg value="${host}"/>
<arg value="${port}"/>
<arg value="${application.cell}"/>
<arg value="${application.cluster}"/>
</exec>
<antcall target="undeployApplication"/>
<antcall target="redeployApplication"/>
<antcall target="clusterStart"/>
<exec dir="." executable="./waitForState.sh">
<arg value="Cluster State: websphere.cluster.running"/>
<arg value="${host}"/>
<arg value="${port}"/>
<arg value="${application.cell}"/>
<arg value="${application.cluster}"/>
</exec>
</target>
</project>
Most interesting last part then we stop cluster, wait till it shut downs completely, undeploy application, redeploy application, start cluster and wait will it starts successfully. We use jython as wsadmin programming language.
import sys
def clusterStop(cell, cluster):
cluster = AdminControl.completeObjectName('cell='+cell+',type=Cluster,name='+cluster+',*')
print "Stop Cluster : %s" % ( repr(cluster) )
AdminControl.invoke(cluster, 'stop')
def clusterStart(cell, cluster):
cluster = AdminControl.completeObjectName('cell='+cell+',type=Cluster,name='+cluster+',*')
print "Start Cluster : %s" % ( repr(cluster) )
AdminControl.invoke(cluster, 'start')
def clusterState(cell, cluster):
cluster = AdminControl.completeObjectName('cell='+cell+',type=Cluster,name='+cluster+',*')
state = AdminControl.getAttribute(cluster, 'state')
print "Cluster State: %s" %(state)
def appState(app):
state = AdminControl.completeObjectName('type=Application,name='+app+',*')
print "App State: %s" %(state)
def undeployApplication(appName):
AdminApp.uninstall( appName )
AdminConfig.save()
def redeployApplication(pathToFile, cell, cluster, appName):
print "installApplicationOnServer: fileName=%s appName=%s Cell=%s Cluster=%s" % ( pathToFile, appName, cell, cluster )
AdminApp.install(pathToFile,'[-nopreCompileJSPs -distributeApp -nouseMetaDataFromBinary -nodeployejb -appname "'+appName+'" -createMBeansForResources -noreloadEnabled -nodeployws -MapModulesToServers [["WEB_APP_NAME" WEB_APP_NAME.war,WEB-INF/web.xml WebSphere:cell='+cell+',cluster='+cluster+' ]] -MapWebModToVH [["WEB_APP_NAME" WEB_APP_NAME.war,WEB-INF/web.xml shared_host ]] -verbose]')
AdminConfig.save()
"""modify classloader model for application"""
deploymentID = AdminConfig.getid('/Deployment:'+appName+'/')
deploymentObject = AdminConfig.showAttribute(deploymentID, 'deployedObject')
classldr = AdminConfig.showAttribute(deploymentObject, 'classloader')
AdminConfig.modify(classldr, [['mode', 'PARENT_LAST']])
"""Modify WAR class loader model"""
AdminConfig.show(deploymentObject, 'warClassLoaderPolicy')
AdminConfig.modify(deploymentObject, [['warClassLoaderPolicy', 'SINGLE']])
AdminConfig.save()
"""-----------------------------------------------------------
Phyton script to interface with WAS Admin/Management Tools
-----------------------------------------------------------"""
if len(sys.argv) < 1:
print "wasAdminIntegration.py : need parameters : functionName <args>"
sys.exit(0)
if(sys.argv[0] == 'clusterStop'):
clusterStop(sys.argv[1], sys.argv[2])
if(sys.argv[0] == 'clusterStart'):
clusterStart(sys.argv[1], sys.argv[2])
if(sys.argv[0] == 'clusterState'):
clusterState(sys.argv[1], sys.argv[2])
if(sys.argv[0] == 'undeployApplication'):
undeployApplication(sys.argv[1])
if(sys.argv[0] == 'appState'):
appState(sys.argv[1])
if(sys.argv[0] == 'redeployApplication'):
redeployApplication(sys.argv[1], sys.argv[2], sys.argv[3], sys.argv[4])</pre>
In this code, replace “WEB_APP_NAME” with real application name or change the script so it can be passed with the rest of parameters. For waiting part of the scripts, we will user same jython script in conjuction with bash. #!/bin/bash binDir=`dirname "$0"` REQURED_STATE=$1 WAS_HOST=$2 WAS_PORT=$3 WAS_CELL=$4 WAS_CLUSTER=$5 if [ ! -n "$REQURED_STATE" ] || [ ! -n "$WAS_HOST" ] || [ ! -n "$WAS_PORT" ] || [ ! -n "$WAS_CELL" ] || [ ! -n "$WAS_CLUSTER" ]; then echo "Usage: waitForState.sh <state> <host> <port> <cell> <cluster>" exit 1 fi CURR_STATE="" echo "CURR_STATE: $CURR_STATE" while [[ "$CURR_STATE" != "$REQURED_STATE" ]] do sleep 20 CURR_STATE="$($binDir/wsadmin.sh -conntype SOAP -lang jython -host $WAS_HOST -port $WAS_PORT -f ./wsAdminIntegration.py clusterState $WAS_CELL $WAS_CLUSTER |grep State:)" echo "Current State: $CURR_STATE" done So, now we can use all these code in conjunction just by calling ant fullRedeploy Output log should be monitored for Websphere errors. If it return “Result: 99″ for every operation, then everything is fine, otherwise, something went wrong. Originally published at Dreamer's thoughts. You can comment here or there. 3 comments | post a comment
Sometime ago I ran into the problem with Tomcat DataSource definition – it doesn’t allow encrypted password! So, we need to be able to specify DataSource with encrypted password in Tomcat. <Resource name="jdbc/MyDS" auth="Container" type="javax.sql.DataSource" driverClassName="oracle.jdbc.OracleDriver" url="CONNECTION_STRING" username="USER_NAME" password="PASSWORD"/> In this case, Tomcat sees that attribute ‘type’ equals to ‘javax.sql.DataSource’ and creates connection pool using BasicDataSourceFactory from tomcat-dbcp.jar library. Implementation of custom Object factory is shown below.
package my.home;
import java.net.URL;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.Name;
import javax.naming.NamingException;
import javax.naming.RefAddr;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import javax.naming.spi.ObjectFactory;
import org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory;
public class DataSourceWithEncryptedPasswordFactoryimplements ObjectFactory {
public static final String DBCP_DATASOURCE_FACTORY = "org.apache.tomcat.dbcp.dbcp.BasicDataSourceFactory";
public static final String PROP_PASSWORD = "password";
public static final String PASSWORD_PROVIDER = "passwordProvider";
public static final String PASSWORD_FILE = "passwordFile";
private BasicDataSourceFactory basicDataSourceFactory = null;
private MyPasswordProvider passwordProvider = null;
public EncryptedPasswordDataSourceFactory() {
}
public Object getObjectInstance(Object obj, Name name, Context nameCtx,
Hashtable<?, ?> environment) throws Exception {
try {
basicDataSourceFactory = (BasicDataSourceFactory) Class.forName(DBCP_DATASOURCE_FACTORY).newInstance();
} catch (Throwable t) {
NamingException ex = new NamingException("Could not create resource factory instance internal");
ex.initCause(t);
throw ex;
}
Reference ref = (Reference)obj;
String sPasswordProvider = ref.get(PASSWORD_PROVIDER).getContent().toString();
if (sPasswordProvider != null && sPasswordProvider.length() > 0){
ClassLoader loader = Thread.currentThread().getContextClassLoader();
passwordProvider = (MyPasswordProvider)Class.forName(sPasswordProvider, true, loader).newInstance();
String sPasswordFile = ref.get(PASSWORD_FILE).getContent().toString();
if (sPasswordFile != null && sPasswordFile.length() > 0){
URL file = loader.getResource(sPasswordFile);
}
String password = passwordProvider.getPassword(file);
StringRefAddr newPasswordRA = new StringRefAddr(PROP_PASSWORD, password);
ref.add(0, newPasswordRA);
}
return basicDataSourceFactory.getObjectInstance(obj, name, nameCtx, environment);
}
}
For the factory, Resource definition will look like that: <Resource name="jdbc/MyDS" auth="Container" type="javax.sql.DataSource" factory="my.home.DataSourceWithEncryptedPasswordFactory" passwordProvider="my.home.MyPasswordProvider" passwordFile="PASSWORDFILE" driverClassName="oracle.jdbc.OracleDriver" url="CONNECTION_STRING" username="USER_NAME"/> I hope this will help someone who is stuck with unencrypted passwords in Tomcat. Originally published at Dreamer's thoughts. You can comment here or there. post a comment
Вот интересно, как японцы разбирают, как читать иероглиф は? ха или ва?
DSC_0019, originally uploaded by BikeDreamer.
DSC_0019, originally uploaded by BikeDreamer. 1 comment | post a comment
post a comment
Был приятно удивлен работой Lost and Found в нашем MBTA.
test cossposting to LJ post a comment
Надо составлять список книг для покупки в России 9 comments | post a comment
Вот и до нас докатилась волна спада в американской экономике - с нового года я безработный.
Жена хочет новый монитор....
В конце мая мы с Юлей зашли послушать музыку на Earth Fest, что проходил не далеко от нашего дома.
Сегодня обедал с настоящим админом и он рассказал (вернее сначала ему пришлось показать) как он работает.
Есть така программа для финансов Quicken, она при загрузке транзакции пытается угодать ее категорию.
( под катом ) 2 comments | post a comment
Сегодня ночью, ближе к концу зимы, решил выпасть снег. Снег в Бостоне, это не просто снег, а нечто мокрое, хлюпкое и до ужаса противное. Переборов себя, я пошел провожать Юлю в институт и за одно прогуляться в библиотеку. Вышли мы из квартиры под то, что тут называется "Freezing rain", т.е. помесь воды со льдом, летящее сверху плюс ветер, который пытается направить все это тебе в лицо, несмотря на то, что ты идешь под зонтиком. Машины по Beacon Hill едут медленно - медленно, тут водители начинают вспоминать почему Beacon Hill все же Hill - если разгонишься сильно есть вероятность оказаться или на Cambridge или на Charles street, или, что еще веселей, съехать по ступенькам прямо в Boston Common.
Повадился я таскать из Boston Public Library сериал The West Wing. Сериал, кстати, неплохой - смотреть интересно. Но, не про то разговор. Попутно беру фильмы, которые мне бы хотелось иметь в собственной коллекции. Взял я на днях старый The Omen и стал его листать. Среди прочих трейлеров на этом диске, оказался наш Ночной Дозор. Так же сей фильм шел в славном городе Ванкувере, год назад, на больших экранах. Все это не может меня не радовать - могут же сделать фильм, который заинтересует голливудский FOX, настолько что его будут продвигать всеми способами. |
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||