Deployment Solution

 View Only

Using NS Package Servers as DS Local Image Repositories with Linux Automation 

Sep 07, 2007 01:30 PM

Here's a clever way to leverage the NS database to retrieve a list of possible DS image repositories. The included script also includes a ping check to make sure you use the file share with lowest average ping, like Altiris Software Delivery.

The eXpress share

First off create a software package, "eXpress", for the eXpress share (I guess using the dslibrary package works fine also). This package needs no program, it should only contain the OS image files and required drivers.

The software cache folder of this "eXpress" package needs to be shared as "eXpress" on all package servers.

Retrieve the assigned package servers

A software delivery agent gets it's package servers from the "http://NS/altiris/NS/Agent/GetPackageInfo.aspx" url. It takes an XML string as input, and by accessing this URL with a string containg your IP address and the package you are looking for, a XML response is recieved. (KB article here.)

Now, how to access this URL from the linux automation?

The simplest way seems to be using "wget". This application is not included in the linux automation, but you can get it up and running by copying the wget binary and required libs to the DS express share, and reload the lib cache.

The CentOS 4.5 "wget" require the following libs, but you can get them and the wget binary from almost any Linux distribution:

  • libc.so.6
  • libcrypto.so.4
  • libdl.so.2
  • libgssapi_krb5.so.2
  • libk5crypto.so.3
  • libkrb5.so.3
  • libpthread.so.0
  • libresolv.so.2
  • librt.so.1
  • libssl.so.4
  • libz.so.1

Put them in a directory together with the wget binary on your DS (e.g Script\wget).

In the same wget directory on the DS create a file "url.txt". This will hold the XML string that is going to be sent to GetPackageInfo.aspx.

Since this string is a XML string that is going to be sent over http it does not look pretty (but it really doesn't matter):

http://sespmm45/altiris/NS/Agent/GetPackageInfo.aspx?xml=%3Crequest%20resource=%22%7B549dcf61-6da0-4077-906d-f3fab8c49f62%7D%22%20version=%221%22%20type=%22codebases%22%20compress=%220%22%20totalTime=%220%22%3E%0A%3Cpackages%3E%0A%09%3Cpackage%20guid=%22%7Ba521f923-5044-4bd6-92c6-d653ab0373d4%7D%22%2F%3E%0A%3C%2Fpackages%3E%0A%3Caddresses%3E%0A%09%3Caddress%20ip=%22[ipaddress]%22%2F%3E%0A%3C%2Faddresses%3E%0A%3C%2Frequest%3E%0A

The first variable highlighted should be a computer resource guid and we set it to the NS guid (as we can be certain this guid will always exist).

What's interesting to us is the package guid variable, and this is set to the guid of the "eXpress" software package, containing the OS image(s) and needed drivers. This can be any package guid but it it nice to know that the "eXpress" package is present and in sync on the package server.

The other variable is replaced with a "place holder" [ipaddress], and this has to be replaced with the current ip of the client. Using bash this is no problem!

The script

Here is an example script to mount an "eXpress" share from a local package server. Save it as \\ds\eXpress\Script\MountLocalShare.sh.

#!/bin/bash
#MountLocalShare.sh
export PATH=$PATH:/opt/altiris/deployment/adlagent:/mnt/ds/rdeploy/Linux

#Get ip address of eth0:
IPADDR=`ifconfig eth0 | grep Mask | awk '{split($2,ipaddr,":");printf ipaddr[2] }'`
echo My ip-address is $IPADDR >> /dev/tty1
logevent -c:0 -l:0 -ss:"Connecting with $IPADDR"

#wget path
WGET_PATH=/mnt/ds/Script/wget
if [ -d $WGET_PATH ]; then
  #Add the wget lib path to ls.so.conf and recreate the cache of shared libs
  echo $WGET_PATH >> /etc/ld.so.conf
  echo Running ldconfig >> /dev/tty1
  ldconfig
else
  echo Path to wget files not found! Aborting... >> /dev/tty1
  logevent -c:110 -l:3 -ss:"Path to wget files not found!"
  exit 110
fi;

echo Retrieving a list of possible package servers... >> /dev/tty1
if [ -e $WGET_PATH/url.txt ]; then
  urlstring=$(cat $WGET_PATH/url.txt)
  #Find the string "[ipaddress]" and replace it with IPADDR
  echo "${urlstring/\[ipaddress\]/$IPADDR}" > /url.txt
  $WGET_PATH/wget -i /url.txt -O /reply.txt
  #grep for line containing "<codebase url" and using "/" as field separator print the third column. Pipe to cut and remove possible ":" and port number (if it's an http url). Also we don't want to fetch images from ns
  PS=($(grep "<codebase url" /reply.txt  | grep -E -i -v "ns" | awk -F/ '{print $3}' | cut -d: -f1))
  if [ -n "$PS" ]; then
    echo "Returned package server(s): ${PS[@]}" >> /dev/tty1
    logevent -c:0 -l:0 -ss:"Returned package server(s): ${PS[@]}"
  else
    echo "No package servers returned!" >> /dev/tty1
    logevent -c:111 -l:3 -ss:"No package servers returned!"
    exit 111
  fi;
else
  logevent -c:112 -l:3 -ss:"Can't find file url.txt"
  exit 112
fi;

if [ "${#PS[@]}" -eq 1 ]; then #Only one package server returned
  pkgsrv=$PS
  echo "Testing: $pkgsrv" >> /dev/tty1
  logevent -c:0 -l:0 -ss:"Testing: $pkgsrv"
  if ping -I $IPADDR -c3 $pkgsrv 2>/dev/null; then
    echo "  $pkgsrv: Ping check ok" >> /dev/tty1
    logevent -c:0 -l:0 -ss:"$pkgsrv: Ping check ok"
    SELECTED_PS=$pkgsrv
  else
    echo "  No reply from $pkgsrv!" >> /dev/tty1
    logevent -c:0 -l:0 -ss:"No reply from $pkgsrv!"
  fi;
elif [ "${#PS[@]}" -gt 1 ]; then #More than one package server in the array
  LOW_AVG=99999
  echo Trying to determine the closest package server... >> /dev/tty1
  for pkgsrv in "${PS[@]}"; do
    echo "Testing: $pkgsrv" >> /dev/tty1
    if ping -I $IPADDR -c3 $pkgsrv 2>/dev/null; then
      echo "  $pkgsrv: Ping check ok" >> /dev/tty1
      logevent -c:0 -l:0 -ss:"$pkgsrv: Ping check ok"
      #Get the average response time from five pings:
      avgping=$(ping -q -c5 $pkgsrv | grep = | awk '{print $4}' | cut -d / -f 2)
      echo "  $pkgsrv: Average response time: $avgping ms" >> /dev/tty1
      if [ $(echo "$avgping < $LOW_AVG" | bc) -eq 1 ]; then #This is the lowest avg so far...
        echo "  $pkgsrv: New low avg: $avgping ms" >> /dev/tty1
        LOW_AVG=$avgping
        SELECTED_PS=$pkgsrv
      fi;
    else
      echo "  No reply from $pkgsrv!" >> /dev/tty1
      logevent -c:0 -l:0 -ss:"No reply from $pkgsrv!"
    fi;
  done
fi;

if [ -z "$SELECTED_PS" ]; then #SELECTED_PS variable is not initialized... No PS has responded to the ping request
  logevent -c:42 -l:3 -ss:"None of the returned package servers are online!"
  exit 42
else
  echo Selected package server: $SELECTED_PS >> /dev/tty1
  logevent -c:0 -l:0 -ss:"Selected package server: $SELECTED_PS"
  cd /mnt
  mkdir ps
  RETVAL=$?

  case $RETVAL in
    1)  logevent -c:1 -l:0 -ss:"mkdir: /mnt/ps already exists."
      umount /mnt/ps
      ;;
    0)  logevent -c:0 -l:0 -ss:"mkdir: /mnt/ps created."
      ;;
    *)  logevent -c:$RETVAL -l:3 -ss:"mkdir: Error creating mount point /mnt/ps"
      exit $RETVAL
      ;;
  esac

  logevent -c:0 -l:0 -ss:"Connecting with $IPADDR; Using $SELECTED_PS for image deployment."
  echo Using $SELECTED_PS for image deployment. >> /dev/tty1
  asmbmount -d DOMAIN -f /DSUSER.pwl //$SELECTED_PS/eXpress /mnt/ps
  RETVAL=$?
  if [ $RETVAL -ne 0 ]; then
    logevent -c:$RETVAL -l:3 -ss:"Error mounting $SELECTED_PS/eXpress"
    exit $RETVAL
  fi;
