The magical, mystical FOG post download script
-
Part 3 Code snippets
This first code snippet will connect our post install script to the target computer’s hard drive. This connection may or may not have been made by a previous FOG script. If the connection has already been setup we’ll just error gracefully and continue on with the execution. This is a good programming style in that you need to do a task, perform that task as if no other script has run on this target computer, go through the steps to set it up and then tare it down before you script is over.
- Connecting to the local hard drive.
To connect our post install script to the target computers local hard drive requires a little understand about the deployed operating system and the deployed os hard drive layout (partitions). For windows vista and later there will be at least 2 partitions on the target hard drive. The first partition (1) is the boot partition that contains the windows startup code. The second partition on the target’s hard drive is the or windows partition. If there is a drive in the target image then there will be a 3rd partition, and so on. For our script this second partition will be the target of our attention. To allow our script to interact with the windows partition on our target computer we will first need to create a mount (or connection) point in FOS and then attach the second partition of the first disk to that mount point. We’ll use the following code snippet.
To make our code flexible for other operating systems I’m going to assign the partition layout to a variable. For other disk layouts we would just update the variable, but maintain a consistent code after that by referencing the variable. In this caseosdiskpart
will represent the disk and partition we are interested in.
# windows 7 osdiskpart="/dev/sda2"; # create a directory to hang the Windows C: drive partition on in FOS # the 2>/dev/null below just redirects any errors from the mkdir command to null. i.e. # if the directory already exists, I don't want to know about it, just hide the error. Understand # that I could have tested if the directory already existed, but that takes more programming steps # I'm just going to try to create it and ignore the error if it already exists. mkdir /ntfs 2>/dev/null # This next command connects the hard drive partition to the directory we just created. You will see the # 2>/tmp/mntfail at the end of the mount command. In this case if the connection fails we want to write # the output to a text file we can review and test to see if it exists. If the file exists then something went # wrong with the connection to the hard disk partition. mount.ntfs-3g "${osdiskpart}" /ntfs 2>/tmp/mntfail # this last bit of magic checks to see if the mntfail file exists and if it does then it means the mount # failed so there is no need to continue on with the script. mntRet="$?"; if [ ! "$mntRet" = "0" ]; then echo "Failed to mount C:"; # display what happened cat /tmp/mntfail; # give the reader a chance to see what the error was sleep 12; # terminate the post install script exit 1; fi
- After the connection to the hard drive is established, your script can make alterations to the Windows disk. You can update configuration files, interact with the registry, delete files, or copy files to and from the FOG server. In our case we want to update some settings in the MS Windows unattend.xml file.
Note: the unattend.xml file is only used if the reference image was sysprep'd before image capture. Since we were following the recommend rules and sysprep'd the image before capture this is the current state our reference image
We have to remember that MS Windows is not case specific, but our post install script is running on a FOS linux environment which IS case important. Remember this as you write your post install scripts /ntfs/windows is not the same as /ntfs/Windows. - For the next part lets assign the path of our unattent.xml file to a variable so its easier to use in with our script.
# Unattend.xml path (note the case specifics in the file name and path) unattendfile="/ntfs/Windows/Panther/unattend.xml";
- With the $unatendfile variable set we can use it to update… lets say the computer name stored in the unattend.xml file with the computer name defined in fog. The fog developers have already copied the target computer name into the $hostname variable for us so to update the computer name in the unattend file we just need to do some sed (linux application) “regular expression” magic. I’m not going to explain the magic that is going on in this script. If you are interested look up sed and “regular expression” to decode what this command is really doing.
sed -i -e "s#<ComputerName>\([^<][^<]*\)</ComputerName>#<ComputerName>$hostname</ComputerName>#gi" $unatendfile
- Using the same concepts we can update other unattend.xml elements like:
timezone
sed -i -e "s#<TimeZone>\([^<][^<]*\)</TimeZone>#<TimeZone>$timezone</TimeZone>#gi" $unattendfile
computer ou
sed -i -e "s#<MachineObjectOU>\([^<][^<]*\)</MachineObjectOU>#<MachineObjectOU>${oupath}</MachineObjectOU>#gi" $unattendfile
< insert keyboard>
< insert system language>
6. Lets say we need to determine what type of computer is the target computer (i.e. desktop, laptop. ?). We can query the SMBIOS using dmidecode to extract we are installing the chassis type using this code snippet.chassis=`dmidecode -s chassis-type`; chassis="${chassis%"${chassis##*[![:space:]]}"}"; #Remove training space chassis="${chassis,,}"; # Convert string to lower if [ "$chassis" = "laptop" ]; then chtype="Portable"; elif [ "$chassis" = "tablet" ]; then chtype="Tablet"; else # We'll default every other chassis type to desktop chtype="Desktop"; fi
- Connecting to the local hard drive.
-
Part 2 FOG Post install script.
As I noted above, the post install script is called by the FOS target engine just after the image has been copied to the target host computer and before the house keeping and recording steps are performed. (Hint, don’t force a reboot in your post install script or the house keeping and recording steps will not be performed). There is a call to execute the /images/postdownloadscripts/fog.postdownload script. You should hook your custom post install scripts into this bash script file.
The bash shell environment (created in 1988) is a mix of operating system interface (command processor) and programming environment. In windows terms, think of it as a great, great, grandfather to what MS PowerShell will be one day. If you are a PowerShell maven, a lot of the PS look and feel came from this era of command processors, so programming in bash is just a syntax change, the program flow is very similar. The bash shell script can call linux applications, create run time variables, and produce output that can be written directly to disk storage or filtered through another linux application before being written to disk (we are going to take advantage of this functionality in our fog post install scripts. I’m not going into the details of bash programming. The environment has been around for almost 30 years, there is plenty of examples on the internet to follow. I will go into the specifics of what we need to do in bash to connect to the target computer’s hard drive and query info about the target computer. In our case we can either query the computer directly to find out key elements of its design or since FOG r8050 we can make a call back to FOG to retrieve things that FOG knows about the target computer.
For our example post install script we are going to create it next to the existing fog.postinstall script. I do recommend that you compartmentalize your fog post install scripts based on their task and not just have a single monolithic (i.e. big a$$) script. Its much easier to maintain smaller and specific code elements. I also recommend that you write your own scripts in your own files and not just use the fog.postdownload script for your scripts. The nature of that FOG owned script may change over time. I would not want changes to the fog.postdownload script to erase your content.
For our example fog post install script, I’m calling it fog.postexamp and will place it in the /images/postdownloadscripts directory. For clarity you can call this script anything you want, I’ve just kept with the fog naming convention of “fog.<action>”.
For this example I'm running as root on centos, for other linux distros you will probably need sudo. For this thread assume all commands have a hidden sudo on front
- Lets begin to create our script
touch /images/postdownloadscripts/fog.postexamp
- We’ll need to make it runable
chmod 755 /images/postdownloadscripts/fog.postexamp
- With your favorite text editor, edit the fog.postexamp script.
- For every bash script you must insert this mandatory line on the very first line of your script. There can be no blank lines above or spaces to the left of this text. So insert this on the very first line of your bash script.
#!/bin/bash
and press enter. This line tells the command processor to use bash to process this script. - Now I recommend that you enter several lines of comments to describe what this script does, who created it, and any other relevant information. Comment lines for bash begin with a pound symbol (a hash tag for the millennials) and then the remainder of the line is text to the end of the line.
- We are going to take advantage of one of the fog developers scripts for several interesting functions later so lets include that script in our script. After your comments enter the following line
. /usr/share/fog/lib/funcs.sh
(note: again don’t forget that lonely dot plus a space before the path to the script).
Comment: As I mentioned before the fog post install scripts execute on the FOS client, so the /usr/share/fog/lib/funcs.sh is not on the FOG server, but on the FOS virtual hard drive (a.k.a the inits). So if you are nosy you won’t find this file if you search the path on the fog server.
- At this point your fog.postexamp script should look something like this one
#!/bin/bash # # This is an example script that will show you the recommend way to create a # FOG post install script. There are many ways you can go about this, some will be better than # others. # # Author: George1421 # Version: 1.0 # Date: 20160611 # . /usr/share/fog/lib/funcs.sh
- If you stop right here you have a complete fog post install script. Admittedly it doesn’t do anything special, but you DO have a complete script.
- The rest of the script will be up to you to decide what you want your post install script to do. I’ll include more code fragments that you can assemble into your own script in Part 3
- Lets begin to create our script
-
#wiki worthy
-
@george1421 said in The magical, mystical FOG post download script:
hostbuilding # ??
This is an old field in the
hosts
table left over from much older versions of fog. As far as I can tell, it is not used for anything anymore. -
@george1421 Update to part 5 Access FOG host data
if [[ ! -z $mac ]]; then curl -A "" -Lkso /tmp/hinfo.sh ${web}/service/hostinfo.php -d "mac=$mac" if [[ -f /tmp/hinfo.sh ]]; then . /tmp/hinfo.sh fi fi
-
@dburk Great catch, thank you for the update. I’m not sure how I missed that one but great job. I’ll get my post updated so that it works correctly.
-
I am confused about the actual syntax of this post download script.
In the sample script on the FOG server, it says:
“# syntax of the post download scripts are”
"#. ${postdownpath}<SCRIPTNAME>(assuming the script is called (without quotes) “mypostdlscript.sh”, and it is in “/images/postinstall/” directory)
Should I be typing (without quotes) “. ${postdownpath}mypostdlscript.sh”
or should I be typing it as (again without quotes) “. /images/postinstall/mypostdlscript.sh”?
Can you explain what the ${postdownpath} means? -
@enswafford said in The magical, mystical FOG post download script:
${postdownpath}
This is a variable in bash scripts. Should probably be set to
/images/postdownloadscripts/
-
@enswafford said in The magical, mystical FOG post download script:
“. ${postdownpath}mypostdlscript.sh”
First of all sebasian is spot on with this explanation.To break this post download script a bit more. The script is actually a bash shell script. Its akin to a DOS batch file, with 1000’s more capability. The bash variable is called
postdownpath
so the bash shell interpreter understands its a variable you prefix the variable name with a dollar sign. The interpreter can still get a bit confused at times so you wrap the variable with curly braces so it knows fore sure there is a variable call ${postdownpath} . The FOG server populates that variable before the post install script runs with the proper value so you don’t need to know where the post install scripts are run from.So the command is this
“. ${postdownpath}mypostdlscript.sh”
The preceding dot is shorthand way of saying run themypostdlscript.sh
in this context so all of my populated variables are shared with this new bash script. Its a little complicated to explain but that is what that entire command will do. So if you set a variable in the current script, that variable will be available to any subsequent bash scripts you create. -
@george1421 I need to add,
the preceeding
.
is NOT just a way of saying run, it’s also a shorthand way of sourcing the file, the same as:source mypostdlscript.sh
Basically, source means to bring the file in, similar to requiring other files in order to access different variables/functions that you may want separated from the purpose of the main running script.
-
@george1421 Looking at the code, say if I wanted to extract the hostimageid and assign it to $imageid in a while loop, would the following be correct :
while [[ $imageid -le 10 ]]; do if [[ -z "imageid"]]; then if [[ ! -z $mac ]]; then curl -A "" -Lkso /tmp/hinfo.sh ${web}/fog/service/hinfo.php -d "mac=$mac&hostimageid=$imageid" if [[ -f /tmp/hinfo.sh ]]; then . /tmp/hinfo.sh fi echo "Please wait" sleep 60 fi done
This should in theory run the while loop until a value is given to the $imageid
-
@zaboxmaster said in The magical, mystical FOG post download script:
curl -A “” -Lkso /tmp/hinfo.sh ${web}/fog/service/hinfo.php -d “mac=$mac&hostimageid=$imageid”
That call returns all variables not just the one you pass to it. Only the mac address value is used and understood.
-
@zaboxmaster I’ve updated your code into a code block so you can see a bit cleaner on what’s happening.
First, the loop you’re providing will not work. This is because it’s missing a fi (for the
if [[ -z "imageid" ]]
line).Second: Why is the code looking if the value is less than or equal to 10? Why do you need to loop this code at all?
From what I understand of your needs, you want to get the image ID for a host if the host has no image id set. This makes 0 sense. In what scenario would you be able to get an image ID for a host that has no assigned image ID? This is circular referencing as no matter what happens, the host isn’t going to have an image id associated to it. So it will never be able to complete the loop.
You seem to be rebuilding the cart before you have built it. (I don’t know if the metaphor makes sense here.)
Too me, what you’re looking for seems rather strange. You would never be able to image a host if you don’t have an image assigned (and did not select an image during pxe boot.)
If this is during registration, what’s the point in this?
- The host doesn’t exist, so calling hinfo.sh will gain you nothing.
- You have to be in front of the host when registering (unless you are using quick reg - in which case why not set the quick reg image id for quick registration rather than re-invent the wheel) so why try an automate this part?
- Why all the erroneous checking in the first place? First, your while loop is extremely limiting. You have it set to check if the imageid is less than or equal to 10. What about image id 1? Why is this a valid check on anything?
- In side the while loop you have
if [[ -z "$imageid" ]]; then
Why not just make the while loopwhile [[ -z $imageid && $imageid -gt 0 ]]; do
- In what scenario would you ever be able to do anything on a machine with the mac variable is not set (you should not need to check this variable as FOS kind of relies on it in the first place)?
- Why are you waiting for a minute to do anything?
If there’s a valid reasoning for this I would redo the script to run:
while [[ -z $imageid && $imageid -gt 0 ]]; do curl -A "" -Lkso /tmp/hinfo.sh ${web}/fog/service/hinfo.php -d "mac=$mac" if [[ -f /tmp/hinfo.sh ]]; then . /tmp/hinfo.sh fi echo "Please wait" sleep 60 done
-
@Tom-Elliott Thank you for your input. I realize that i have made a mistake in the code. I am new to bash and fog in general.
The idea is to have a while loop running until an image has been assigned. Or a sort of pause before it continues. The reason being that this is being done remotely and I would be assigning the correct image to the host. I am not psychically in front of the computer. The hosts users would only select that they want an image to be deployed and not select an image to deploy.
Hope that makes sense.
So what I guess I was looking for and I do realize that this is n the wrong thread is a way inside a while loop to see if an image has been assigned before continuing on with the deployment. BTW I have modified the fog.man.reg to go straight to the fog.download and the end of the registration.
-
-
-
-
-
-
-
-
-