Novell Home

Load Balancing ZENworks Desktop Components across a Linux Cluster

Novell Cool Solutions: Feature
By Giovanni Coa

Digg This - Slashdot This

Posted: 3 Oct 2006
 

ENVIRONMENT:
Open Enterprise Server SP1
ZENworks Desktop Management 7 SP1
Novell Cluster Services

PROBLEM: By default ZENworks Desktop Management 7 utilizes only one cluster node at a time with all configured services running on it (no load balancing at all).

Here's how to load-balance ZENworks Desktop Management 7 components across an NCS on Linux cluster with multiple nodes in such a way that services such as PXE, Imaging, etc., may be moved from one node to another independently, taking advantage of the processing power of multiple cluster nodes.

SOLUTION: Look at the modified script in the Example, modified sections have the *CLUSTER* in the comment.

We left out the Middle Tier services because we don't use them.

After that modification you can create different cluster resources for each ZENworks service and start and stop them using the following syntax :

Usage: ZDMstart <cmd> <service>
where <cmd> is one of:

  • start = start specified service
  • stop = stop specified service
  • status = show status of the specified service
  • help = display this message

and <service> is one of:

  • awsi = ZENworks Auto Workstation Import/Removal Service
  • img = ZENworks Imaging Service
  • pxe = ZENworks PXE Services
  • rm = ZENworks Remote Management Service
  • inv = ZENworks Inventory Service

EXAMPLE:

#!/bin/bash
# Copyright (c) 2005 Novell, Inc.  All rights reserved.

unset IFS
PATH=/bin:/usr/bin

PROG=${0##*/}
GETTEXT=/usr/bin/gettext
[ -x $GETTEXT ] || GETTEXT=echo

#-----------------------------------------------------------------------------
# *CLUSTER* Modified to show how to control single ZENworks services
# Display usage message
#
USAGE()
{
    if [[ $ACTION != *help ]] ;then
        UNKNOWN=$($GETTEXT "unknown action: '%s'")
        printf "$UNKNOWN\n" $ACTION
    fi

    USAGE=$($GETTEXT 'Usage: %s <cmd> <service>')
    WHERE=$($GETTEXT 'where <cmd> is one of:')

    STRT_MSG=$($GETTEXT 'start specified service')
    STOP_MSG=$($GETTEXT 'stop specified service')
    STAT_MSG=$($GETTEXT 'show status of the specified service')
    HELP_MSG=$($GETTEXT 'display this message')

    printf "\n$USAGE\n" $PROG
    printf "  $WHERE\n"
    printf "   start  = $STRT_MSG\n"
    printf "   stop   = $STOP_MSG\n"
    printf "   status = $STAT_MSG\n"
    printf "   help   = $HELP_MSG\n"
    printf "\n"

    WHERE=$($GETTEXT 'and <service> is one of:')

    AWSI_MSG=$($GETTEXT 'ZENworks Auto Workstation Import/Removal Service')
    PXE_MSG=$($GETTEXT 'ZENworks PXE Services')
    RM_MSG=$($GETTEXT 'ZENworks Remote Management Service')
    IMG_MSG=$($GETTEXT 'ZENworks Imaging Service')
    INV_MSG=$($GETTEXT 'ZENworks Inventory Service')

    printf "  $WHERE\n"
    printf "   awsi = $AWSI_MSG\n" 
    printf "   img  = $IMG_MSG\n" 
    printf "   pxe  = $PXE_MSG\n" 
    printf "   rm   = $RM_MSG\n" 
    printf "   inv  = $INV_MSG\n" 
    printf "\n"

    exit $1
}

#-----------------------------------------------------------------------------
# Allow actions to be specified, or determined by program name...
#
ACTION=""
OPT_CLUSTER=""
OPT_COLD=""
OPT_SERVICE=""
while [ $# -gt 0 ] ;do
    case $1 in
        *cluster)
            OPT_CLUSTER="true"
            shift
            ;;
        *cold)
            OPT_COLD="true"
            shift
            ;;
        # *CLUSTER* Allow additional command line parameters specifing the service 
        *awsi)
            ZDM_DAEMON_NAMES=( \
            "$($GETTEXT 'ZENworks Auto Workstation Import/Removal')" \
            )
            ZDM_DAEMON_SCRIPTS=( \
            "novell-zdm-awsi" \ 
            )
            shift
            ;;
        # *CLUSTER* Allow additional command line parameters specifing the service 
        *pxe)
            ZDM_DAEMON_NAMES=( \
            "$($GETTEXT 'ZENworks PXE Services')" \
            )
            ZDM_DAEMON_SCRIPTS=( \
            "novell-proxydhcp novell-tftp novell-zmgprebootpolicy" \
            ) 
           shift
            ;;
        # *CLUSTER* Allow additional command line parameters specifing the service 
        *img)
            ZDM_DAEMON_NAMES=( \
            "$($GETTEXT 'ZENworks Imaging Service')" \
            )
            ZDM_DAEMON_SCRIPTS=( \
            "novell-zmgserv" \
            )
            shift
            ;;
        # *CLUSTER* Allow additional command line parameters specifing the service 
        *rm)
            ZDM_DAEMON_NAMES=( \
            "$($GETTEXT 'ZENworks Remote Management')" \
            )
            ZDM_DAEMON_SCRIPTS=( \
            "novell-zdm-wol" \
            )
            shift
            ;;
        # *CLUSTER* Allow additional command line parameters specifing the service 
        *inv)
            ZDM_DAEMON_NAMES=( \
            "$($GETTEXT 'ZENworks Inventory Service')" \
            )
            ZDM_DAEMON_SCRIPTS=( \
            "novell-zdm-sybase novell-zfs novell-zdm-inv" \ 
            )
            shift
            ;;
        *)
            ACTION="$1"
            shift
            ;;
    esac