fi;
#EOF
You will need to replace "ns" in the following line with you Notification server name (Leave the qoutes!)
PS=($(grep "<codebase url" /reply.txt  | grep -E -i -v "ns" | awk -F/ '{print $3}' | cut -d: -f1))

And you will also need to replace DOMAIN and DSUSER in the following line of the script:

asmbmount -d DOMAIN -f /DSUSER.pwl //$SELECTED_PS/eXpress /mnt/ps

Now, to fetch a disk image from your closest package server all you need to do is to create a job containing this script and a disk image task.

The DS Job

Run the "\\ds\eXpress\Script\MountLocalShare.sh" script from file

followed by a "Distribute Disk Image..." You also need to check the "Image is stored locally on the client".

I don't know how popular Linux is as an Altiris automation environment, but we have used it to deploy Windows XP since it first became available in DS.

This script could probably be ported to vbscript and used with the WinPE automation also!

Statistics
0 Favorited
0 Views
0 Files
0 Shares
0 Downloads

Tags and Keywords

Comments

Aug 20, 2008 03:46 PM

You can do the same or very similar function in WinPE. We have a "GetPackageServer.vbs" script that runs, gets the local/closest Package Server and map a drive to it. From that point, the local package server is always used for the jobs. Instead of ping however, we rely on the NS Site and Subnet configuration to properly map the client's subnet to the NS site/Package Server they should use.

Aug 19, 2008 05:08 PM

Good point. We have under a dozen remote offices and I am tired of creating individual PXE images already. I'm going to take a second look at this script.

Aug 19, 2008 03:48 AM

With our 70 something branch offices that would mean maintaining a whole lot of pxe images. What if you want to make a change to the pxe image?

Aug 18, 2008 04:52 PM

We redirect the shared Linux PXE image at each site to a local PXE image that is already set to mount the image share on that site's package server to /mnt/whatever.

Sep 19, 2007 11:42 AM

I use Linux PreBoot Almost exclusively as my preboot operating system. I have set up something very similar to this however I call the script from rc.local and that then runs on OS boot. When the script runs it grabs a listing of Subnets, to Primary Package Server and Secondary Package Server. So the mount points would be

  • /mnt/ds

  • /mnt/ps

  • /mnt/ps2


If any of my imaging jobs fail pointing to /mnt/ps then I auto-rerun the job (based on return codes) pointed at the /mnt/ps2.
Good Stuff!

Related Entries and Links

No Related Resource entered.