# IBM_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # bos720 src/bos/usr/lpp/bosinst/samples/NIM/Deploy/Mksysb/ImageData.pm 1.1 # # Licensed Materials - Property of IBM # # COPYRIGHT International Business Machines Corp. 2008,2009 # 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 # @(#)55 1.1 src/bos/usr/lpp/bosinst/samples/NIM/Deploy/Mksysb/ImageData.pm, bosinst, bos720 3/29/09 15:20:49 package NIM::Deploy::Mksysb::ImageData; =head1 NAME NIM::Deploy::Mksysb::ImageData =over 2 =item Class for parsing and modifying an image.data file. =back =head1 VARIABLES =head1 FUNCTIONS =cut #------------------------------------------------------------------------------- BEGIN { # print "NIM::Deploy::Mksysb::ImageData BEGIN\n"; use NIM::Deploy; use Hash::Util; use File::Basename; use NIM::Util qw(:DEFAULT !log_print !log_printf); use POSIX qw(ceil floor); use Math::BigInt; *log_print = \&NIM::Deploy::log_print; *log_printf = \&NIM::Deploy::log_printf; } #------------------------------------------------------------------------------- INIT { # print "NIM::Deploy::Mksysb::ImageData INIT\n"; # use Config; # ($Config{use64bitint} eq 'define' || $Config{longsize} >= 8) && print "Supports 64-bit numbers\n"; } #------------------------------------------------------------------------------- =head2 new =over 2 =item C =back =head3 DESCRIPTION =over 2 =item Creates a new instance of NIM::Deploy::Mksysb::ImageData. =back =head3 PARAMETERS =over 2 =item * $file_name (REQUIRED) =back =head3 RETURNS =over 2 =item * Reference to the newly created object. =back =head3 EXCEPTIONS =cut #------------------------------------------------------------------------------- sub new { my $type = shift; my ($file_name) = @_; ### log_print("NIM::Deploy::Mksysb::ImageData::new(\'$file_name\')\n"); ### my $this = {}; bless $this, $type; $this->{'file_name'} = $file_name; $this->{'content'} = $this->parse_file($file_name); ### return $this; } #------------------------------------------------------------------------------- sub parse_file { my $this = shift; my ($file_name) = @_; log_print "NIM::Deploy::Mksysb::ImageData::parse_file(\'$file_name\')\n"; my %rc = (); open(IMAGE_DATA, "<$file_name") || die "Can't open $file_name: $!"; my $lineno = 0; my $stanza_name = ''; my $stanza = undef; my $key = ''; while () { my $line = $_; chomp($line); # print "line = \'$line\'\n"; # yyy $lineno++; if (($line =~ m/^[\s]*#.*$/) || ($line =~ m/^[\s]*$/)) { } elsif ($line =~ m/^[\s]*([^\s]+):[\s]*$/) { $stanza_name = $1; $stanza = {}; # print "stanza = \'$stanza_name\'\n"; # yyy if (! defined $rc{$stanza_name}) { $rc{$stanza_name} = []; } push @{$rc{$stanza_name}}, ($stanza); $key = ''; } elsif ((defined $stanza) && ($line =~ m/^[\s]*([^\s]+)[\s]*=[\s]*(.*)[\s]*$/)) { $stanza->{$1} = $2; # print "\t\'$1\' = \'$2\'\n"; # yyy } else { warn "Error parsing file $file_name / line ${lineno}: \'$line\'"; } } close(IMAGE_DATA); return \%rc; } #------------------------------------------------------------------------------- sub print { my $this = shift; my ($fh) = @_; if (! $fh) { $fh = STDOUT; } log_print "NIM::Deploy::Mksysb::ImageData::print()\n"; my @stanza_sections = ('image_data', 'logical_volume_policy', 'ils_data', 'vg_data', 'source_disk_data', 'lv_data', 'fs_data', 'post_install_data', 'post_restvg'); my $stanza_hash = $this->{'content'}; # while (my ($stanza_name, $stanzas) = each(%$stanza_hash)); foreach my $stanza_name (@stanza_sections) { my $stanzas = $stanza_hash->{$stanza_name}; foreach my $stanza (@$stanzas) { print $fh "$stanza_name:\n"; while (my ($key, $value) = each(%$stanza)) { print $fh "\t$key= $value\n"; } print $fh "\n"; } } } #------------------------------------------------------------------------------- sub vg_disk_names { my $this = shift; my @rc = (); eval { my $disks = $this->{'content'}->{'vg_data'}->[0]->{'VG_SOURCE_DISK_LIST'}; @rc = split(/[ \t]+/, $disks); }; return ($@ ? () : @rc); } #------------------------------------------------------------------------------- sub bint { Math::BigInt->new(shift); } #------------------------------------------------------------------------------- sub disk_size { my $this = shift; my ($disk_name) = @_; log_print "NIM::Deploy::Mksysb::ImageData::disk_size(\'$disk_name\')\n"; my $rc = bint(0); eval { foreach my $source_disk (@{$this->{'content'}->{'source_disk_data'}}) { if ($source_disk->{'HDISKNAME'} eq $disk_name) { $rc = bint($source_disk->{'SIZE_MB'} * 1024 * 1024); } } }; $rc = ($@ ? bint(0) : $rc); log_printf("\trc = %s\n", $rc->bstr()); return $rc; } #------------------------------------------------------------------------------- sub num_disks { my $this = shift; log_print "NIM::Deploy::Mksysb::ImageData::num_disks()\n"; my @disk_names = $this->vg_disk_names(); my $rc = ($#disk_names >= 0) ? ($#disk_names + 1) : 0; log_print"\trc = $rc\n"; return $rc; } #------------------------------------------------------------------------------- sub image_size { my $this = shift; log_print "NIM::Deploy::Mksysb::ImageData::image_size()\n"; my $rc = bint(0); my @disk_names = $this->vg_disk_names(); foreach my $disk_name (@disk_names) { $rc += $this->disk_size($disk_name); } log_printf("\trc = %s\n", $rc->bstr()); return $rc; } #------------------------------------------------------------------------------- sub lps_to_fs_size { my $this = shift; my ($lps, $lv_data) = @_; # FS_SIZE = (# of 512 blocks) = PP_SIZE * (# of 512 blocks per PP) * LPs * (PPs / LPs) # size in bytes = FS_SIZE * (512 bytes / block) my $fs_size = bint(0); eval { $fs_size = (bint($lv_data->{'PP_SIZE'}) * 1024) * 2 * $lps * ($lv_data->{'PP'} / $lv_data->{'LPs'}); }; return ($@ ? bint(0) : $fs_size); } #------------------------------------------------------------------------------- sub lps_to_size { my $this = shift; my ($lps, $lv_data) = @_; # size in bytes = FS_SIZE * (512 bytes / block) return ($this->lps_to_fs_size($lps, $lv_data) * 512); } #------------------------------------------------------------------------------- sub allocated_size # includes all logical volumes { my $this = shift; log_print "NIM::Deploy::Mksysb::ImageData::allocated_size()\n"; my $rc = bint(0); eval { foreach my $lv_data (@{$this->{'content'}->{'lv_data'}}) { log_print("\tprocessing logical volume $lv_data->{'LOGICAL_VOLUME'}\n"); log_print("\tLPs = $lv_data->{'LPs'}\n"); my $size = $this->lps_to_size($lv_data->{'LPs'}, $lv_data); log_printf("\tsize = %s\n", $size->bstr()); $rc += $size; } }; $rc = ($@ ? bint(0) : $rc); log_printf("\trc = %s\n", $rc->bstr()); return $rc; } #------------------------------------------------------------------------------- sub unallocated_size # includes all logical volumes { my $this = shift; log_print "NIM::Deploy::Mksysb::ImageData::unallocated_size()\n"; my $rc = $this->image_size() - $this->allocated_size(); log_printf("\trc = %s\n", $rc->bstr()); return $rc; } #------------------------------------------------------------------------------- sub free_space_size { my $this = shift; my ($min_lp_delta) = @_; if (! defined $min_lp_delta) { $min_lp_delta = 0; } log_print "NIM::Deploy::Mksysb::ImageData::free_space_size(\'$min_lp_delta\')\n"; my $rc = bint(0); eval { foreach my $lv_data (@{$this->{'content'}->{'lv_data'}}) { if ($lv_data->{'FS_TAG'}) { log_print "\tprocessing logical volume $lv_data->{'LOGICAL_VOLUME'}\n"; log_print "\tLPs = $lv_data->{'LPs'} / LV_MIN_LPS = $lv_data->{'LV_MIN_LPS'}\n"; if (($lv_data->{'LPs'} - $lv_data->{'LV_MIN_LPS'}) > $min_lp_delta) { my $fs_free_space = $this->lps_to_size($lv_data->{'LPs'} - ($lv_data->{'LV_MIN_LPS'} + $min_lp_delta), $lv_data); $rc += $fs_free_space; log_printf("\tfree space = %s\n", $fs_free_space->bstr()); } } } }; $rc = ($@ ? bint(0) : $rc); log_printf("\trc = %s\n", $rc->bstr()); return $rc; } #------------------------------------------------------------------------------- sub set_min_free_space_lps_per_filesystem { my $this = shift; my ($min_lp_delta) = @_; # $min_lp_delta is the required free space LPs available per filesystem logical volume log_print "NIM::Deploy::Mksysb::ImageData::set_min_free_space_lps_per_filesystem(\'$min_lp_delta\')\n"; eval { foreach my $lv_data (@{$this->{'content'}->{'lv_data'}}) { if ($lv_data->{'FS_TAG'}) { my $lv_name = $lv_data->{'LOGICAL_VOLUME'}; log_print "\tprocessing logical volume: $lv_name\n"; log_print "\tLPs = $lv_data->{'LPs'} / LV_MIN_LPS = $lv_data->{'LV_MIN_LPS'}\n"; my $lv_min_lps = $lv_data->{'LV_MIN_LPS'} + $min_lp_delta; if ($lv_data->{'LPs'} < $lv_min_lps) { if ($lv_min_lps > $lv_data->{'MAX_LPS'}) { $lv_min_lps = $lv_data->{'MAX_LPS'}; } my $lps = $lv_min_lps; my $pps = $lps * $lv_data->{'PP'} / $lv_data->{'LPs'}; $lv_data->{'LPs'} = $lps; $lv_data->{'PP'} = $pps; log_print "\tsetting LPs = $lps / PP = $pps\n"; my $pp_size = $lv_data->{'PP_SIZE'} * 1024; foreach my $fs_data (@{$this->{'content'}->{'fs_data'}}) { if ($fs_data->{'FS_LV'} eq "/dev/$lv_name") { log_print "\tprocessing filesystem: /dev/$lv_name\n"; log_print "\tFS_SIZE = $fs_data->{'FS_SIZE'}\n"; my $fs_size = bint($pps) * $pp_size; $fs_size *= 2; # fs_size == number of 512-byte blocks, 2 per pp $fs_data->{'FS_SIZE'} = $fs_size; log_printf("\tsetting FS_SIZE = %s\n", $fs_size->bstr()); last; } } } } } } } #------------------------------------------------------------------------------- sub scale_fs_down { my $this = shift; my ($target_size_mb, $min_lp_delta) = @_; # $min_lp_delta is the desired free space LPs available per filesystem logical volume log_printf("NIM::Deploy::Mksysb::ImageData::scale_fs_down(\'%llu MB\', \'$min_lp_delta\')\n", $target_size_mb); my $target_size = bint($target_size_mb) * 1024 * 1024; my $alloced_size = $this->allocated_size(); my $reduce_amount = ($alloced_size > $target_size) ? ($alloced_size - $target_size) : bint(0); log_printf("\ttargeted reduction amount = %s (%s - %s)\n", $reduce_amount->bstr(), $alloced_size->bstr(), $target_size->bstr()); if ($reduce_amount > 0) { if ($this->num_disks() == 1) { if (! $min_lp_delta) { $min_lp_delta = 4; } my $free_space = $this->free_space_size($min_lp_delta); if ($free_space > 0) { if ($reduce_amount <= $free_space) { my $reduce_percent = ($reduce_amount * 100) / $free_space; if (($reduce_amount * 100) % $free_space) { $reduce_percent++; } log_print "\treduce percent = $reduce_percent\n"; my $percent = 100 - $reduce_percent; eval { my $freed_bytes = bint(0); foreach my $lv_data (@{$this->{'content'}->{'lv_data'}}) { if ($lv_data->{'FS_TAG'}) { my $lv_name = $lv_data->{'LOGICAL_VOLUME'}; log_print "\tprocessing logical volume: $lv_name\n"; log_print "\tLPs = $lv_data->{'LPs'} / LV_MIN_LPS = $lv_data->{'LV_MIN_LPS'}\n"; my $lv_min_lps = $lv_data->{'LV_MIN_LPS'} + $min_lp_delta; if ($lv_data->{'LPs'} > $lv_min_lps) { my $free_lps = ($percent * ($lv_data->{'LPs'} - $lv_min_lps)) / 100; my $lps = $lv_min_lps + $free_lps; my $pps = $lps * $lv_data->{'PP'} / $lv_data->{'LPs'}; my $lv_freed_bytes = $this->lps_to_size($lv_data->{'LPs'} - $lv_min_lps - $free_lps, $lv_data); $freed_bytes += $lv_freed_bytes; $lv_data->{'LPs'} = $lps; $lv_data->{'PP'} = $pps; log_print "\tsetting LPs = $lps / PP = $pps\n"; my $pp_size = $lv_data->{'PP_SIZE'} * 1024; foreach my $fs_data (@{$this->{'content'}->{'fs_data'}}) { if ($fs_data->{'FS_LV'} eq "/dev/$lv_name") { log_print "\tprocessing filesystem: /dev/$lv_name\n"; log_print "\tFS_SIZE = $fs_data->{'FS_SIZE'}\n"; my $fs_size = bint($pps) * $pp_size; $fs_size *= 2; # fs_size == number of 512-byte blocks, 2 per pp $fs_data->{'FS_SIZE'} = $fs_size; log_printf("\tsetting FS_SIZE = %s\n", $fs_size->bstr()); last; } } } } } log_printf("\tactual reduction amount = %s\n", $freed_bytes->bstr()); # my $source_disk = $this->{'content'}->{'source_disk_data'}->[0]; # $source_disk->{'SIZE_MB'} = $this->allocated_size() / (1024 * 1024); }; } elsif ($reduce_amount > $free_space) { log_print "\tthe reduction amount required is larger than the available free space\n"; # $this->{'content'}->{'logical_volume_policy'}->[0]->{'SHRINK'} = 'yes'; } } else { log_print "\tno free space available for reduction\n"; } } else { log_print "\tmore than one disk specified in the image.data file - no action performed\n"; } } else { log_print "\ttarget size is already large enough to contain the logical volume sizes\n"; } } #------------------------------------------------------------------------------- sub shrink_size { my $this = shift; log_print "NIM::Deploy::Mksysb::ImageData::shrink_size()\n"; my $rc = bint(0); eval { foreach my $lv_data (@{$this->{'content'}->{'lv_data'}}) { $rc += $this->lps_to_size($lv_data->{'LV_MIN_LPS'}, $lv_data); } }; $rc = ($@ ? bint(0) : $rc); log_printf("\trc = %s\n", $rc->bstr()); return $rc; } #------------------------------------------------------------------------------- sub paging_space_size { my $this = shift; log_print "NIM::Deploy::Mksysb::ImageData::paging_space_size()\n"; my $rc = bint(0); eval { foreach my $lv_data (@{$this->{'content'}->{'lv_data'}}) { if ($lv_data->{'TYPE'} eq 'paging') { $rc += $this->lps_to_size($lv_data->{'LPs'}, $lv_data); # last; } } }; $rc = ($@ ? bint(0) : $rc); log_printf("\trc = %s\n", $rc->bstr()); return $rc; } #------------------------------------------------------------------------------- sub num_paging_space { my $this = shift; log_print "NIM::Deploy::Mksysb::ImageData::num_paging_space()\n"; my $rc = 0; eval { foreach my $lv_data (@{$this->{'content'}->{'lv_data'}}) { if ($lv_data->{'TYPE'} eq 'paging') { $rc++; } } }; $rc = ($@ ? 0 : $rc); log_printf("\trc = %d\n", $rc); return $rc; } #------------------------------------------------------------------------------- sub resize_paging_space { my $this = shift; my ($target_size_mb) = @_; log_printf("NIM::Deploy::Mksysb::ImageData::resize_paging_space(\'%llu MB\')\n", $target_size_mb); my $target_size = bint($target_size_mb) * 1024 * 1024; my $num_ps = $this->num_paging_space(); my $ps_size = $this->paging_space_size(); my $divided_ps_size = $target_size / $num_ps; if ($divided_ps_size <= 0) { $divided_ps_size = bint(1); } log_printf("\teach paging space size = %s\n", $divided_ps_size->bstr()); eval { foreach my $lv_data (@{$this->{'content'}->{'lv_data'}}) { if ($lv_data->{'TYPE'} eq 'paging') { my $pp_size = $lv_data->{'PP_SIZE'} * 1024; my $pp_lp_ratio = $lv_data->{'PP'} / $lv_data->{'LPs'}; # account for mirroring my $lp_size = $pp_size * $pp_lp_ratio; $lp_size *= 2; # fs_size == number of 512-byte blocks, 2 per pp $lp_size *= 512; # size in bytes my $lps = $divided_ps_size / $lp_size; if ($lv_data->{'MAX_LPS'} < $lps) { $lps = $lv_data->{'MAX_LPS'}; } if ($lps < $lv_data->{'LV_MIN_LPS'}) { $lps = $lv_data->{'LV_MIN_LPS'}; } my $pps = $lps * $pp_lp_ratio; $lv_data->{'LPs'} = $lps; $lv_data->{'PP'} = $pps; log_print("\tresizing paging space: $lv_data->{'LOGICAL_VOLUME'}\n"); log_printf("\tnew paging space size = %s\n", $divided_ps_size->bstr()); log_print("\tLPs = $lps\n"); log_print("\tPPs = $pps\n"); } } }; my $comment = q { my $ps_delta = $this->paging_space_size() - $ps_size; if ($ps_delta > 0) { my $ps_delta_mb = $ps_delta / (1024 * 1024); if ($ps_delta % (1024 * 1024)) { $ps_delta_mb++; } foreach my $source_disk (@{$this->{'content'}->{'source_disk_data'}}) { $source_disk->{'SIZE_MB'} += $ps_delta_mb; log_print("\tresizing $source_disk->{'HDISKNAME'} disk to $source_disk->{'SIZE_MB'} MB\n"); } } }; } #------------------------------------------------------------------------------- sub set_default_image_data_values { my $this = shift; my ($shrink, $exact_fit) = @_; log_print "NIM::Deploy::Mksysb::ImageData::set_default_image_data_values(\'$shrink\', \'$exact_fit\')\n"; if (! $shrink) { $shrink = 'no'; } if (! $exact_fit) { $exact_fit = 'no'; } foreach my $lv_policy (@{$this->{'content'}->{'logical_volume_policy'}}) { $lv_policy->{'SHRINK'} = $shrink; $lv_policy->{'EXACT_FIT'} = $exact_fit; } } 1; # __END__ =head1 AUTHOR IBM =head1 BUGS Please report any bugs to the L. =head1 SUPPORT =head1 ACKNOWLEDGEMENTS =head1 SEE ALSO =begin html =end html =cut