done
[ -z "$ACTION" ] && ACTION=$PROG


MYUID=$(id -u)
COLS=$((15 - ${COLUMNS-80}))
case $ACTION in
    *restart)
            FMT="$($GETTEXT 'Restarting component %s')"
            FAILURE="$($GETTEXT 'Failed to restart %s')"
            CMD=restart
            ;;
    *stop)
            FMT="$($GETTEXT 'Shutting down component %s')"
            FAILURE="$($GETTEXT 'Failed to stop %s')"
            CMD=stop
            ;;
    *start)
            FMT="$($GETTEXT 'Starting %s')"
            FAILURE="$($GETTEXT 'Failed to start %s')"
            CMD=start
            ;;
    *status)
            MYUID=0
            CMD=status
            ;;
    *help)
            USAGE 0
            ;;
    *)
            USAGE 1
            ;;
esac

#-----------------------------------------------------------------------------
# Messages
#
FAILED=$($GETTEXT 'failed')
DONE=$($GETTEXT 'done')
NOT_INSTALLED=$($GETTEXT 'Component %s is not Installed')
RUNNING=$($GETTEXT 'Component %s is Running')
STOPPED=$($GETTEXT 'Component %s is Stopped')
ALREADY_RUNNING=$($GETTEXT 'Component %s is already Running')
ALREADY_STOPPED=$($GETTEXT 'Component %s is already Stopped')
ROOT_REQUIRED=$($GETTEXT 'You must be root to execute %s')
[ $MYUID -ne 0 ] && printf "$ROOT_REQUIRED\n" $PROG && exit 1

#-----------------------------------------------------------------------------
# *CLUSTER* ZDM_DAEMON_NAMES and ZDM_DAEMON_SCRIPTS are commented out because
#           they are already defined above.
# Service / Component configuration...
#
#
#ZDM_DAEMON_NAMES=( \
#    "$($GETTEXT 'ZENworks Auto Workstation Import/Removal')" \
#    "$($GETTEXT 'ZENworks PXE Services')" \
#    "$($GETTEXT 'ZENworks Imaging Service')" \
#    "$($GETTEXT 'ZENworks Remote Mangement')" \
#    "$($GETTEXT 'ZENworks Middle Tier Server')" \
#    "$($GETTEXT 'ZENworks Inventory Service')" \
#)
#ZDM_DAEMON_SCRIPTS=( \
#    "novell-zdm-awsi" \
#    "novell-proxydhcp novell-tftp novell-zmgprebootpolicy" \
#    "novell-zmgserv" \
#    "novell-zdm-wol" \
#    "+_novell-tomcat4 +apache2 novell-xregd novell-xsrvd" \
#    "+novell-zdm-sybase novell-zfs novell-zdm-inv"
#)

#if [ -n "$OPT_CLUSTER" ] ;then
#ZDM_DAEMON_SCRIPTS=( \
#    "novell-zdm-awsi" \
#    "novell-proxydhcp novell-tftp novell-zmgprebootpolicy" \
#    "novell-zmgserv" \
#    "novell-zdm-wol" \
#    "+_novell-tomcat4 +apache2 novell-xregd novell-xsrvd" \
#    "novell-zdm-sybase novell-zfs novell-zdm-inv"
#)
#fi

