#!/usr/bin/perl use strict; use warnings; use File::Temp qw(tempdir); BEGIN { # Install needed RHEL packages if missing my %rhelmodules = ( 'XML::Simple' => 'perl-XML-Simple', ); for my $module (keys %rhelmodules) { eval "use $module;"; if ($@) { my $pkg = $rhelmodules{$module}; system("yum install -y $pkg"); eval "use $module;"; } } } my $errorsto = 'pere@hungry.com'; upgrade_dell(); exit 0; sub run_firmware_script { my ($opts, $script) = @_; unless ($script) { print STDERR "fail: missing script name\n"; exit 1 } print STDERR "Running $script\n\n"; if (0 == system("sh $script $opts")) { # FIXME correct exit code handling print STDERR "success: firmware script ran succcessfully\n"; } else { print STDERR "fail: firmware script returned error\n"; exit 1; } } sub run_firmware_scripts { my ($opts, @dirs) = @_; # Run firmware packages for my $dir (@dirs) { print STDERR "info: Running scripts in $dir\n"; opendir(my $dh, $dir) or die "Unable to open directory $dir: $!"; while (my $s = readdir $dh) { next if $s =~ m/^\.\.?/; run_firmware_script($opts, "$dir/$s"); } closedir $dh; } } sub download { my $url = shift; print STDERR "info: Downloading $url\n"; system("wget --quiet \"$url\""); } 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('yum install -y compat-libstdc++-33.i686 libstdc++.i686 libxml2.i686 procmail'); my $tmpdir = tempdir( CLEANUP => 1 ); chdir($tmpdir); fetch_dell_fw('catalog/Catalog.xml.gz'); system('gunzip Catalog.xml.gz'); my @paths = fetch_dell_fw_list('Catalog.xml'); # -q is quiet, disabling interactivity and reducing console output my $fwopts = "-q"; if (@paths) { for my $url (@paths) { fetch_dell_fw($url); } run_firmware_scripts($fwopts, $tmpdir); } else { print STDERR "error: Unsupported Dell model '$product'.\n"; print STDERR "error: Please report to $errorsto.\n"; exit 1; } chdir('/'); } else { print STDERR "error: Unsupported Dell model '$product'.\n"; print STDERR "error: Please report to $errorsto.\n"; exit 1; } } sub fetch_dell_fw { my $path = shift; my $url = "ftp://ftp.us.dell.com/$path"; 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 "Finding firmware bundles for $mybrand $mymodel\n"; my $xml = XMLin($filename); my @paths; for my $bundle (@{$xml->{SoftwareBundle}}) { my $brand = $bundle->{TargetSystems}->{Brand}->{Display}->{content}; my $model = $bundle->{TargetSystems}->{Brand}->{Model}->{Display}->{content}; my $oscode; if ("ARRAY" eq ref $bundle->{TargetOSes}->{OperatingSystem}) { $oscode = $bundle->{TargetOSes}->{OperatingSystem}[0]->{osCode}; } else { $oscode = $bundle->{TargetOSes}->{OperatingSystem}->{osCode}; } if ($mybrand eq $brand && $mymodel eq $model && "LIN" eq $oscode) { @paths = map { $_->{path} } @{$bundle->{Contents}->{Package}}; } } for my $component (@{$xml->{SoftwareComponent}}) { my $componenttype = $component->{ComponentType}->{value}; # Drop application packages, only firmware and BIOS next if 'APAC' eq $componenttype; my $cpath = $component->{path}; for my $path (@paths) { if ($cpath =~ m%/$path$%) { push(@paths, $cpath); } } } return @paths; }