]> pere.pagekite.me Git - homepage.git/blobdiff - blog/archive/2011/11/11.rss
Generated.
[homepage.git] / blog / archive / 2011 / 11 / 11.rss
index 36972c4b3e4421373d012b9873f1794f8817b7b9..367493088dfccdfaf195b30c0460a9c46efbfbed 100644 (file)
@@ -100,5 +100,193 @@ til aktuelle artikler og innlegg om temaet.</p>
 </description>
        </item>
        
+       <item>
+               <title>Automatically upgrading server firmware on Dell PowerEdge</title>
+               <link>http://people.skolelinux.org/pere/blog/Automatically_upgrading_server_firmware_on_Dell_PowerEdge.html</link>        
+               <guid isPermaLink="true">http://people.skolelinux.org/pere/blog/Automatically_upgrading_server_firmware_on_Dell_PowerEdge.html</guid>
+                <pubDate>Mon, 21 Nov 2011 12:00:00 +0100</pubDate>
+               <description>&lt;p&gt;At work we have heaps of servers.  I believe the total count is
+around 1000 at the moment.  To be able to get help from the vendors
+when something go wrong, we want to keep the firmware on the servers
+up to date.  If the firmware isn&#39;t the latest and greatest, the
+vendors typically refuse to start debugging any problems until the
+firmware is upgraded.  So before every reboot, we want to upgrade the
+firmware, and we would really like everyone handling servers at the
+university to do this themselves when they plan to reboot a machine.
+For that to happen we at the unix server admin group need to provide
+the tools to do so.&lt;/p&gt;
+
+&lt;p&gt;To make firmware upgrading easier, I am working on a script to
+fetch and install the latest firmware for the servers we got.  Most of
+our hardware are from Dell and HP, so I have focused on these servers
+so far.  This blog post is about the Dell part.&lt;/P&gt;
+
+&lt;p&gt;On the Dell FTP site I was lucky enough to find
+&lt;a href=&quot;ftp://ftp.us.dell.com/catalog/Catalog.xml.gz&quot;&gt;an XML file&lt;/a&gt;
+with firmware information for all 11th generation servers, listing
+which firmware should be used on a given model and where on the FTP
+site I can find it.  Using a simple perl XML parser I can then
+download the shell scripts Dell provides to do firmware upgrades from
+within Linux and reboot when all the firmware is primed and ready to
+be activated on the first reboot.&lt;/p&gt;
+
+&lt;p&gt;This is the Dell related fragment of the perl code I am working on.
+Are there anyone working on similar tools for firmware upgrading all
+servers at a site?  Please get in touch and lets share resources.&lt;/p&gt;
+
+&lt;p&gt;&lt;pre&gt;
+#!/usr/bin/perl
+use strict;
+use warnings;
+use File::Temp qw(tempdir);
+BEGIN {
+    # Install needed RHEL packages if missing
+    my %rhelmodules = (
+        &#39;XML::Simple&#39; =&gt; &#39;perl-XML-Simple&#39;,
+        );
+    for my $module (keys %rhelmodules) {
+        eval &quot;use $module;&quot;;
+        if ($@) {
+            my $pkg = $rhelmodules{$module};
+            system(&quot;yum install -y $pkg&quot;);
+            eval &quot;use $module;&quot;;
+        }
+    }
+}
+my $errorsto = &#39;pere@hungry.com&#39;;
+
+upgrade_dell();
+
+exit 0;
+
+sub run_firmware_script {
+    my ($opts, $script) = @_;
+    unless ($script) {
+        print STDERR &quot;fail: missing script name\n&quot;;
+        exit 1
+    }
+    print STDERR &quot;Running $script\n\n&quot;;
+
+    if (0 == system(&quot;sh $script $opts&quot;)) { # FIXME correct exit code handling
+        print STDERR &quot;success: firmware script ran succcessfully\n&quot;;
+    } else {
+        print STDERR &quot;fail: firmware script returned error\n&quot;;
+    }
+}
+
+sub run_firmware_scripts {
+    my ($opts, @dirs) = @_;
+    # Run firmware packages
+    for my $dir (@dirs) {
+        print STDERR &quot;info: Running scripts in $dir\n&quot;;
+        opendir(my $dh, $dir) or die &quot;Unable to open directory $dir: $!&quot;;
+        while (my $s = readdir $dh) {
+            next if $s =~ m/^\.\.?/;
+            run_firmware_script($opts, &quot;$dir/$s&quot;);
+        }
+        closedir $dh;
+    }
+}
+
+sub download {
+    my $url = shift;
+    print STDERR &quot;info: Downloading $url\n&quot;;
+    system(&quot;wget --quiet \&quot;$url\&quot;&quot;);
+}
+
+sub upgrade_dell {
+    my @dirs;
+    my $product = `dmidecode -s system-product-name`;
+    chomp $product;
+
+    if ($product =~ m/PowerEdge/) {
+
+        # on RHEL, these pacakges are needed by the firwmare upgrade scripts
+        system(&#39;yum install -y compat-libstdc++-33.i686 libstdc++.i686 libxml2.i686 procmail&#39;);
+
+        my $tmpdir = tempdir(
+            CLEANUP =&gt; 1
+            );
+        chdir($tmpdir);
+        fetch_dell_fw(&#39;catalog/Catalog.xml.gz&#39;);
+        system(&#39;gunzip Catalog.xml.gz&#39;);
+        my @paths = fetch_dell_fw_list(&#39;Catalog.xml&#39;);
+        # -q is quiet, disabling interactivity and reducing console output
+        my $fwopts = &quot;-q&quot;;
+        if (@paths) {
+            for my $url (@paths) {
+                fetch_dell_fw($url);
+            }
+            run_firmware_scripts($fwopts, $tmpdir);
+        } else {
+            print STDERR &quot;error: Unsupported Dell model &#39;$product&#39;.\n&quot;;
+            print STDERR &quot;error: Please report to $errorsto.\n&quot;;
+        }
+        chdir(&#39;/&#39;);
+    } else {
+        print STDERR &quot;error: Unsupported Dell model &#39;$product&#39;.\n&quot;;
+        print STDERR &quot;error: Please report to $errorsto.\n&quot;;
+    }
+}
+
+sub fetch_dell_fw {
+    my $path = shift;
+    my $url = &quot;ftp://ftp.us.dell.com/$path&quot;;
+    download($url);
+}
+
+# Using ftp://ftp.us.dell.com/catalog/Catalog.xml.gz, figure out which
+# firmware packages to download from Dell.  Only work for Linux
+# machines and 11th generation Dell servers.
+sub fetch_dell_fw_list {
+    my $filename = shift;
+
+    my $product = `dmidecode -s system-product-name`;
+    chomp $product;
+    my ($mybrand, $mymodel) = split(/\s+/, $product);
+
+    print STDERR &quot;Finding firmware bundles for $mybrand $mymodel\n&quot;;
+
+    my $xml = XMLin($filename);
+    my @paths;
+    for my $bundle (@{$xml-&gt;{SoftwareBundle}}) {
+        my $brand = $bundle-&gt;{TargetSystems}-&gt;{Brand}-&gt;{Display}-&gt;{content};
+        my $model = $bundle-&gt;{TargetSystems}-&gt;{Brand}-&gt;{Model}-&gt;{Display}-&gt;{content};
+        my $oscode;
+        if (&quot;ARRAY&quot; eq ref $bundle-&gt;{TargetOSes}-&gt;{OperatingSystem}) {
+            $oscode = $bundle-&gt;{TargetOSes}-&gt;{OperatingSystem}[0]-&gt;{osCode};
+        } else {
+            $oscode = $bundle-&gt;{TargetOSes}-&gt;{OperatingSystem}-&gt;{osCode};
+        }
+        if ($mybrand eq $brand &amp;&amp; $mymodel eq $model &amp;&amp; &quot;LIN&quot; eq $oscode)
+        {
+            @paths = map { $_-&gt;{path} } @{$bundle-&gt;{Contents}-&gt;{Package}};
+        }
+    }
+    for my $component (@{$xml-&gt;{SoftwareComponent}}) {
+        my $componenttype = $component-&gt;{ComponentType}-&gt;{value};
+
+        # Drop application packages, only firmware and BIOS
+        next if &#39;APAC&#39; eq $componenttype;
+
+        my $cpath = $component-&gt;{path};
+        for my $path (@paths) {
+            if ($cpath =~ m%/$path$%) {
+                push(@paths, $cpath);
+            }
+        }
+    }
+    return @paths;
+}
+&lt;/pre&gt;
+
+&lt;p&gt;The code is only tested on RedHat Enterprise Linux, but I suspect
+it could work on other platforms with some tweaking.  Anyone know a
+index like Catalog.xml is available from HP for HP servers?  At the
+moment I maintain a similar list manually and it is quickly getting
+outdated.&lt;/p&gt;
+</description>
+       </item>
+       
         </channel>
 </rss>