#-----------------------------------------------------------------------------
# Main 
#
MAIN()
{
I=0
while [ -n "${ZDM_DAEMON_NAMES[$I]}" ]
do
    echo ${ZDM_DAEMON_NAMES[$I]}
    echo ${ZDM_DAEMON_SCRIPTS[$I]}
    SCRIPTS=( ${ZDM_DAEMON_SCRIPTS[$I]} )

    #
    # Setup indeces for loop-- start in order, stop in reverse order...
    #
    MAX=0
    for SCRIPT in ${SCRIPTS[@]}
    do
        MAX=$(($MAX + 1))
    done
    if [ $CMD == stop ] ;then
        BEG=$(($MAX - 1))
        END=-1
        INC=-1
    else
        BEG=0
        END=$MAX
        INC=1
    fi    

    #
    # Process each script for this service...
    #
    J=$BEG
    while [ $J -ne $END ]
    do
        SCRIPT=${SCRIPTS[$J]}
        J=$(($J + $INC))

        #
        # SCRIPTS beginning w/ '+' should be started,
        # but never stopped... unless OPT_COLD specified...
        #
        if [[ $SCRIPT == \+* ]] ;then
            [ $CMD == start -o $CMD == status -o -n "$OPT_COLD" ] || continue
            SCRIPT=${SCRIPT#\+}
        fi

        #
        # Is this component even installed??
        #
        INSTALL_STATUS=""
        case $SCRIPT in
            _*)
                        INSTALL_STATUS=$($SCRIPT IS_INSTALLED ; echo $?)
                        ;;
            */*)
                        ;;
            *)
                        SCRIPT="/etc/init.d/$SCRIPT"
                        ;;
        esac

        [ -z "$INSTALL_STATUS" ] && INSTALL_STATUS=$([ -x $SCRIPT ] ; echo $?)

        if [ "$INSTALL_STATUS" -ne 0 ] ;then
            printf "\t$NOT_INSTALLED\n" ${SCRIPT##*/}
            continue
        fi

        #
        # Is this component running?
        #
        $SCRIPT status >&/dev/null; STATUS=$?
        if [ $CMD == status ] ;then
            if [ $STATUS -eq 0 ] ;then
                printf "\t$RUNNING\n" ${SCRIPT##*/}
            else
                printf "\t$STOPPED\n" ${SCRIPT##*/}
            fi
            continue
        fi

        [ $STATUS -eq 0 -a $CMD == start ] &&
            printf "\t$ALREADY_RUNNING\n" ${SCRIPT##*/} &&
            continue
        [ $STATUS -ne 0 -a $CMD == stop ] &&
            printf "\t$ALREADY_STOPPED\n" ${SCRIPT##*/} &&
            continue

        #
        # Execute command
        #
        LABEL=$(printf "$FMT" ${SCRIPT##*/})
        printf "\t%${COLS}s" "$LABEL"
        $SCRIPT $CMD >&/dev/null
        if [ $? -ne 0 ] ;then
            printf "$FAILED\n"
            printf "** $FAILURE **\n" "${ZDM_DAEMON_NAMES[$I]}"
            break
        fi
        printf "$DONE\n"
    done
    
    I=$(($I + 1))
done
}

#-----------------------------------------------------------------------------
# _novell-zimgserv pseudo script for imaging services... (loads in eDir...)
#
_novell-zimgserv()
{
    NDSTRACE=/usr/bin/ndstrace
    [ -x ${NDSTRACE} ] || NDSTRACE=/opt/novell/eDirectory/bin/ndstrace
    [ -x ${NDSTRACE} ] || NDSTRACE=ndstrace
    case $1 in
        IS_INSTALLED)
                ([ -x /etc/init.d/ndsd ] &&
                ${NDSTRACE} -c modules | grep -qi zimgserv) >&/dev/null
                ;;
        stop)
                (${NDSTRACE} -c modules | grep -qi zimgserv.*not.loaded ||
                ${NDSTRACE} -c "unload zimgserv") >&/dev/null
                ;;
        start)
                (/etc/init.d/ndsd status || /etc/init.d/ndsd start) >&/dev/null
                if [ $? -eq 0 ] ;then
                    (${NDSTRACE} -c modules | grep -qi zimgserv.*running ||
                    ${NDSTRACE} -c "load zimgserv") >&/dev/null
                else
                    false
                fi
                ;;
        restart)
                _novell-zimgserv stop && _novell-zimgserv start
                ;;
        status)
                (/etc/init.d/ndsd status >&/dev/null &&
                ${NDSTRACE} -c modules | grep -qi zimgserv.*running) >&/dev/null
                ;;
    esac
}

#-----------------------------------------------------------------------------
# _novell-tomcat4 pseudo script for midtier services... (no status in orig...)
#
_novell-tomcat4()
{
    case $1 in
        IS_INSTALLED)
                [ -x /etc/init.d/novell-tomcat4 ]
                ;;
        status)
                #
                # this is a modified detection algorithm
                # originally taken from /etc/init.d/novell-tomcat4
                #
                if [ -f /var/run/novell-tomcat4.pid ] ;then
                    CAT_PID=$(cat /var/run/novell-tomcat4.pid)
                    [ -f /proc/$CAT_PID/cmdline ] &&
                        grep -ic catalina /proc/$CAT_PID/cmdline && return
                fi
                false
                ;;
        *)      
                /etc/init.d/novell-tomcat4 $1
                ;;
    esac
}

MAIN

If you have any questions you may contact Giovanni at Giovanni.Coa@edp4you.it


Novell Cool Solutions (corporate web communities) are produced by WebWise Solutions. www.webwiseone.com

© 2014 Novell