#!/usr/bin/perl # IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # bos720 src/bos/usr/lib/nim/methods/c_loadiso.pl 1.10 # # Licensed Materials - Property of IBM # # COPYRIGHT International Business Machines Corp. 2008 # All Rights Reserved # # US Government Users Restricted Rights - Use, duplication or # disclosure restricted by GSA ADP Schedule Contract with IBM Corp. # # IBM_PROLOG_END_TAG # @(#)44 1.10 src/bos/usr/lib/nim/methods/c_loadiso.pl, cmdnim, bos720 11/25/08 07:53:10 use strict; use warnings; use Getopt::Long; use Carp; use IPC::Open3; use IO::Select; use File::Path; # Used for mkpath rmtree use File::Basename; # Used for basename use File::Temp qw / tempfile tempdir /; use lib '/usr/lpp/bos.sysmgt/nim/perl'; use NIMUtils; use NIMUtils ':rc_csts'; # KO_CODE OK_CODE # The following line is dynamically replaced at compiled time # with the list of all IDs needed to display i18n messages. # See the Makefile for more details. # === START use constant { ERR_OVF_REFERS => [1,449], ERR_OVF_RUNCMD => [1,450], ERR_OVF_BAD_OPTION => [1,451], ERR_OVF_MISSING_PARAM => [1,452], ERR_OVF_UNKN_OBJECT => [1,453], ERR_OVF_OPEN => [1,454], ERR_OVF_FILE_NOTFOUND => [1,455], ERR_OVF_LOCATION_NOTFOUND => [1,456], ERR_OVF_RESTORE => [1,457], ERR_OVF_UNMOUNT => [1,458], ERR_OVF_FS_EXISTS => [1,459], ERR_OVF_COLLECT_INFO => [1,460], ERR_OVF_INVALID_ENVELOPE => [1,461], ERR_OVF_DEFAULT_VALUES => [1,462], ERR_OVF_NOSPACE_FOR_REPOSITORY => [1,468], MSG_M_MKOVF_VM_SYNTAX => [479,492], MSG_M_RMOVF_VM_SYNTAX => [479,493], ATTR_OVF_VM => [5,820], H_ATTR_OVF_VM => [5,821], ATTR_OVF_ENVELOPE => [5,824], H_ATTR_OVF_ENVELOPE => [5,825], ATTR_OVF_SOURCE => [5,826], H_ATTR_OVF_SOURCE => [5,827], ATTR_OVF_ENVELOPE_UPDATE => [5,834], H_ATTR_OVF_ENVELOPE_UPDATE => [5,835], VERBOSE_ATTR_OVF_VM => [11,380], VERBOSE_ATTR_OVF_ENVELOPE => [11,381], VERBOSE_ATTR_OVF_SOURCE => [11,382], VERBOSE_ATTR_OVF_ENVELOPE_UPDATE => [11,384], }; # === END # Global variables use vars qw($resources_mounted %lsnim_info $image_name $device_name $tmpdir ); # return code values use constant ERR_RC_RUNCMD => 2; use constant ERR_RC_MOUNT => 3; use constant ERR_RC_UNMOUNT => 4; use constant ERR_RC_BAD_OPTION => 5; use constant ERR_RC_MISSING_PARAM => 6; use constant ERR_RC_COLLECT_IMAGE_INFO => 7; use constant ERR_RC_CANT_CREATE_ISO => 8; use constant ERR_RC_CANT_CREATE_TMPDIR => 9; use constant ERR_RC_NOSPACE_FOR_REPOSITORY => 10; # List of the AIX commands used my $LSSLOT = "/usr/sbin/lsslot"; my $LSREP = "/usr/ios/cli/ioscli lsrep"; my $MKREP = "/usr/ios/cli/ioscli mkrep"; my $CHREP = "/usr/ios/cli/ioscli chrep"; my $LSVOPT = "/usr/ios/cli/ioscli lsvopt"; my $LSSP = "/usr/ios/cli/ioscli lssp"; my $MKVOPT = "/usr/ios/cli/ioscli mkvopt"; my $RMVOPT = "/usr/ios/cli/ioscli rmvopt"; my $MKVDEV = "/usr/ios/cli/ioscli mkvdev"; my $RMVDEV = "/usr/ios/cli/ioscli rmvdev"; my $LOADOPT = "/usr/ios/cli/ioscli loadopt"; # ---------------------------------------------------------------------------- # SUBROUTINE_NAME: cleanup_exit # ABSTRACT: This function cleanups all the resources used by this script and exit # GLOBAL_MODIFIED: none # INPUT: none # OUTPUT: none # RETURN: KO_CODE # ---------------------------------------------------------------------------- sub cleanup_exit() { &NIMUtils::restore_default_signals_handlers(); cleanup(); if (-d $tmpdir) { chdir('/'); # avoid the warning on stderr rmtree($tmpdir); } exit(KO_CODE); } # ---------------------------------------------------------------------------- # SUBROUTINE_NAME: remove_vopt # ABSTRACT: This function checks that the virtual optical media is created # and remove it. # GLOBAL_MODIFIED: none # INPUT: none # OUTPUT: none # RETURN: OK_CODE # ---------------------------------------------------------------------------- sub remove_vopt() { my ($rc, $stdout, $cmd); if ($image_name ne "") { $cmd = "$RMVOPT -name $image_name"; # run the command but don't check the returned values ($rc, $stdout) = &NIMUtils::run_command($cmd); $image_name = ""; } return(OK_CODE); } # ---------------------------------------------------------------------------- # SUBROUTINE_NAME: remove_vadapt # ABSTRACT: This function checks that the virtual drive exists # and remove it. # GLOBAL_MODIFIED: none # INPUT: none # OUTPUT: none # RETURN: OK_CODE # ---------------------------------------------------------------------------- sub remove_vadapt() { my ($rc, $stdout, $cmd); if (defined($device_name) && ($device_name !~ /^\s*$/)) { $cmd = "$RMVDEV -vtd $device_name"; # run the command but don't check the returned values ($rc, $stdout) = &NIMUtils::run_command($cmd); $device_name = ""; } return(OK_CODE); } # ---------------------------------------------------------------------------- # SUBROUTINE_NAME: cleanup # ABSTRACT: This function cleanup all the resources used by this script # GLOBAL_MODIFIED: none # INPUT: name of mount point to cleanup # INPUT: Did the resource use -o allocate at the time of allocation # INPUT: Did the resource is a mounted filesystem # OUTPUT: none # RETURN: OK_CODE if ok, ERR_RC_RUNCMD else # ---------------------------------------------------------------------------- sub cleanup() { my ($rc); # 1 - umount the resource &NIMUtils::nim_umount($resources_mounted, 1); # 2 - remove the virtual optical drive if necessary &remove_vadapt($device_name); # 3 - remove the virtual optical device if necessary &remove_vopt($image_name); return(OK_CODE); } # ---------------------------------------------------------------------------- # SUBROUTINE_NAME: mount_iso_in_vopt_drive # ABSTRACT: This function does all the real work to mount the VOPT device. # GLOBAL_MODIFIED: # INPUT: slot_id # INPUT: iso_location # OUTPUT: none # RETURN: OK_CODE if OK # ---------------------------------------------------------------------------- sub mount_iso_in_vopt_drive ($$) { my($slot_num, $iso_location, $vopt_obj_name)=@_; my $base_name = basename($iso_location); my $server_nim_object = "master"; my $mount_pnt = $tmpdir . "/$base_name"; my ($rc, $cmd, $stdout, $image_location); my ($fn_imgname, $tmpl_imgname, $tmpl_imgsuffix); #-1- Mount the resource allocated by the server method # The ISO is always on the master $rc = &NIMUtils::lsnim_command($server_nim_object, \%lsnim_info); if ($rc) { translate(ERR_OVF_RUNCMD, "%s: The command \"%s\" failed (rc=%s).\n", "mount_iso_in_vopt_drive", "/usr/sbin/nimclient -l -l $server_nim_object", $rc); &cleanup(); return (ERR_RC_RUNCMD); } my %server_info = %{$lsnim_info{$server_nim_object}}; my $server_hostname = (split(/ /, $server_info{"if1"}))[1]; ($rc, $resources_mounted) =&NIMUtils::nim_mount($server_nim_object, "$server_hostname:$iso_location", "$mount_pnt", $vopt_obj_name); if ($rc == OK_CODE) { $image_location = $mount_pnt; } else { &cleanup(); translate(ERR_OVF_RUNCMD, "%s: The command \"%s\" failed (rc=%s).\n", "mount_iso_in_vopt_drive", "mount $server_hostname:$iso_location on $mount_pnt", $rc); return (ERR_RC_COLLECT_IMAGE_INFO); } #-2- Get the iso file size my @sb = stat($image_location); # Note: put this size in mb to be able to compare it to the other outputs my $image_size = int(($sb[7] / (1024 * 1024)) + 1); #-3- Check the repository exists and has enough free space $cmd = "$LSREP 2>&1"; ($rc, $stdout) = &NIMUtils::run_command($cmd); my $repository_found = 0; if ($rc ==0 and $stdout !~ /The DVD repository has not been created yet/) { # the repository exists my @tmp = split(/\n/, $stdout); # search for it in the lsrep output and check its size foreach my $line (@tmp) { #$ lsrep #Size(mb) Free(mb) Parent Pool Parent Size Parent Free # 62 62 rootvg_clients 69888 31424 if ($line =~ /^\s+(\d+)\s+(\d+)\s+(\S+)\s+(\d+)\s+(\d+)$/) { # a repository was found => check its size my $rep_free = $2; if ($rep_free < $image_size) { my $extend_size = $image_size - $rep_free; $cmd = "$CHREP -size " . $extend_size . "M"; ($rc, $stdout) = &NIMUtils::run_command($cmd); if ($rc) { # this repository can not be extended, only one can be created => failed &NIMUtils::translate(ERR_OVF_RUNCMD, "%s: The command \"%s\" failed (rc=%s).\n", "mount_iso_in_vopt_drive", $cmd, $rc); &cleanup(); return (ERR_RC_RUNCMD); } } $repository_found = 1; last; } } } if (!$repository_found) { #-4- Create a repository -> check the free space in the storage pools $cmd = "$LSSP"; ($rc, $stdout) = &NIMUtils::run_command($cmd); if ($rc) { &NIMUtils::translate(ERR_OVF_RUNCMD, "%s: The command \"%s\" failed (rc=%s).\n", "mount_iso_in_vopt_drive", $cmd, $rc); &cleanup(); return (ERR_RC_RUNCMD); } my $candidate_pool = undef; my @tmp = split(/\n/, $stdout); foreach my $l (@tmp) { if ($l =~ /^(\S+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\d+)\s+(\S+)/) { if ($3 >= $image_size) { $candidate_pool = $1; $cmd = "$MKREP -sp " . $candidate_pool . " -size " . $image_size . "M"; ($rc, $stdout) = &NIMUtils::run_command($cmd); if ($rc) { &NIMUtils::translate(ERR_OVF_RUNCMD, "%s: The command \"%s\" failed (rc=%s).\n", "mount_iso_in_vopt_drive", $cmd, $rc); &cleanup(); return (ERR_RC_RUNCMD); } last; } } } if (!defined($candidate_pool)) { &NIMUtils::translate(ERR_OVF_NOSPACE_FOR_REPOSITORY, "%s: There is not enough space left to create a virtual optical disk repository.\n", "mount_iso_in_vopt_drive"); &cleanup(); return (ERR_RC_NOSPACE_FOR_REPOSITORY); } } #-5- generate a unique name for the iso_file based on the base_name # "nim_vopt_iso_XXXXX_.iso $tmpl_imgname = "nim_vopt_iso_XXXXX"; $tmpl_imgsuffix = "_" . $base_name; if ($tmpl_imgsuffix !~ /.iso$/) { $tmpl_imgsuffix .= ".iso"; } # the lenght of the iso can not exceed 38 characters if (length($tmpl_imgsuffix) > 19) { my $start = substr($tmpl_imgsuffix, 0, 14); $tmpl_imgsuffix = $start . ".iso"; } (undef, $fn_imgname) = tempfile($tmpl_imgname, SUFFIX => "$tmpl_imgsuffix", DIR => "/var/vio/VMLibrary", OPEN => 0); if ($fn_imgname eq "") { &NIMUtils::translate(ERR_OVF_RUNCMD, "%s: The command \"%s\" failed (rc=%s).\n", "mount_iso_in_vopt_drive", "tempfile", ERR_RC_CANT_CREATE_ISO); &cleanup(); return (ERR_RC_RUNCMD); } $image_name = basename($fn_imgname); #-6- Create the Virtual optical device $cmd = "$MKVOPT -name $image_name -file $image_location -ro"; ($rc, $stdout) = &NIMUtils::run_command($cmd); if ($rc) { &NIMUtils::translate(ERR_OVF_RUNCMD, "%s: The command \"%s\" failed (rc=%s).\n", "mount_iso_in_vopt_drive", $cmd, $rc); &cleanup(); unlink($fn_imgname); return (ERR_RC_RUNCMD); } #-7- umount the resource &NIMUtils::nim_umount($resources_mounted, 1); #-8- Grep the vhost $cmd = "$LSSLOT -c slot | grep -- -C$slot_num"; ($rc, $stdout) = &NIMUtils::run_command($cmd); if ($rc) { &NIMUtils::translate(ERR_OVF_RUNCMD, "%s: The command \"%s\" failed (rc=%s).\n", "mount_iso_in_vopt_drive", $cmd, $rc); &remove_vopt(); return (ERR_RC_RUNCMD); } my $vhost_id = (split(/\s+/, $stdout))[-1]; if (! defined($vhost_id) || ($vhost_id !~ /vhost/)) { &NIMUtils::translate(ERR_OVF_RUNCMD, "%s: The command \"%s\" failed (rc=%s).\n", "mount_iso_in_vopt_drive", $cmd, $rc); &remove_vopt(); return (ERR_RC_RUNCMD); } #-9- Create the Virtual Adapter # root equiv "mkdev -t fbopt -s vtdev -c virtual_target -p $vhost_id" $cmd = "$MKVDEV -fbo -vadapter $vhost_id"; ($rc, $stdout) = &NIMUtils::run_command($cmd); if ($rc) { &NIMUtils::translate(ERR_OVF_RUNCMD, "%s: The command \"%s\" failed (rc=%s).\n", "mount_iso_in_vopt_drive", $cmd, $rc); &remove_vopt(); return (ERR_RC_RUNCMD); } if ($stdout =~ /^(\S+)\s+Available/) { $device_name = $1; } if (! defined($device_name) || ($device_name =~ /^\s*$/)) { &NIMUtils::translate(ERR_OVF_RUNCMD, "%s: The command \"%s\" failed (rc=%s).\n", "mount_iso_in_vopt_drive", $cmd, $rc); &remove_vopt(); return (ERR_RC_RUNCMD); } #-10- Load the Virtual Optical Device $cmd = "$LOADOPT -vtd $device_name -disk $image_name"; ($rc, $stdout) = &NIMUtils::run_command($cmd); if ($rc) { &NIMUtils::translate(ERR_OVF_RUNCMD, "%s: The command \"%s\" failed (rc=%s).\n", "mount_iso_in_vopt_drive", $cmd, $rc); &remove_vopt(); &remove_vadapt(); return (ERR_RC_RUNCMD); } # All is OK, the device name must be printed on stdout print("$device_name\n"); return OK_CODE; } # ---------------------------------------------------------------------------- ## BEGIN MAIN ## # ---------------------------------------------------------------------------- # options: -a slot_num= -a location= # Parse the arguments my %options; GetOptions("a=s" => \%options) or do { # invalid option parameter &NIMUtils::translate(ERR_OVF_BAD_OPTION, "%s: Invalid option.\n", "main"); exit(ERR_RC_BAD_OPTION); }; my $slot_num = $options{'slot_num'}; my $iso_location = $options{'location'}; my $vopt_obj_name = $options{'vopt_iso'}; $image_name = ""; # Check that mandatory arguments are here &NIMUtils::set_signals_handler(\&cleanup_exit); if ((!defined($slot_num) or ($slot_num eq "")) || (!defined($iso_location) or ($iso_location eq "")) || (!defined($vopt_obj_name) or ($vopt_obj_name eq "")) ) { &NIMUtils::translate(ERR_OVF_MISSING_PARAM, "%s: A mandatory command parameter is missing on the command line.\n", "main"); exit(ERR_RC_MISSING_PARAM); } $resources_mounted = ""; # Generate and create a unique directory $tmpdir = &NIMUtils::create_tmpdir("nim_tmp"); # Change the working directory to $tmpdir chdir($tmpdir); my $rc = &mount_iso_in_vopt_drive($slot_num, $iso_location, $vopt_obj_name); #Change again before deleting. if ($tmpdir) { chdir('/'); # avoid the warning on stderr rmtree($tmpdir); } exit($rc);