Rev 287 | Blame | Compare with Previous | Last modification | View Log | RSS feed
#!/usr/local/bin/perl -wrequire 5.8.2;use Getopt::Std;use DeployUtils::Logger;use vars qw ( $opt_l $opt_h $opt_a $opt_A $opt_d $opt_D $opt_y );getopts('l:haAdDy');help() if ( defined($opt_h) );help("Must supply nodespec file & new version number as args") if ( !defined($ARGV[0]) || !defined($ARGV[1]) );help("Cant use -a & -A together") if ( defined($opt_a) && defined($opt_A) );help("Cant use -d & -D together") if ( defined($opt_d) && defined($opt_D) );setLogLevel($opt_l) if ( defined($opt_l) );my $ver = shift;my $retval;while ( my $nsfile = shift ){$retval = pkgmnt::init($ver, $nsfile,(defined($opt_d)) ? "NO" : (defined($opt_D)) ? "YES" : "ASK",(defined($opt_a)) ? "NO" : (defined($opt_A)) ? "YES" : "ASK",(defined($opt_y)) ? 1 : 0 );$retval = pkgmnt::getNodeSpecFromDM() if ( $retval );if ( $retval ){pkgmnt::checkForDeleted();pkgmnt::checkForNew();pkgmnt::mergeHashs();$retval = pkgmnt::updateNodeSpecFile();}LogError("-x", "Unable to process Nodespec file [$nsfile]") if ( ! $retval );}sub help{my $error = shift;my $usage = qq(updateNodeSpec.pl [-l N] [-d|-D] [-a|-A] [-y] NewVersion nodespecfilewhereNewVersion : The new BOM version for the nodespec file.nodespecfile : Specifies the nodespec file to update.Options:-l : Sets log level 1-5-d : Dont Automatically Delete packages from nodespec file if DM does not have them.-D : Do Automatically Delete packages from nodespec file if DM does not have them.: DEFAULT if neither supplied is to interactively ask for each package.-a : Dont Automatically Add new packages from DM into nodespec file.-A : Do Automatically Add new packages from DM into nodespec file.: DEFAULT if neither supplied is to interactively ask for each package.-y : Automatically answer yes to final Update nodespec file question.);print "$error\n" if ( defined $error );print $usage;exit 1;}#============================================================================package pkgmnt;use strict;use DBI;use Data::Dumper;use DeployUtils::Logger;use JatsRmApi;our ($G_NodeSBOMVersion, $G_NodeName, %G_NodeProcessHash, %G_NodePkgHash, %G_NodeDmInfo);our %newPkgs;our ( @actionlog, $actions );our $nodeSpecFile;our ( $newVer, $bomver, $lifecycle );our ( $autoDelete, $autoAdd, $autoUpdate );sub init{( $newVer, $nodeSpecFile, $autoDelete, $autoAdd, $autoUpdate ) = @_;LogNorm("");LogNorm("");LogNorm("Upgrading NodeSpec file [$nodeSpecFile] to $newVer");if ( ! -f $nodeSpecFile ){LogError("-x", "Nodespec file [$nodeSpecFile] does not exist");return 0;}# version must start & end with numbers and contain numbers & '.' in betweenif ( $newVer =~ /^[0-9]+[0-9\.]*[0-9]+$/ ){# split version number into number sectionsmy @verNums = split(/\./, "$newVer");#last section is the lifecycle number so remove from list$lifecycle = pop(@verNums);#now join rest of numbers$bomver = join(".", @verNums);}else{LogError("-x", "Version number format incorrect, must contain digits & '.' eg (1.2 or 1.1.2)");return 0;}$autoDelete = uc $autoDelete;$autoAdd = uc $autoAdd;if ( $autoDelete ne "YES" && $autoDelete ne "NO" && $autoDelete ne "ASK" ){LogError("-x", "autoDelete flag must be YES, NO or ASK");return 0;}if ( $autoAdd ne "YES" && $autoAdd ne "NO" && $autoAdd ne "ASK" ){LogError("-x", "autoAdd flag must be YES, NO or ASK");return 0;}$Data::Dumper::Purity = 1;$Data::Dumper::Quotekeys = 0;$Data::Dumper::Sortkeys = 1;$Data::Dumper::Indent = 1;$G_NodeSBOMVersion = "";$G_NodeName = "";%G_NodeProcessHash = ( );%G_NodePkgHash = ( );%G_NodeDmInfo = ( );%newPkgs = ( );$#actionlog = -1;$actions = 0;# require the nodespk file to get detailsrequire $nodeSpecFile;if ( ! defined($G_NodeDmInfo{ProjectName}) && ! defined($G_NodeDmInfo{BranchName}) &&! defined($G_NodeDmInfo{BomName}) && ! defined($G_NodeDmInfo{NodeName}) &&! defined($G_NodeDmInfo{OsName}) ){LogError("-x", "G_NodeDmInfo hash in nodespec does not have enough info");return 0;}LogInfo("ProjectName : $G_NodeDmInfo{ProjectName}");LogInfo("BranchName : $G_NodeDmInfo{BranchName}");LogInfo("BomName : $G_NodeDmInfo{BomName}");LogInfo("NodeName : $G_NodeDmInfo{NodeName}");LogInfo("OsName : $G_NodeDmInfo{OsName}");return 1;}sub getNodeSpecFromDM{my $DM;connectDM( \$DM );my ($m_sqlstr ) = qq /SELECT oc.prod_id, pkg.pkg_name, pv.pkg_version, pv.pv_description, pv.v_ext, pv.is_patchFROM deployment_manager.dm_projects dm_,deployment_manager.branches branches,deployment_manager.boms boms,deployment_manager.bom_names bom,deployment_manager.network_nodes net,deployment_manager.bom_contents bomcont,deployment_manager.operating_systems ope,deployment_manager.os_contents oc,release_manager.package_versions pv,release_manager.PACKAGES pkgWHERE ( (dm_.proj_id = branches.proj_id) AND (branches.branch_id = boms.branch_id) AND(bom.bom_name_id = boms.bom_name_id) AND (boms.bom_id = bomcont.bom_id) AND(net.node_id = bomcont.node_id) AND (net.node_id = ope.node_id) AND(ope.os_id = oc.os_id) AND (oc.prod_id = pv.pv_id) AND (pv.pkg_id = pkg.pkg_id) AND(dm_.proj_name = '$G_NodeDmInfo{ProjectName}') AND(branches.branch_name = '$G_NodeDmInfo{BranchName}') AND(bom.bom_name = '$G_NodeDmInfo{BomName}') AND(boms.bom_version = '$bomver') AND(boms.bom_lifecycle = '$lifecycle') AND(net.node_name = '$G_NodeDmInfo{NodeName}') AND(ope.os_name = '$G_NodeDmInfo{OsName}'))/;my ($sth ) = $DM->prepare($m_sqlstr);my @row;my $found = 0;LogDebug("Executing SQL statement\n$m_sqlstr");if ( defined($sth) ){if ( $sth->execute() ){if ( $sth->rows ){while ( @row = $sth->fetchrow_array ){# Skip Patchesif ( !defined($row[5]) || $row[5] !~ /y/i ){# if extension definedif ( defined($row[4]) ){# remove dot from start of extension$row[4] =~ s/^\.//;# remove extension from versionif ( $row[2] =~ /\.$row[4]$/ ){$row[2] =~ s/\.$row[4]$//;}else{LogWarn("Pkg [$row[1]] version [$row[2]] & extension [$row[4]] do not match");}}else{$row[4] = "";}$row[3] = "" if ( ! defined($row[3]) );chomp $row[3];# if pkg version defined in _Forceversion then we force the versionif ( defined($G_NodeDmInfo{_ForceVersion}{$row[1]}) && defined($G_NodeDmInfo{_ForceVersion}{$row[1]}{$row[2]})){LogDebug("Forcing pkg [$row[1]] from version [$row[2]] to [$G_NodeDmInfo{_ForceVersion}{$row[1]}{$row[2]}]");$newPkgs{$row[1]}{PkgVersion} = $G_NodeDmInfo{_ForceVersion}{$row[1]}{$row[2]};}else{$newPkgs{$row[1]}{PkgVersion} = $row[2];}$newPkgs{$row[1]}{PkgProjAcronym} = $row[4];$newPkgs{$row[1]}{PkgDesc} = $row[3];$found = 1;LogDebug("Found DM Pkg [$row[1]], ver [$row[2]], proj [$row[4]], desc [$row[3]]");}}}if ( ! $found ){LogError("-x", "Found No Information about node in Deployment Manager");return 0;}$sth->finish();}else{LogError("-x", "Unable to execute SQL statement in DBI");return 0;}}else{LogError("-x", "Unable to prepare SQL statement in DBI");return 0;}disconnectDM(\$DM);return 1;}sub checkForDeleted{foreach my $i ( keys %G_NodePkgHash ){# if pkg not defined in newPkgs from DM AND its not in the NoDelete List then we ask or process# that is is pkg is not in DM but it is in NoDelete list then we keep it as if it wasif ( ! defined($newPkgs{$i}) && ! defined($G_NodeDmInfo{_NoDelete}{$i}) ){# ask if neither -d or -D setmy $ans = "";$ans = askYN("Pkg [$i] is not in new list, remove") if ( $autoDelete eq "ASK" );# if -d defined or asn = N then we dont delete so just logif ( $autoDelete eq "NO" || $ans eq "N" ){push(@actionlog, "KEEP Old Pkg [$i]: Version [$G_NodePkgHash{$i}{PkgVersion}] Project [$G_NodePkgHash{$i}{PkgProjAcronym}] from original Nodespec");# keeping an old package is not a real action, as nothing changes in nodespec}# if -D defined or ans = Y then deleteelsif ( $autoDelete eq "YES" || $ans eq "Y" ){push(@actionlog, "DELETE Old Pkg [$i]: Version [$G_NodePkgHash{$i}{PkgVersion}] Project [$G_NodePkgHash{$i}{PkgProjAcronym}] from original Nodespec");delete($G_NodePkgHash{$i});$actions++;}}}}sub checkForNew{foreach my $i ( keys %newPkgs ){if ( ! defined($G_NodePkgHash{$i}) ){# if pkg is defined in noAdd list then we just remove, otherwise process as normalif ( defined($G_NodeDmInfo{_NoAdd}{$i}) ){delete($newPkgs{$i});}else{# ask if neither -d or -D setmy $ans = "";$ans = askYN("Pkg [$i] has been added, add") if ( $autoAdd eq "ASK" );# if -A defined or ans = Y then we add so just logif ( $autoAdd eq "YES" || $ans eq "Y" ){push(@actionlog, "ADD New Pkg [$i]: Version [$newPkgs{$i}{PkgVersion}] Project [$newPkgs{$i}{PkgProjAcronym}] from Deployment Manager");$actions++;}# if -a defined then dont Add (remove from dm list), otherwise askelsif ( $autoAdd eq "NO" || $ans eq "N" ){push(@actionlog, "SKIP New Pkg [$i]: Version [$newPkgs{$i}{PkgVersion}] Project [$newPkgs{$i}{PkgProjAcronym}] from Deployment Manager");delete($newPkgs{$i});# deleting a new package is not a real action, as nothing changes in nodespec}}}}}sub mergeHashs{my $str;my $updated;foreach my $i ( keys %newPkgs ){if ( defined($G_NodePkgHash{$i}) ){$str = "UPDATE Pkg [$i]: ";$updated = 0;if ( $newPkgs{$i}{PkgVersion} ne $G_NodePkgHash{$i}{PkgVersion} ){$str .= "Version [$G_NodePkgHash{$i}{PkgVersion}]=>[$newPkgs{$i}{PkgVersion}] ";$updated = 1;$G_NodePkgHash{$i}{PkgVersion} = $newPkgs{$i}{PkgVersion};}if ( ($newPkgs{$i}{PkgProjAcronym} || '') ne ($G_NodePkgHash{$i}{PkgProjAcronym} || '') ){$str .= "Project [$G_NodePkgHash{$i}{PkgProjAcronym}]=>[$newPkgs{$i}{PkgProjAcronym}] ";$updated = 1;if ( $newPkgs{$i}{PkgProjAcronym} ){$G_NodePkgHash{$i}{PkgProjAcronym} = $newPkgs{$i}{PkgProjAcronym};}else{delete $G_NodePkgHash{$i}{PkgProjAcronym};}}if ( $newPkgs{$i}{PkgDesc} ne $G_NodePkgHash{$i}{PkgDesc} ){$str .= "Description [$G_NodePkgHash{$i}{PkgDesc}]=>[$newPkgs{$i}{PkgDesc}] ";$updated = 1;$G_NodePkgHash{$i}{PkgDesc} = $newPkgs{$i}{PkgDesc};}if ( $updated ){push(@actionlog, $str);$actions++;}}else{$G_NodePkgHash{$i}{PkgVersion} = $newPkgs{$i}{PkgVersion};$G_NodePkgHash{$i}{PkgProjAcronym} = $newPkgs{$i}{PkgProjAcronym};$G_NodePkgHash{$i}{PkgDesc} = $newPkgs{$i}{PkgDesc};$G_NodePkgHash{$i}{ERGPkgFlag} = "T";$G_NodePkgHash{$i}{CheckVersionFlag} = "T";# no need to log as its already done}}}sub updateNodeSpecFile{my ( $buffer, $line );LogNorm("--------------------------------------------------------------------");if ( $G_NodeSBOMVersion eq $newVer && $actions == 0 ){LogNorm("NO ACTIONS will be performed on the nodespec file [$nodeSpecFile]");LogNorm("--------------------------------------------------------------------");}else{LogNorm("The Following actions will be performed on the nodespec file [$nodeSpecFile]");LogNorm("UPDATE BOM version from $G_NodeSBOMVersion to $newVer");foreach my $i ( sort @actionlog ){LogNorm($i);}LogNorm("--------------------------------------------------------------------");if ( $autoUpdate || askYN("Update nodespec file as described ") eq "Y" ){# read all comment lines up to first comment lineif ( ! open(NODESPEC, "<$nodeSpecFile") ){LogError("-x", "Unable to open Node Spec File to update");return 0;}do{$line = <NODESPEC>;$line =~ s/\r\n/\n/;$buffer .= $line if ( $line =~ /^#/ );}while ( $line =~ /^#/ );close NODESPEC;# now lets update the fileif ( ! open(NODESPEC, ">$nodeSpecFile") ){LogError("-x", "Unable to open Node Spec File to update");return 0;}binmode(NODESPEC);print NODESPEC "$buffer\n";# Dumper prints hashes as references ie $hash = { .... };# Where the original nodespec files were real hashes ie %hash = ( .... );# So we dump hashes to buffer and replace the first line with real hash & (# and replace last line }; with );$buffer = Data::Dumper->Dump([ \%G_NodeDmInfo ], [ "pkgmnt::G_NodeDmInfo" ]);$buffer =~ s/^\$(pkgmnt::G_NodeDmInfo *= *)\{(.*)\}(.*)$/\%$1\($2\)$3/ms;print NODESPEC "$buffer\n";print NODESPEC Data::Dumper->Dump([ $newVer ], [ "pkgmnt::G_NodeSBOMVersion" ]) . "\n";print NODESPEC Data::Dumper->Dump([ $G_NodeName ], [ "pkgmnt::G_NodeName" ]) . "\n";$buffer = Data::Dumper->Dump([ \%G_NodeProcessHash], [ "pkgmnt::G_NodeProcessHash" ]);$buffer =~ s/^\$(pkgmnt::G_NodeProcessHash *= *)\{(.*)\}(.*)$/\%$1\($2\)$3/ms;print NODESPEC "$buffer\n";$buffer = Data::Dumper->Dump([ \%G_NodePkgHash ], [ "pkgmnt::G_NodePkgHash" ]);$buffer =~ s/^\$(pkgmnt::G_NodePkgHash *= *)\{(.*)\}(.*)$/\%$1\($2\)$3/ms;print NODESPEC "$buffer\n1;\n";close NODESPEC;LogNorm("Updated nodespec file $nodeSpecFile");}}return 1;}sub askYN{use Term::ReadKey;my $msg = shift;$msg .= " [ynq] ? ";my $ch = "";my $rMode = 0;while ( $ch ne "Y" && $ch ne "N" ){LogNorm("-n", $msg);#$ch = uc HotKey::readkey();eval { ReadMode('cbreak'); $rMode = 1 }; # do in eval because it barfs on cygwin term$ch = uc ReadKey(0);eval { ReadMode('normal') };chomp $ch;if ( $rMode ){print "\n";}else{# if not rMode then a CR needs to be entered so lets remove it.my $a = <STDIN>;}LogError("Quitting application") if ( $ch eq "Q" );}return $ch;}1;#============================================================================# HotKey.pm#package HotKey;#use strict;#use POSIX qw(:termios_h);#my ($term, $oterm, $echo, $noecho, $fd_stdin);#BEGIN {#$fd_stdin = fileno(STDIN);#$term = POSIX::Termios->new();#$term->getattr($fd_stdin);#$oterm = $term->getlflag();#$echo = ECHO | ECHOK | ICANON;#$noecho = $oterm & ~$echo;#}#sub cbreak {# $term->setlflag($noecho); # ok, so i don't want echo either# $term->setcc(VTIME, 1);# $term->setattr($fd_stdin, TCSANOW);#}#sub cooked {# $term->setlflag($oterm);# $term->setcc(VTIME, 0);# $term->setattr($fd_stdin, TCSANOW);#}#sub readkey {# my $key = '';# cbreak();# sysread(STDIN, $key, 1);# cooked();# return $key;#}#END { cooked() }#1;