#!/bin/ksh93 # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License") # (see http://www.opensource.org/licenses/CDDL-1.0). # # Copyright (c) 2011-2012 Jens Elkner. All rights reserved. # Use is subject to license terms. SDIR=${.sh.file} && SDIR=${SDIR%/*} && [[ $SDIR == ${.sh.file} ]] && SDIR=$PWD GFS_DIR=${ cd "$SDIR/.." ; print $PWD; } export PATH=${PATH}:. # glassfish related poperties, like install and data dir GF_PROPS=gf.properties # SMF manifest template to use MANIFEST_TEMPLATE=etc/manifest.xml # where the manifest for the domain in question gets copied MANIFEST_DIR=/lib/svc/manifest/application/glassfish typeset -ft $(typeset +f) Usage() { BN=${0##*/} printf ' Usage: %s [-n] [-D] -c {domain|service|dbpool|datasource|realm2|mail} -d domain [-a applist] %s [-n] [-D] -r {domain|service|dbpool|datasource|realm2|mail} -d domain [-a applist] %s [-n] -x {start|stop|chpass} -d domain %s [-h] Options: -n .. dry run, i.e. show what to do but do not execute it -D .. enable debug mode -c target .. create the given target for the given domain -r target .. remove the given target for the given domain -d domain .. the name of the domain aka instance in question -a applist .. a comma separated list of web application names to apply the specified target (honored for dbpool|datasource|realm2). The names are the directory name of the corresponding web application in the GF setup directory. The directory must have a db.properties files, otherwise it gets ignored (see %s/$domain/ ). If omitted, %s tries to create it for all valid $domain/ sub directories. -x action .. execute the given action for the given domain. ' "$BN" "$BN" "$BN" "$GFS_DIR" "$BN" if [[ -n $HELP ]]; then printf "\n\n Related files: The base directory for all GF related properties and required stuff for deployment. Assumed dir layout: %s base directory (name is not important) /etc/ contains this script and misc support files /gf.properties default properties for all GF instances /gf.properties.\$hostname additional properties for all GF instances on this machine (optional) /\$domain/domain.properties additional properties for all GF instances for the via -d option given domain /\$dbtype-pool.properties default properties for the given type of DB /\$domain/\$dbtype-pool.properties additional properties for the given type of DB for the via -d option given domain (optional) /\$domain/\$app/\$dbtype-pool.properties additional properties for the given type of DB for the via -d option given domain (optional) for the via -a given web applications /\$domain/\$app/build.properties additional application specific properties (see option -d and -a) /lib/ contains additional/fixed libs for GF " "$GFS_DIR" fi } ACTION= DOMAIN= TARGET= ECHO= TMPFILE= APPS= OPTS= DEBUG= HELP= while getopts "c:(create)r:(remove)d:(domain)h(help)n(dry)a:(apps)D(debug)x:(excute)" option ; do case "$option" in h) HELP=1; Usage ; exit 0 ;; c) ACTION=CREATE ; TARGET="$OPTARG" ;; r) ACTION=DELETE ; TARGET="$OPTARG" ;; d) DOMAIN="$OPTARG" ;; n) ECHO="echo " ;; a) APPS="$OPTARG" ;; D) DEBUG ;; x) ACTION=EXECUTE if [[ $OPTARG == start ]]; then TARGET=start elif [[ $OPTARG == stop ]]; then TARGET=stop elif [[ $OPTARG == chpass ]]; then TARGET=chpass else print -u2 "Invalid action for option -x" exit 1; fi ;; *) print -u2 "exiting" ; exit 1; esac done IDX=$((OPTIND-1)) shift $IDX if [[ -z $DOMAIN ]]; then print -u2 "Missing domain - exiting." ; Usage ; exit 2 fi if [[ -z $TARGET ]]; then print -u2 "Missing target - exiting." ; Usage ; exit 3 fi if [[ -z $ACTION ]]; then print -u2 "Don't what to do - exiting." ; Usage ; exit 4 fi cleanup() { [[ -n $TMPFILE ]] && rm -f "$TMPFILE" } sourceGlobalProps() { source "$GF_PROPS" RES=$? NODENAME=${ hostname; } [[ -r ${GF_PROPS}.$NODENAME ]] && source "${GF_PROPS}.$NODENAME" return $RES } cd $GFS_DIR sourceGlobalProps if (( $? != 0 )); then print -u2 "directory $GFS_DIR does not exist - exiting" ; exit 5 fi source "$DOMAIN/domain.properties" if [[ ! -x $ASADMIN ]]; then print -u2 "$ASADMIN does not exist - exiting" exit 1 fi # All other errors should be caught by asadmin createService() { if [[ ! -r $MANIFEST_TEMPLATE ]]; then print -u2 "manifest template $MANIFEST_TEMPLATE not found in $PWD - exiting." return fi if [[ ! -d $MANIFEST_DIR ]]; then $ECHO mkdir "$MANIFEST_DIR" (( $? -ne 0 )) && print -u2 "Exiting." && return fi if [[ -r $MANIFEST_DIR/${DOMAIN}.xml ]]; then print -u2 "$MANIFEST_DIR/${DOMAIN}.xml exists already. Remove the service first." return fi if [[ -z $ECHO ]]; then SECOPT="" [[ $SECURE == true ]] && SECOPT="-s" gsed -e "s,@ASADMIN@,$ASADMIN,g" -e "s,@SECURE@,${SECOPT}," \ -e "s,@DOMAIN_DIR@,$DOMAIN_DIR,g" \ -e "s,@DOMAIN@,$DOMAIN,g" "$MANIFEST_TEMPLATE" \ > "$MANIFEST_DIR/${DOMAIN}.xml" [[ ! -r $MANIFEST_DIR/${DOMAIN}.xml ]] && print -u2 "Exiting." && return else echo "gsed -e s,@ASADMIN@,$ASADMIN,g" \ "-e s,@DOMAIN_DIR@,$DOMAIN_DIR,g" \ "-e s,@DOMAIN@,$DOMAIN,g" "$MANIFEST_TEMPLATE" \ " > $MANIFEST_DIR/${DOMAIN}.xml" fi SVCCFG_CHECKHASH=1 $ECHO /usr/sbin/svcadm restart svc:/system/manifest-import #$ECHO /usr/sbin/svccfg -v import "$MANIFEST_DIR/${DOMAIN}.xml" } addPassOpts() { if [[ -z $AS_ADMIN_PASSWORD ]]; then print -u2 "AS_ADMIN_PASSWORD env variable should be set! Trying without a password!" return fi TMPFILE=${ mktemp -tq; } if [[ -z $TMPFILE ]]; then echo "Unable to create a tmp password file - falling back to interactive mode" return fi chmod 600 "$TMPFILE" printf "AS_ADMIN_PASSWORD=%s\n" "$AS_ADMIN_PASSWORD" >>"$TMPFILE" OPTS="--passwordfile $TMPFILE" } createRealm2() { [[ -z $1 ]] && return if [[ ! -r $DOMAIN_DIR/$DOMAIN/config/login.conf ]]; then print -u2 "Unable to read $DOMAIN_DIR/$DOMAIN/config/login.conf - exiting." return elif [[ ! -r $AS_HOME/glassfish/modules/jdbcrealm2.jar ]]; then print -u2 "$AS_HOME/glassfish/modules/jdbcrealm2.jar does not exist - exiting" return fi PW_QUERY='SELECT passwd FROM users WHERE login\=? AND (ISNULL(expire) OR (UNIX_TIMESTAMP() - (expire/1000) < 0))' GRP_QUERY='SELECT r.name FROM users u JOIN user2role m ON u.id\=m.uid JOIN roles r ON m.rid\=r.id WHERE u.login\=?' JNDI_DS=${ getDSname $1; } $ECHO $ASADMIN ${OPTS} create-auth-realm --domaindir "$DOMAIN_DIR" \ --classname "de.ovgu.cs.frs.auth.JDBCRealm2" \ --property "passwd-query=${PW_QUERY}:groups-query=${GRP_QUERY}:datasource-jndi=${JNDI_DS}:digest-algorithm=MD5:encoding=base64:charset=UTF-8:jaas-context=jdbcRealm2" \ "$1""-realm" $ECHO grep -q '^[[:space:]]*jdbcRealm2 ' \ "$DOMAIN_DIR/$DOMAIN/config/login.conf" if (( $? == 1 )); then if [[ -z $ECHO ]]; then echo 'jdbcRealm2 { de.ovgu.cs.frs.auth.JDBCLoginModule required; };' >> "$DOMAIN_DIR/$DOMAIN/config/login.conf" else $ECHO "echo 'jdbcRealm2 { de.ovgu.cs.frs.auth.JDBCLoginModule required; };' >> $DOMAIN_DIR/$DOMAIN/config/login.conf" fi fi } getPoolOpts() { FILES="" for PF in "${DB_TYPE}-pool.properties" \ "$DOMAIN/${DB_TYPE}-pool.properties" \ "$DOMAIN/$1/${DB_TYPE}-pool.properties" do [[ -r $PF ]] && FILES="$FILES $PF" done [[ -z $FILES ]] && return cat $FILES | gsed -e '/^#/ d' -e '/^[[:space:]]*$/ d' \ -e 's/[[:space:]]*$//'| tr '\n' ':' } createPool() { [[ -z $1 ]] && return unset DB_TYPE DB_PORT DB_HOST DB_NAME DS_CLASSNAME sourceGlobalProps source "$DOMAIN/domain.properties" [[ -r $DOMAIN/$1/build.properties ]] && source "$DOMAIN/$1/build.properties" MISSING="" [[ -z $DB_TYPE ]] && MISSING+=" DB_TYPE" [[ -z $DB_PORT ]] && MISSING+=" DB_PORT" [[ -z $DB_HOST ]] && MISSING+=" DB_HOST" [[ -z $DB_NAME ]] && MISSING+=" DB_NAME" [[ -z $DB_USER ]] && MISSING+=" DB_USER" if [[ -n $MISSING ]]; then print -u2 "The following properties are not set for $DOMAIN/$1: $MISSING - skipping" return fi if [[ -z $DS_CLASSNAME ]]; then if [[ $DB_TYPE == mysql ]]; then DS_CLASSNAME="com.mysql.jdbc.jdbc2.optional.MysqlXADataSource" else print -u2 "DS_CLASSNAME property is not set. Don't know, which datasource XA classname to use - exiting." return fi fi if [[ -n $DB_JAR ]]; then #DST="$DOMAIN_DIR/$DOMAIN/lib/$DB_JAR" # or better for all DST="$AS_HOME/glassfish/lib/$DB_JAR" if [[ ! -r $DST ]]; then if [[ -r lib/$DB_JAR ]]; then cp "lib/$DB_JAR" "$DST" if (( $? -ne 0 )); then print -u2 "You should copy the DB driver manually to its destination:\n+ cp $GFS_DIR/lib/$DB_JAR $DST\n" fi else print -u2 "Missing lib/$DB_JAR - should be copied to $DST/ - skipping" return fi fi fi SOPTS=${ getPoolOpts "$1"; } [[ -n $SOPTS ]] && SOPTS="${SOPTS}:" SOPTS="$SOPTS"'URL=jdbc\:mysql\://'"$DB_HOST"'\:'"$DB_PORT/$DB_NAME" PNAME=${ getPoolId "$1"; } # we use a dummy for empty pass to get it created SOPTS="${SOPTS}:user=${DB_USER}:password=${DB_PASS:-___}" DESC="$1 Pool" [[ -n $PRODUCT_NAME ]] && DESC="$PRODUCT_NAME Pool" $ECHO $ASADMIN ${OPTS} create-jdbc-connection-pool \ --datasourceclassname="$DS_CLASSNAME" \ --restype="javax.sql.XADataSource" \ --steadypoolsize=8 \ --maxpoolsize=32 \ --maxwait=15000 \ --poolresize=2 \ --idletimeout=300 \ --isolationlevel="repeatable-read" \ --isisolationguaranteed="true" \ --isconnectvalidatereq="true" \ --validationmethod="auto-commit" \ --failconnection="false" \ --allownoncomponentcallers="false" \ --nontransactionalconnections="false" \ --description "$DESC" \ --property "$SOPTS" \ ${ getPoolId "$1"; } if [[ -z $DB_PASS ]]; then print "\nPlease enter the DB password for the DB user '$DB_USER' which\ngets stored encrypted in the domains alias database:" $ECHO $ASADMIN ${OPTS} create-password-alias "$PNAME" DB_PASS='${ALIAS='"$PNAME"'}' print '\nAssigning password alias:' $ECHO $ASADMIN ${OPTS} set resources.jdbc-connection-pool."$PNAME".property.password="$DB_PASS" fi } createDefaultArgs() { OPTS="" addPassOpts [[ -n $AS_HOST ]] && OPTS="$OPTS --host $AS_HOST" [[ -n $AS_PORT_ADMIN ]] && OPTS="$OPTS --port $AS_PORT_ADMIN" [[ $SECURE == true ]] && OPTS="$OPTS --secure=true" [[ -z $AS_ADMIN ]] && AS_ADMIN="admin" OPTS="$OPTS --user $AS_ADMIN" } getDSname() { [[ -z $1 ]] && return print "jdbc/$1" } getPoolId() { [[ -z $1 ]] && return print "$1Pool" } checkApps() { if [[ -z $APPS ]]; then for f in "$DOMAIN"/* ; do [[ -d $f ]] && APPS="$APPS ${f#*/}" done fi APPS=${APPS//,/ } } if [[ $ACTION == CREATE ]]; then # datasource if [[ $TARGET == service ]]; then createService return fi createDefaultArgs checkApps if [[ $TARGET == domain ]]; then SOPTS="" [[ -n $AS_PORT_ADMIN ]] && SOPTS="$SOPTS --adminport $AS_PORT_ADMIN" [[ -n $AS_PORT_HTTP ]] && SOPTS="$SOPTS --instanceport $AS_PORT_HTTP" DOMPROPS="" [[ -n $AS_PORT_HTTP_SSL ]] && DOMPROPS="${DOMPROPS}:http.ssl.port=$AS_PORT_HTTP_SSL" [[ -n $AS_PORT_JMS ]] && DOMPROPS="${DOMPROPS}:jms.port=$AS_PORT_JMS" [[ -n $AS_PORT_JMX ]] && DOMPROPS="${DOMPROPS}:domain.jmxPort=$AS_PORT_JMX" [[ -n $AS_PORT_ORB ]] && DOMPROPS="${DOMPROPS}:orb.listener.port=$AS_PORT_ORB" [[ -n $AS_PORT_ORB_SSL ]] && DOMPROPS="${DOMPROPS}:orb.ssl.port=$AS_PORT_ORB_SSL" [[ -n $AS_PORT_ORB_MUTAUTH ]] && DOMPROPS="${DOMPROPS}:orb.mutualauth.port=$AS_PORT_ORB_MUTAUTH" [[ -n $AS_PORT_OSGI ]] && DOMPROPS="${DOMPROPS}:osgi.shell.telnet.port=$AS_PORT_OSGI" [[ -n $DOMPROPS ]] && SOPTS="$SOPTS --domainproperties ${DOMPROPS#:}" if [[ -z $AS_ADMIN_MASTERPASSWORD ]]; then AS_ADMIN_MASTERPASSWORD="changeit" print -u2 "Using default AS_ADMIN_MASTERPASSWORD changeit" fi [[ -n $TMPFILE && -r $TMPFILE ]] && \ printf "AS_ADMIN_MASTERPASSWORD=%s\n" "$AS_ADMIN_MASTERPASSWORD" \ >>$TMPFILE $ECHO $ASADMIN ${OPTS} create-domain --domaindir "$DOMAIN_DIR" \ --savemasterpassword $SOPTS "$DOMAIN" # set configs.config.server-config.network-config.protocols.protocol.admin-listener.security-enabled=true if [[ $SECURE == true ]]; then DOMFILE="$DOMAIN_DIR/$DOMAIN/config/domain.xml" if [ -r "$AS_HOME/.org.opensolaris,pkg/pkg/glassfish-jca"/3.1*/manifest ]; then # since GF 3.1 $ECHO mv "$DOMFILE" "${DOMFILE}.orig" if [[ -z $ECHO ]]; then xsltproc $GFS_DIR/etc/gf31domain.xslt "${DOMFILE}.orig" \ > "$DOMFILE" else $ECHO "xsltproc $GFS_DIR/etc/gf31domain.xslt \"${DOMFILE}.orig\" > \"$DOMFILE\"" fi else $ECHO gsed -i -e '/name="admin-listener"/ s,protocol ,protocol security-enabled="true" ,' "$DOMFILE" fi fi $ECHO chown -R ${DOMAIN_USER:-webservd}:${DOMAIN_GROUP:-webservd} \ "$DOMAIN_DIR/$DOMAIN" if [[ ${ id -un; } != $USER ]]; then $ECHO chmod A2+user:$USER:rwxpAWCo:allow "$DOMAIN_DIR/$DOMAIN"/config $ECHO chmod A2+user:$USER:rwxpAWCo:allow "$DOMAIN_DIR/$DOMAIN"/autodeploy fi cleanup return fi if [[ ! -d $DOMAIN_DIR/$DOMAIN ]]; then print -u2 "Create domain $DOMAIN first" cleanup return fi case "$TARGET" in realm2) for APP in $APPS ; do createRealm2 "$APP" done ;; mail) MISSING="" [[ -z $MAIL_JNDI_NAME ]] && MISSING+=" MAIL_JNDI_NAME" [[ -z $MAIL_SMTP_SERVER ]] && MISSING+=" MAIL_SMTP_SERVER" if [[ -z $MAIL_DEFAULT_USER ]]; then MISSING+=" MAIL_DEFAULT_USER" elif [[ -z $MAIL_DEFAULT_FROM ]]; then MAIL_DEFAULT_FROM="${MAIL_DEFAULT_USER}@localhost" fi if [[ -n $MISSING ]]; then print -u2 "The following properties are not set: $MISSING - exiting" cleanup return fi $ECHO $ASADMIN ${OPTS} create-javamail-resource \ --mailhost "$MAIL_SMTP_SERVER" \ --mailuser "$MAIL_DEFAULT_USER" \ --fromaddress "$MAIL_DEFAULT_FROM" \ "$MAIL_JNDI_NAME" ;; dbpool) for APP in $APPS ; do createPool "$APP" done ;; datasource) for APP in $APPS ; do $ECHO $ASADMIN ${OPTS} create-jdbc-resource \ --target "server" \ --connectionpoolid $(getPoolId "$APP") \ --description "${DOMAIN} datasource" \ ${ getDSname "$APP"; } done ;; *) print -u2 "Unsupported create target \"$TARGET\" - exiting." ;; esac fi if [[ $ACTION == DELETE ]]; then if [[ $TARGET == service ]]; then $ECHO /usr/sbin/svcadm disable "glassfish/$DOMAIN" # Solaris 11 is not backward compatible to S10 #$ECHO /usr/sbin/svccfg delete "glassfish/$DOMAIN" $ECHO rm -f "$MANIFEST_DIR/${DOMAIN}.xml" $ECHO /usr/sbin/svcadm restart svc:/system/manifest-import return fi createDefaultArgs checkApps case "$TARGET" in domain) /usr/sbin/svcadm disable glassfish/"$DOMAIN" sleep 2 $ECHO $ASADMIN ${OPTS} delete-domain --domaindir "$DOMAIN_DIR" \ "$DOMAIN" X=${ svcs -H -o state glassfish/"$DOMAIN" 2>/dev/null; } [[ -n $X ]] && \ print "The SMF service glassfish/$DOMAIN is $X. To remove it use:\n ${0##*/} -r service -d $DOMAIN" ;; realm2) for APP in $APPS ; do $ECHO $ASADMIN ${OPTS} delete-auth-realm "$APP-realm" done print -u2 "Remove the 'jdbcRealm2' from $DOMAIN_DIR/$DOMAIN/config/login.conf if you do not need it anymore ..." ;; mail) if [[ -z $MAIL_JNDI_NAME ]]; then print -u2 "$MAIL_JNDI_NAME is not set - exiting" cleanup return fi $ECHO $ASADMIN ${OPTS} delete-javamail-resource "$MAIL_JNDI_NAME" ;; dbpool) for APP in $APPS ; do ID=${ getPoolId "$APP"; } [[ -z $ID ]] && continue $ECHO $ASADMIN ${OPTS} delete-jdbc-connection-pool \ --cascade=true "$ID" done ;; datasource) for APP in $APPS ; do $ECHO $ASADMIN ${OPTS} delete-jdbc-resource \ --target "domain" \ ${ getDSname "$APP"; } done ;; *) print -u2 "Unsupported remove target \"$TARGET\" - exiting." ;; esac fi if [[ $ACTION == EXECUTE ]]; then createDefaultArgs checkApps OPTS= case "$TARGET" in start) $ECHO $ASADMIN start-domain --domaindir "$DOMAIN_DIR" \ "$DOMAIN" ;; stop) [[ $SECURE == true ]] && OPTS="$OPTS --secure=true" $ECHO $ASADMIN ${OPTS} stop-domain --domaindir "$DOMAIN_DIR" \ "$DOMAIN" ;; chpass) cat <