Expose FOG host and image properties to post install scripts


  • Moderator

    I ran into a situation where I need to have access to some of the host, image, location specific information during post deployment script execution. I know what and where things need to be done, but my hacking attempts have failed miserably because I don’t understand the fog data structure and php well enough.

    From my testing this is what I can outline.

    1. Create a php page that takes the target computer’s MAC address and return a properly formated bash script page that sets the internal fog database value to a bash variable. This could be an actual script that is executed or a list that is parsed and exported to bash environment variables.
    2. The output of that php page will be saved to /tmp
    3. This would be an example command that needs to be injected into the fog.download script
      wget -q -O /tmp/hinfo.txt "http://${web}service/hostinfo.php?mac=$mac" &>/dev/null
    4. In the fog.download script the property info call could be injected here:
    if [ -f "/images/postdownloadscripts/fog.postdownload" ]; then
        wget -q -O /tmp/hinfo.txt "http://${web}service/hostinfo.php?mac=$mac" &>/dev/null
        # I still need to work out how to import the hinfo.txt file into bash variables
        # if /tmp/hinfo.txt is a bash script will have to do a chmod to make it executable
        postdownpath="/images/postdownloadscripts/";
        . ${postdownpath}fog.postdownload;
    fi
    
    1. The hostinfo.php would export the following FOG variables.
      Image
      ->Name
      ->Operating System
      ->Image Path
      Storage Node
      ->Name
      Hosts
      ->Name
      ->Product key
      ->Location
      ->Domain name
      ->OU
    2. Once these are exported to bash variables then they would be available to any subsequent scripts called by fog.postdownload script. I can pick up the rest of the host details from dmidecode so pulling inventory data is not necessary but may be beneficial.

  • Moderator

    @Tom-Elliott Thank you


  • Senior Developer

    I’ve added the hostinfo.php script, though in a much different fashion. As I stated in chat and on the comments of the pull request, I have not added the setHostname due to security concerns. That all said, the information is now exposed as you requested.


  • Senior Developer

    https://github.com/FOGProject/fogproject/pull/102#issuecomment-223262772

    I’ve added this just to voice my concerns about one aspect of this. Of course if you want to still have setting the hostname, you’re more than welcome to keep it.


  • Moderator

    LET ME SAY THIS RIGHT OF THE BAT, I have not used this in my test environment, only on my dev box. So it may work well for production or it may fall flat. (it shouldn't because the code is solid). After my holiday I'll test it completely in my test environment before moving it to production.

    I think I was able to create a solution for this issue. I attempted to do a git fork / pull request but I’m not sure it worked so for the sake of documentation I’ll update what I was able to do there.

    First I created two new FOG Server pages. One is to pull the system variables I need into the fog postdownload bash scripts. The second page allows me to update/change a registered fog target computer name from a postdownload script. Just some background on this, my target machine names are all calculated based on the computer serial number and a OU prefix. Currently I’m using an unused field in FOG (Other1) to hold this OU prefix. So to properly and automatically name the target computer I need to pick up the serial number from smbios and combine it with the value from the other1 field in the host information. Below is what I’ve worked out to extend FOG to what I need.

    Create the following file: /var/www/html/fog/service/sethostname.php

    <?php
    require_once('../commons/base.inc.php');
    FOGCore::getClass('SetHostName');
    

    Create the following file: /var/www/html/fog/service/hostinfo.php

    <?php
    require_once('../commons/base.inc.php');
    FOGCore::getClass('Hostinfo');
    

    Create the following class file: /var/www/html/fog/lib/fog/sethostname.class.php

    <?php
    class SetHostName extends FOGBase {
        protected $macSimple;
        protected $newName;
        protected $oldName;
    
        public function __construct($check = false) {
            parent::__construct();
    
            self::stripAndDecode($_REQUEST);
            $this->macSimple = strtolower(str_replace(array(':','-'),':',substr($_REQUEST['mac'],0,20)));
            $this->newName = substr(trim($_REQUEST['newname']," \t\n\r\0"),0,20);
            $this->oldName = substr(trim($_REQUEST['oldname']," \t\n\r\0"),0,20);
    
            ob_start();
            header('Content-Type: text/plain');
            header('Connection: close');
    
            if ((strlen($this->newName) > 3) & (strlen($this->oldName) > 0)) {
                $query = sprintf("UPDATE hosts JOIN hostMAC ON (hostMAC.hmHostID = hosts.hostID) SET hostName='%s' WHERE ( (hostMAC.hmMAC='%s') AND (hostName LIKE '%s') );", $this->newName, $this->macSimple, $this->oldName);
    
                self::$DB->query($query);
                echo "OK";
            } else {
                echo "Fail";
            }
            flush();
            ob_flush();
            ob_end_flush();
        }
    }
    

    Create the following class file: /var/www/html/fog/lib/fog/hostinfo.class.php

    <?php
    class HostInfo extends FOGBase {
        protected $macSimple;
        protected $repFields = array(
            'hostName' => 'hostname',
            'hostDesc' => 'hostdesc',
            'imageOSID' => 'imageosid',
            'imagePath' => 'imagepath',
            'hostUseAD' => 'hostusead',
            'hostADDomain' => 'hostaddomain',
            'hostADOU' => 'hostadou',
            'hostProductKey' => 'hostproductkey',
            'iPrimaryUser' => 'primaryuser',
            'iOtherTag' => 'othertag',
            'iOtherTag1' => 'othertag1',
            'lName' => 'location',
            'iSysman' => 'sysman',
            'iSysproduct' => 'sysproduct',
            'iSysserial' => 'sysserial',
            'iMbman' => 'mbman',
            'iMbserial' => 'mbserial',
            'iMbasset' => 'mbasset',
            'iMbproductname' => 'mbproductname',
            'iCaseman' => 'caseman',
            'iCaseserial' => 'caseserial',
            'iCaseasset' => 'caseasset',
        );
    
        public function __construct($check = false) {
            parent::__construct();
    
            self::stripAndDecode($_REQUEST);
            $this->macSimple = strtolower(str_replace(array(':','-'),':',substr($_REQUEST['mac'],0,20)));
    
            $query = sprintf("SELECT hostName,hostDesc,imageOSID,imagePath,hostUseAD,hostADDomain,hostADOU,hostProductKey,iPrimaryUser,iOtherTag,iOtherTag1,lName,iSysman,iSysproduct,iSysserial,iMbman,iMbserial,iMbasset,iMbproductname,iCaseman,iCaseserial,iCaseasset FROM (((hostMAC INNER JOIN (hosts LEFT JOIN images ON hosts.hostImage = images.imageID) ON hostMAC.hmHostID = hosts.hostID) LEFT JOIN inventory ON hosts.hostID = inventory.iHostID) LEFT JOIN locationAssoc ON hosts.hostID = locationAssoc.laHostID) LEFT JOIN location ON locationAssoc.laLocationID = location.lID WHERE (hostMAC.hmMAC='%s');", $this->macSimple);
    
            $tmp = (array)self::$DB->query($query)->fetch('','fetch_all')->get();
    
            ob_start();
            header('Content-Type: text/plain');
            header('Connection: close');
    
            foreach ((array)$tmp AS $i => &$DataRow) {
                foreach ((array)$DataRow AS $j => &$DataField) {
                    echo  "export " . $this->repFields[$j] . "=\"" . $DataField . "\"\n";
                    unset($DataField);
                }
                unset($DataRow);
            };
            flush();
            ob_flush();
            ob_end_flush();
        }
    }
    

    And finally the post install bits

    Edit /images/postdownloadscripts/fog.postdownload and insert the following command before your custom post install script

    . ${postdownpath}fog.hostinfo
    

    Create the following file: /images/postdownloadscripts/fog.hostinfo

    #!/bin/bash
    
      . /usr/share/fog/lib/funcs.sh;
      wget -q -O /tmp/hinfo.txt "http://<fog_server_IP>/fog/service/hostinfo.php?mac=$mac"
      . /tmp/hinfo.txt
      rm -f /tmp/hinfo.txt
    

    If everything works as expected you should now have access to the following bash variables in your post install script

    $hostname == name of the host (should overwrite existing $hostname)
    $hostdesc == Description of host
    $imageosid == Operating System ID (should be the same as $osid)
    $imagepath == The root path of the image(should also be the image name)
    $hostusead == 1 or 0 to add host to AD
    $hostaddomain == host domain name
    $hostadou == host target ou
    $hostproductkey == host product key
    $primaryuser == Value from Primary User field
    $othertag == Value from OtherTag field
    $othertag1 == Value from OtherTag1 field
    $location == Location Name from location plugin
    $sysman == System Manufacturer from smbios
    $sysproduct == System Product Name from smbios (from full registration)
    $sysserial == System Serial Number from smbios (from full registration)
    $mbman == Motherboard Manufacturer from smbios (from full registration)
    $mbserial == Motherboard Serial Number from smbios (from full registration)
    $mbasset == Motherboard Asset tag from smbios (from full registration)
    $mbproductname == Motherboard Product Name from smbios (from full registration)
    $caseman == Case Manufacturer from smbios (from full registration)
    $caseserial == Case Serial Number from smbios (from full registration)
    $caseasset == Case Asset tag from smbios (from full registration)
    

    And the last bit is to call the set host name function.
    wget -q -“http://<fog_server_IP>/fog/service/sethostname.php?mac=$mac&oldname=$oldhostname&newname=$newhostname”

    For this script to work you must supply the host mac address, its new host name and for safety sake its old host name to prevent an accidental host name change.


  • Moderator

    @Junkhacker This can get me started very nicely, but I still need access to some of the other settings as I listed in my OP. Specifically I would need to know the site location of the computer which is the name of the assigned location as well as the Product Key. I think I’m pretty close on having all of the bits though.


  • Moderator

    @george1421 said:

    As a second use case I’m deploying a linux image and I would also like to set a few system parameters post deployment like system name, and a few location specific settings based on the location and deployment node where the image came from.

    @ch3i has a rough script somewhere in the forums that does this. @Jbob has a developmental version of the FOG Service that runs/works on every major flavor of Linux - good luck building it, maybe he’ll get with you and help set it up or give you an executable.


  • Developer

    to gain access to the fog boot environment variables used by the fog scripts add this line to the top of your postinstall script

    . /usr/share/fog/lib/funcs.sh;
    

    i’m afraid there isn’t a master list of the variables used, but here’s a few
    $osid : 1,2,3,4,5,6,7,8,9,50 relates to the OS set for image
    $hostname : name registered in fog
    $storage : the NFS location of the storage node it pulls the image from
    $img : the name of the image that was deployed to the computer

    this will also give you access to the functions in that file, if you want to use them, such as “dots” and “debugPause”


  • Moderator

    Well, I guess I did a cruddy job of explaining what I need. (I’ve been working on this for a while so I left the why out and went right into the how).

    I’m working on a fog.postinstall script. I have a situation where i can not use / install the fog service on a target computer for regulatory reasons. To properly set the system host name, product key, ou and a few other variables correctly in the unattend.xml file I need access to them in the post install bash environment.

    As a second use case I’m deploying a linux image and I would also like to set a few system parameters post deployment like system name, and a few location specific settings based on the location and deployment node where the image came from. If these variables already exist in the system, is there a way I can find out what they are called without having to reverse engineer the answer?

    I’ve also reviewed some of the other scripts in the inits where these settings are derived through one method or another. The idea here is to create a consistent set of post install bash variables that can be use of all post deployment scripts. I was trying to come up with a process that would be easy to implement without much to any recoding required in the inits.


  • Senior Developer

    @Tom-Elliott sorry on spamming but this would mean you don’t need to poll to get that hosts information.


  • Senior Developer

    Further , if you call the script with the . Before the call you can dynamically adjust the script using the passed kernel variable names. So: a line would simple look like: echo $OU in your particular script.


  • Senior Developer

    Also, you could use a hook to present all the data you need in the kernel args stuff. I have to get the hook you’d tie into but I already created an example on how to change the bootmenu stuff before it is output to ipxe.


  • Senior Developer

    Most of this is pretty easy. However, why do you need to download script? Just add the script you need to the images folder and edit the post download script from there, no need to use an inode in the init and changes take affect immediately.

    Hostname is already passed so long as early name changing is on.


Log in to reply
 

Looks like your connection to FOG Project was lost, please wait while we try to reconnect.