Managing The System Boot Location with iControl
The BIG-IP has the ability to partition off different "slots" for multiple software installs. This allows for installing a second version of the software on the system without overwriting the existing configuration to allow for an easy rollback in the case you prefer to roll back to your previous version. The System.SoftwareManagement interface contains the methods to manage the software on the system and hidden in there are the methods for getting and setting the current "boot locations". This article will illustrate the use of those methods.
Usage
The following code samples will build a PowerShell command line application allowing control over system boot locations. This program takes as input the bigip, username, and password as well as a subcommand and optional parameters. Usage is displayed with the Write-Usage function.
param ( $g_bigip = $null, $g_uid = $null, $g_pwd = $null, $g_cmd = $null, $g_arg = $null ); Set-PSDebug -strict; function Write-Usage() { Write-Host "Usage: BootImage.ps1 host uid pwd [options]"; Write-Host " options"; Write-Host " -------"; Write-Host " get - Get the name of the active boot location"; Write-Host " set location - Set the active boot location"; Write-Host " getinfo - Get the contents of the active boot location"; exit; }
Initialization
As is with all of my iControl PowerShell scripts, validation is made as to whether the iControlSnapin is loaded into the current powershell context. The Initialize-F5.iControl cmdlet is then called to setup the connection to the BIG-IP for subsequent calls.
The main application logic checks for the passed in command and then passes control to either the Get-BootLocation, Set-BootLocation, or Get-BootImageInfo local functions which I will talk about below.
function Do-Initialize() { if ( (Get-PSSnapin | Where-Object { $_.Name -eq "iControlSnapIn"}) -eq $null ) { Add-PSSnapIn iControlSnapIn } $success = Initialize-F5.iControl -HostName $g_bigip -Username $g_uid -Password $g_pwd; return $success; } if ( ($g_bigip -eq $null) -or ($g_uid -eq $null) -or ($g_pwd -eq $null) -or ($g_cmd -eq $null) ) { Write-Usage; } if ( Do-Initialize ) { switch ($g_cmd.ToLower()) { "getinfo" { Get-BootImageInfo; } "get" { Get-BootLocation; } "set" { if ( $g_arg -eq $null ) { Write-Usage; } else { Set-BootLocation $g_arg; } } default { Write-Usage; } } } else { Write-Error "ERROR: iControl subsystem not initialized" }
Querying the boot location
The Get-BootLocation local function is just a wrapper for the iControl get_boot_location method. This method takes as input no parameters and returns the current user friendly name for the current boot location. This value is displayed to the console.
function Get-BootLocation() { $location = (Get-F5.iControl).SystemSoftwareManagement.get_boot_location(); Write-Host "Boot Location: $location"; }
Setting the boot location
The Set-BootLocation function passes calls the iControl set_boot_location iControl method with the passed in boot location user friend name. It then sets the boot location with this value so next time a system reboot occurs, it will load in this location.
function Set-BootLocation() { param($location); (Get-F5.iControl).SystemSoftwareManagement.set_boot_location($location); Get-BootLocation; }
Querying all boot image information
There is no iControl method to return just the possible boot locations but we do expose a method that returns all of the boot image information. Contained in here is the boot locations (or slots) along with a bunch of other fun stuff. The Get-BootImageInfo function will call this get_boot_image_information() iControl method. The returned value is the raw configuration file base64 encoded in a byte array. We take this array and then ASCII encode it with the System.Text.ASCIIEncoding's GetString() method. This decoded string is then passed to the Parse-BootLocationData function for further processing.
function Get-BootImageInfo() { $rawdata = (Get-F5.iControl).SystemSoftwareManagement.get_boot_image_information($false); Write-Host "Boot Information"; $ASCII = New-Object -TypeName System.Text.ASCIIEncoding $formatted = $ASCII.GetString($rawdata) Parse-BootLocationData $formatted; }
The Parse-BootLocationData function takes the decoded data and then reads it line by line with a System.IO.StringReader object. The format of the file is a bunch of name=value pairs grouped into sections delimited with a header line starting and ending with a slash. This function loops line after line looking for a start of a section. It then passes the StringReader to the Parse-BootLocationSection function to extract the name=value pairs for that section.
function Parse-BootLocationData() { param($data); $sr = New-Object System.IO.StringReader($data); $line = $sr.ReadLine(); while($null -ne $line) { if ( $line.StartsWith("/") ) { # Beginning of section Parse-BootLocationSection $line $sr; } else { Write-Host $line; } $line = $sr.ReadLine(); } }
The Parse-BootLocationSection function extracts data from the section header and displays the component to the console. Sections include Network, Disk, Slot, Hardware, Installation, and License information. Each subsequent line is extracted until a end of section is reached. Each of the name=value pairs are split apart and put into a hash that is finally displayed to the console in a nice tabular fashion.
function Parse-BootLocationSection() { param($header, $sr); $headertxt = $header.Replace("/", '').Trim(); $tokens = $headertxt.Split( (, ' ')); $comp = $tokens[0]; $desc = $headertxt.Replace("$comp ", ""); $hash = @{}; Write-Host "===========================================================" Write-Host "Component: $comp" Write-Host " Desc: $desc"; Write-Host "===========================================================" $line = $sr.ReadLine(); while ($null -ne $line) { if ( $line.Trim().Length -eq 0 ) { #end of section break; } $tokens = $line.Trim().Split( (, '=')); $hash.Add($tokens[0], $tokens[1]); $line = $sr.ReadLine(); } $hash.GetEnumerator() | Sort-Object -Property Name | Format-Table -autosize; }
Usage
The following commands will get and set the current boot location from HD1.1 to HD1.2 and back.
PS C:\> .\bootimage.ps1 bigip_address username password get Boot Location: HD1.1 PS C:\> .\bootimage.ps1 bigip_address username password set HD1.2 Boot Location: HD1.2 PS C:\> .\bootimage.ps1 bigip_address username password set HD1.1 Boot Location: HD1.1
And this example will query the entire boot information, parse the contents and return the results to the console. There is a lot of information in here with dependencies back and forth but what you'll be looking for is the "visible_name" attribute under the Slots. This will be the value you can pass into the get and set subcommands. I'm sure more interesting things can be gleaming from this information but I'll leave that for another tech tip.
PS C:\> .\bootimage.ps1 bigip_address username password getinfo Boot Information =========================================================== Component: Network Desc: audit_network =========================================================== Name Value ---- ----- address 172.27.230.170 gateway 172.27.230.254 hostname theboss.dev.net interface eth0 nameservers 172.27.1.1,172.27.2.1 netmask 255.255.255.0 =========================================================== Component: Network Desc: audit_network_persist =========================================================== Name Value ---- ----- address 172.27.230.170 gateway 172.27.230.254 interface eth0 nameservers 172.27.1.1,172.27.2.1 netmask 255.255.255.0 =========================================================== Component: Disk Desc: iDisk_0 audit_disks[0] =========================================================== Name Value ---- ----- boot_part_index 2 boot_size_kb 5040 boot_stat 0 capacity_mb 509 i1_size_kib 504000 name hda serial_num 095VT194S0454DC08070 =========================================================== Component: Disk Desc: iDisk_1 audit_disks[1] =========================================================== Name Value ---- ----- boot_part_index 2 boot_size_kb 803250 boot_stat 0 capacity_mb 80418 i1_size_kib 31760505 i2_size_kib 31760505 name hdc serial_num PFD202S2UT1RBJ share_size_kb 16081065 share_stat 0 =========================================================== Component: Slot Desc: iSlot_hda.1 audit_slots[0] =========================================================== Name Value ---- ----- boot_mem 1024M boot_quiet false disk_description SILICONSYSTEMS disk_index 0 disk_part 2 integrity_status 0 is_CF true slot_key hda.1 visible_name CF1.1 =========================================================== Component: Slot Desc: iSlot_hdc.1 audit_slots[1] =========================================================== Name Value ---- ----- boot_mem 1152M boot_quiet true disk_description HDS728080PLAT20 disk_index 1 disk_part 2 integrity_status 0 is_active true slot_key hdc.1 visible_name HD1.1 =========================================================== Component: Slot Desc: iSlot_hdc.2 audit_slots[2] =========================================================== Name Value ---- ----- boot_mem 1152M boot_quiet true disk_description HDS728080PLAT20 disk_index 1 disk_part 3 integrity_status 0 slot_key hdc.2 visible_name HD1.2 =========================================================== Component: Hardware Desc: audit_hardware =========================================================== Name Value ---- ----- boot_slot_key hdc.1 bootdisk_id hda nics 3 platform_family BUFFALO_JUMP platform_id D63 ram_mb 2010 serial_console_speed 19200 sharedisk_id hdc =========================================================== Component: Installation Desc: iInstallation_0 audit_installations[0] =========================================================== Name Value ---- ----- build 119.0 product BIG-IP slot_key hda.1 UTC_delta -0800 UTC_hwclock true version 9.2.0 =========================================================== Component: Configuration Desc: iConfiguration_0 audit_configurations[0] =========================================================== Name Value ---- ----- filename /mnt/tmp/install/slot/hdc.1/var/auto-ucs/config.ucs mod_date 2008-12-10 mod_time 08:37:31.000000000 mod_tz -0800 slot_key hdc.1 version 9.4.5 =========================================================== Component: License Desc: iLicense_0 audit_licenses[0] =========================================================== Name Value ---- ----- Licensed_Date 20070206 regkey J9742-63173-86271-91277-3682254 Service_Check_Date 20081120 slot_key hdc.1 =========================================================== Component: Installation Desc: iInstallation_1 audit_installations[1] =========================================================== Name Value ---- ----- build 1049.10 product BIG-IP slot_key hdc.1 UTC_delta -0800 UTC_hwclock true version 9.4.5 =========================================================== Component: Configuration Desc: iConfiguration_1 audit_configurations[1] =========================================================== Name Value ---- ----- filename /mnt/tmp/install/slot/hdc.2/config.ucs mod_date 2008-10-09 mod_time 09:30:29.000000000 mod_tz -0700 slot_key hdc.2 version 9.4.2 =========================================================== Component: License Desc: iLicense_1 audit_licenses[1] =========================================================== Name Value ---- ----- Licensed_Date 20070206 regkey J9742-63173-86271-91277-3682254 Service_Check_Date 20080716 slot_key hdc.2 =========================================================== Component: Installation Desc: iInstallation_2 audit_installations[2] =========================================================== Name Value ---- ----- build 228.13 product BIG-IP slot_key hdc.2 UTC_delta -0800 UTC_hwclock true version 9.4.2
Conclusion
The boot location methods in the System.SoftwareManagement interface can give you access to remotely configure which boot slots your system will load into. You can use the System.Services.reboot_system to switch the system back and forth between running software versions programmatically.