mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-31 03:12:30 +00:00 
			
		
		
		
	- zvmdiscovery plugin will not handle findme - not change request if no temp discovered bmc nodes, to avoid the confusing error message - add more logs, and ignore the `ipmitool sol info` error output
		
			
				
	
	
		
			2319 lines
		
	
	
		
			89 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			2319 lines
		
	
	
		
			89 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
| #!/usr/bin/env perl
 | |
| ## IBM(c) 2015 EPL license http://www.eclipse.org/legal/epl-v10.html
 | |
| #
 | |
| # This plugin is used to handle the z/VM discovery. 
 | |
| # z/VM discovery will discover the z/VM virtual machines running
 | |
| # on a specified z/VM host and define them to xCAT DB.
 | |
| # In addition, it will optionally define the systems to OpenStack.
 | |
| #
 | |
| 
 | |
| package xCAT_plugin::zvmdiscovery;
 | |
| BEGIN
 | |
| {
 | |
|     $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
 | |
| }
 | |
| 
 | |
| use strict;
 | |
| use Data::Dumper;
 | |
| use Getopt::Long;
 | |
| use XML::Simple;
 | |
| $XML::Simple::PREFERRED_PARSER='XML::Parser';
 | |
| 
 | |
| use lib "$::XCATROOT/lib/perl";
 | |
| use Time::HiRes qw(gettimeofday sleep);
 | |
| use xCAT::Table;
 | |
| use xCAT::MsgUtils;
 | |
| use xCAT::DiscoveryUtils;
 | |
| use xCAT::Utils;
 | |
| use xCAT::zvmCPUtils;
 | |
| use xCAT::zvmUtils;
 | |
| 
 | |
| my $request_command;
 | |
| ( $::SUDOER, $::SUDO ) = xCAT::zvmUtils->getSudoer();
 | |
| my $ZHCP_BIN = '/opt/zhcp/bin';
 | |
| 
 | |
| # Hash of host name resolution commands to be issued in a virtual OS.
 | |
| my @hostnameCmds = ( 'hostname --fqdn', 
 | |
|                      'hostname --long',
 | |
|                      'hostname',
 | |
|                    );
 | |
| 
 | |
| # Location of the various OpenStack plugins for discovery.
 | |
| my $locOpenStackDiscovery = '/var/lib/sspmod/discovery.py';         # location of OpenStack discovery
 | |
| my $locOpenStackNodeNameInfo = '/var/lib/sspmod/nodenameinfo.py';   # location of OpenStack node name info
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3   addOpenStackSystem
 | |
| 
 | |
|     Description : Add a single system to OpenStack.
 | |
|     Arguments   : class
 | |
|                   callback
 | |
|                   z/VM host node
 | |
|                   verbose flag: 1 - verbose output, 0 - non-verbose
 | |
|                   UUID generated for this node to be used in the discoverydata table
 | |
|                   z/VM userid of the discovered system
 | |
|                   Reference to the discoverable hash variable
 | |
|     Returns     : Node as provisioned in OpenStack or an empty string if it failed.
 | |
|     Example     : my $OSnode = addOpenStackSystem( $callback,
 | |
|                     $zvmHost, $hcp, $verbose, $activeSystem, $discoverableRef );
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub addOpenStackSystem {
 | |
|     my ( $callback, $zvmHost, $hcp, $verbose, $activeSystem, $discoverableRef ) = @_;
 | |
|     my %discoverable = %$discoverableRef;
 | |
| 
 | |
|     my $junk;
 | |
|     my $openstackNodeName = '';
 | |
|     my $out = '';
 | |
|     my $rc = 0;
 | |
| 
 | |
|     # Argument mapping between xCAT and the OpenStack python code.
 | |
|     # Argument name is as known to xCAT is the key and the value is
 | |
|     # the argument name as it is known to the OpenStack python code.
 | |
|     my %passingArgs = (
 | |
|             'cpuCount'            => '--cpucount',
 | |
|             'hostname'            => '--hostname',
 | |
|             'ipAddr'              => '--ipaddr',
 | |
|             'memory'              => '--memory',
 | |
|             'node'                => '--guestname',
 | |
|             'os'                  => '--os',
 | |
|             'openstackoperands'   => '',
 | |
|             );
 | |
|     my $args = "";
 | |
| 
 | |
|     # Build the argument string for the OpenStack call.
 | |
|     foreach my $key ( keys %passingArgs ) {
 | |
|         if ( defined( $discoverable{$activeSystem}{$key} ) ) {
 | |
|             if ( $key ne '' ) {
 | |
|                 # Pass the key and the value.
 | |
|                 $args = "$args $passingArgs{$key} $discoverable{$activeSystem}{$key}";
 | |
|             } else {
 | |
|                 # When name of parm to pass is '', we just pass the value of the parm.
 | |
|                 # The name would only complicates things for the call because it contains multiple subparms.
 | |
|                 # We also remove any surrounding quotes or double quotes.
 | |
|                 $args = "$args $discoverable{$activeSystem}{$key}";
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     $args = "$args --verbose $verbose --zvmhost $zvmHost --uuid $discoverable{$activeSystem}{'uuid'}";
 | |
| 
 | |
|     # Call the python discovery command
 | |
|     if ( $verbose == 1 ) {
 | |
|         my $rsp;
 | |
|         push @{$rsp->{data}}, "Passing $discoverable{$activeSystem}{'node'} to OpenStack " .
 | |
|                               "for userid $activeSystem on z/VM $zvmHost with arguments: $args";
 | |
|         xCAT::MsgUtils->message("I", $rsp, $callback);
 | |
|     }
 | |
|     xCAT::MsgUtils->message( "S", "Calling $locOpenStackDiscovery for $discoverable{$activeSystem}{'node'} on $zvmHost" );
 | |
|     $out = `python $locOpenStackDiscovery $args`;
 | |
|     xCAT::MsgUtils->message( "S", "Returned from $locOpenStackDiscovery" );
 | |
| 
 | |
|     if ( $out ) {
 | |
|         chomp( $out );
 | |
| 
 | |
|         if ( $verbose == 1 ) {
 | |
|             my $rsp;
 | |
|             push @{$rsp->{data}}, $out;
 | |
|             xCAT::MsgUtils->message("I", $rsp, $callback);
 | |
|         }
 | |
| 
 | |
|         my @lines= split( /\n/, $out );
 | |
|         my (@createdLine) = grep( /Node\screated:/, @lines );
 | |
|         if ( @createdLine ) {
 | |
|             # Node created. Do not need to show any output from OpenStack.
 | |
|             ($junk, $openstackNodeName) = split( /:\s/, $createdLine[0], 2 );
 | |
|         } else {
 | |
|             # Node was not created.
 | |
|             my @failedLine = grep( /Node\screation\sfailed/, @lines );
 | |
|             if ( @failedLine ) {
 | |
|                 my $rsp;
 | |
|                 push @{$rsp->{data}}, "Unable to create the node " .
 | |
|                                       "in OpenStack.  xCAT node creation is being undone " .
 | |
|                                       "for $discoverable{$activeSystem}{'node'}.";
 | |
|                 if (( @lines > 1 ) && ( $verbose == 0 )) {
 | |
|                     # Had more then the "Node creation failed" line AND we have not
 | |
|                     # shown them (vebose == 0) so show all of the lines now.
 | |
|                     push @{$rsp->{data}}, "Response from the OpenStack plugin:";
 | |
|                     push @{$rsp->{data}}, @lines;
 | |
|                 }
 | |
|                 xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|             } else {
 | |
|                 my @alreadyCreatedLine = grep( /already\screated/, @lines );
 | |
|                 if ( @alreadyCreatedLine ) {
 | |
|                 	# The node is already known to OpenStack as an instance.  We will get
 | |
|                 	# the node name from the response in case OpenStack wants the xCAT node to
 | |
|                 	# be a different name.
 | |
|                 	($openstackNodeName) = $alreadyCreatedLine[0] =~ m/Node (.*) already created/;
 | |
|                 } else {
 | |
|                     my $rsp;
 | |
|                     push @{$rsp->{data}}, "Response from the Openstack plugin " .
 | |
|                                           "did not contain 'Node created:' or 'Node creation failed' " .
 | |
|                                           "or 'already created' string.  It is assumed to have failed.";
 | |
|                     if (( @lines > 1 ) && ( $verbose == 0 )) {
 | |
|                         # Had more then the "Node creation failed" line AND we have not
 | |
|                         # shown them (vebose == 0) so show all of the lines now.
 | |
|                         push @{$rsp->{data}}, "Response from the OpenStack plugin:";
 | |
|                         push @{$rsp->{data}}, @lines;
 | |
|                     }
 | |
|                     xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     } else {
 | |
|         my $rsp;
 | |
|         push @{$rsp->{data}}, "No response was received from the Openstack plugin.";
 | |
|         xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|     }
 | |
| 
 | |
|     # If the xCAT node was renamed by OpenStack then update xCAT to use the new node name
 | |
|     # so that the node names match.
 | |
|     if (( $openstackNodeName ne '' ) and ( $discoverable{$activeSystem}{'node'} ne $openstackNodeName )) {
 | |
|         if ( $verbose == 1 ) {
 | |
|             my $rsp;
 | |
|             push @{$rsp->{data}}, "Renaming the xCAT node $discoverable{$activeSystem}{'node'} " .
 | |
|                                   "to $openstackNodeName as requested by the OpenStack plugin.";
 | |
|             xCAT::MsgUtils->message("I", $rsp, $callback);
 | |
|         }
 | |
|         my $renameRC = changeNode( $callback,
 | |
|                                    $discoverable{$activeSystem}{'node'},
 | |
|                                    'r',
 | |
|                                    $openstackNodeName );
 | |
|         if ( $renameRC == 0 ) {
 | |
|             $discoverable{$activeSystem}{'node'} = $openstackNodeName;
 | |
|         } else {
 | |
|             $openstackNodeName = '';  # Want to undo the created xCAT node.
 | |
|             my $rsp;
 | |
|             push @{$rsp->{data}}, "Unable to rename the xCAT node $discoverable{$activeSystem}{'node'} " .
 | |
|                                   "to $openstackNodeName, as requested by the OpenStack plugin, " .
 | |
|                                   "rc: $renameRC";
 | |
|             xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|         }
 | |
|     }
 | |
| 
 | |
| FINISH_addOpenStackSystem:
 | |
|     return $openstackNodeName;
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3   addPrevDisc
 | |
| 
 | |
|     Description : Add previously discovered xCAT nodes
 | |
|                   to OpenStack. (Not done. Waiting for input from Emily)
 | |
|     Arguments   : class
 | |
|                   callback
 | |
|                   z/VM host node
 | |
|                   ZHCP node
 | |
|                   Time when discovery was started.  Used to determine if
 | |
|                   a stop was requested and then we were restarted.
 | |
|                   nodediscoverstart argument hash
 | |
|     Returns     : None.
 | |
|     Example     : my $out = addPrevDisc( $callback, $zvmHost,
 | |
|                                          $hcp, $initStartTime, \%args );
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub addPrevDisc {
 | |
|     my ( $callback, $zvmHost, $hcp, $initStartTime, $argsRef ) = @_;
 | |
| 
 | |
|     my %discoverable;
 | |
|     my @nodes;
 | |
|     my $rc = 0;
 | |
|     my $verbose = $argsRef->{'verbose'};
 | |
| 
 | |
|     # Get the list of discovered nodes from the 'zvm' table.
 | |
|     my $zvmTab = xCAT::Table->new("zvm");
 | |
|     if ( !$zvmTab ) {
 | |
|         my $rsp;
 | |
|         push @{$rsp->{data}}, "Could not open table: zvm.";
 | |
|         xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|         goto FINISH_addPrevDisc;
 | |
|     }
 | |
|     my @results = $zvmTab->getAttribs( { 'discovered'=>'1', 'hcp'=>$hcp }, ('userid', 'node') );
 | |
|     foreach my $id ( @results ) {
 | |
|         if ( $id->{'userid'} and $id->{'node'} ) {
 | |
|             $discoverable{$id->{'userid'}}{'node'} = $id->{'node'};
 | |
|             $discoverable{$id->{'userid'}}{'hcp'} = $hcp;
 | |
|         } else {
 | |
|             if ( $verbose == 1 ) {
 | |
|                 my $rsp;
 | |
|                 push @{$rsp->{data}}, "Node $id->{'node'} is missing 'userid' or 'node' property in the zvm table.";
 | |
|                 xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|             }
 | |
|          }
 | |
|     }
 | |
|     $zvmTab->close;
 | |
| 
 | |
|     if ( $verbose == 1 ) {
 | |
|         my @discoverableKeys = keys %discoverable;
 | |
|         my $discoverableCount = scalar( @discoverableKeys );
 | |
|         my $rsp;
 | |
|         push @{$rsp->{data}}, "$discoverableCount nodes have been previously discovered for $zvmHost.";
 | |
|         xCAT::MsgUtils->message( "I", $rsp, $callback );
 | |
|     }
 | |
| 
 | |
|     # Get the ip and hostname for each discovered node from the hosts table.
 | |
|     my $hostsTab = xCAT::Table->new('hosts');
 | |
|     if ( !$hostsTab ) {
 | |
|         my $rsp;
 | |
|         push @{$rsp->{data}}, "Could not open table: hosts.";
 | |
|         xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|         goto FINISH_addPrevDisc;
 | |
|     }
 | |
|     my %nodes;
 | |
|     my @attribs = ('node', 'ip', 'hostnames');
 | |
|     my @hosts = $hostsTab->getAllAttribs( @attribs );
 | |
|     foreach my $nodeRef ( @hosts ) {
 | |
|         my $node;
 | |
|         if ( $nodeRef->{'node'} ) {
 | |
|             $node = $nodeRef->{'node'};
 | |
|         } else {
 | |
|             next;
 | |
|         }
 | |
|         if ( $nodeRef->{'ip'} ) {
 | |
|             $nodes{$node}{'ip'} = $nodeRef->{'ip'};
 | |
|         } else {
 | |
|             next;
 | |
|         }
 | |
|         if ( $nodeRef->{'hostnames'} ) {
 | |
|             $nodes{$node}{'hostnames'} = $nodeRef->{'hostnames'};
 | |
|         } else {
 | |
|             # Don't have enough info, remove it from the nodes hash.
 | |
|             delete( @nodes{$node} );
 | |
|         }
 | |
|     }
 | |
|     $hostsTab->close;
 | |
| 
 | |
|     foreach my $activeSystem ( keys %discoverable ) {
 | |
|         my $node = $discoverable{$activeSystem}{'node'};
 | |
|         if ( $nodes{$node}{'ip'} ) {
 | |
|             $discoverable{$activeSystem}{'ipAddr'} = $nodes{$node}{'ip'};
 | |
|             $discoverable{$activeSystem}{'hostname'} = $nodes{$node}{'hostnames'};
 | |
|         } else {
 | |
|             # Don't have enough info, remove it from the discoverable hash.
 | |
|             delete( $discoverable{$activeSystem} );
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     # Get the OS info, memory, CPU count and UUID.
 | |
|     foreach my $activeSystem ( keys %discoverable ) {
 | |
|         # Verify that the virtual machine is currently running.
 | |
|         my $out = `ssh -q $::SUDOER\@$hcp $::SUDO $ZHCP_BIN/smcli "Image_Status_Query -T '$activeSystem'"`;
 | |
|         $rc = $? >> 8;
 | |
|         if ( $rc == 255 ) {
 | |
|             my $rsp;
 | |
|             push @{$rsp->{data}}, "z/VM discovery is unable to communicate with the zhcp server: $hcp";
 | |
|             xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|             delete( $discoverable{$activeSystem} );
 | |
|             next;
 | |
|         } elsif ( $rc == 1 ) {
 | |
|             if ( $verbose == 1 ) {
 | |
|                 my $rsp;
 | |
|                 push @{$rsp->{data}}, "ignoring: $activeSystem - virtual machine is not logged on";
 | |
|                 xCAT::MsgUtils->message("I", $rsp, $callback);
 | |
|             }
 | |
|             delete( $discoverable{$activeSystem} );
 | |
|             next;
 | |
|         } elsif ( $rc != 0 ) {
 | |
|             my $rsp;
 | |
|             push @{$rsp->{data}}, "An unexpected return code $rc was received from " .
 | |
|                                   "the zhcp server $hcp for an smcli Image_Status_Query " .
 | |
|                                   "request.  SMAPI servers may be unavailable.  " .
 | |
|                                   "Received response: $out";
 | |
| 
 | |
|             xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|             delete( $discoverable{$activeSystem} );
 | |
|             next;
 | |
|         }
 | |
| 
 | |
|         # Get the OS version from the OS.
 | |
|         my $os = xCAT::zvmUtils->getOsVersion( $::SUDOER, $discoverable{$activeSystem}{'node'}, $callback );
 | |
|         if ( $os ) {
 | |
|             $discoverable{$activeSystem}{'os'} = $os;
 | |
|         } else {
 | |
|             if ( $verbose == 1 ) {
 | |
|                 my $rsp;
 | |
|                 push @{$rsp->{data}}, "ignoring: $activeSystem - Unable to obtain OS version information from node $discoverable{$activeSystem}{'node'}";
 | |
|                 xCAT::MsgUtils->message( "I", $rsp, $callback );
 | |
|             }
 | |
|             delete( $discoverable{$activeSystem} );
 | |
|             next;
 | |
|         }
 | |
| 
 | |
|         # Install vmcp in the target system just in case no one has done that yet.
 | |
|         xCAT::zvmCPUtils->loadVmcp( $::SUDOER, $discoverable{$activeSystem}{'node'} );
 | |
| 
 | |
|         # Get the current memory from CP.
 | |
|         my $memory = xCAT::zvmCPUtils->getMemory( $::SUDOER, $discoverable{$activeSystem}{'node'} );
 | |
|         if ( $memory ) {
 | |
|             $discoverable{$activeSystem}{'memory'} = $memory;
 | |
|         } else {
 | |
|             my $rsp;
 | |
|             push @{$rsp->{data}}, "Could not obtain the current virtual machine memory size from node: $discoverable{$activeSystem}{'node'}";
 | |
|             xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|             delete( $discoverable{$activeSystem} );
 | |
|             next;
 | |
|         }
 | |
| 
 | |
|         # Get the current CPU count from CP.
 | |
|         my $cpuString = xCAT::zvmCPUtils->getCpu( $::SUDOER, $discoverable{$activeSystem}{'node'} );
 | |
|         if ( $cpuString ) {
 | |
|             my @cpuLines = split( /\n/, $cpuString );
 | |
|             $discoverable{$activeSystem}{'cpuCount'} = scalar( @cpuLines );
 | |
|         } else {
 | |
|             my $rsp;
 | |
|             push @{$rsp->{data}}, "Could not obtain the current virtual machine CPU count from node: $discoverable{$activeSystem}{'node'}";
 | |
|             xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|             delete( $discoverable{$activeSystem} );
 | |
|             next;
 | |
|         }
 | |
| 
 | |
|         $discoverable{$activeSystem}{'uuid'} = xCAT::Utils::genUUID();
 | |
|     }
 | |
| 
 | |
|     my $rsp;
 | |
|     if ( %discoverable ) {
 | |
|         if ( $verbose == 1 ) {
 | |
|             push @{$rsp->{data}}, "The following xCAT nodes are eligible for OpenStack only discovery:";
 | |
|         }
 | |
|     } else {
 | |
|         push @{$rsp->{data}}, "No xCAT nodes are eligible for OpenStack only discovery.";
 | |
|     }
 | |
|     foreach my $activeSystem ( keys %discoverable ) {
 | |
|         $discoverable{$activeSystem}{'openstackoperands'} = $argsRef->{'openstackoperands'};
 | |
|         if ( $verbose == 1 ) {
 | |
|             push @{$rsp->{data}}, "  $discoverable{$activeSystem}{'node'}";
 | |
|         }
 | |
|     }
 | |
|     if ( $rsp ) {
 | |
|         xCAT::MsgUtils->message("I", $rsp, $callback);
 | |
|     }
 | |
| 
 | |
|     foreach my $activeSystem ( keys %discoverable ) {
 | |
|         # Exit if we have been asked to stop discovery for this host.
 | |
|         my $startTime = getRunningDiscTimestamp( $callback, $zvmHost );
 | |
|         if ( $startTime != $initStartTime ) {
 | |
|             # Start time for this run is different from start time in the site table.
 | |
|             # User must have stopped and restarted discovery for this host.
 | |
|             # End now to let other discovery handle the work.
 | |
|             push @{$rsp->{data}}, "Stopping due to a detected stop request.";
 | |
|             xCAT::MsgUtils->message("I", $rsp, $callback);
 | |
|             goto FINISH_addPrevDisc;
 | |
|         }
 | |
| 
 | |
|         # Define the system to OpenStack
 | |
|         my $openstackNodeName = addOpenStackSystem( $callback, $zvmHost, $hcp, $verbose, $activeSystem, \%discoverable );
 | |
|         if ( $openstackNodeName ) {
 | |
|             updateDiscoverydata( $callback, 'add', $verbose, $zvmHost, $activeSystem, \%discoverable );
 | |
|         }
 | |
|     }
 | |
| 
 | |
| FINISH_addPrevDisc:
 | |
|     return;
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3   changeNode
 | |
| 
 | |
|     Description : Change an xCAT node.  The change can
 | |
|                   be a rename or a deletion of the node from
 | |
|                   the xCAT tables.
 | |
|     Arguments   : Callback handle
 | |
|                   node name
 | |
|                   Type of change:
 | |
|                     'r'  - rename the node name and redo makehosts
 | |
|                     'd'  - delete the node from xCAT tables and /etc/hosts
 | |
|                     'do' - delete the node from xCAT tables only, don't
 | |
|                            undo makehosts
 | |
|     Returns     : Return code
 | |
|                     0 - It worked
 | |
|                     1 - It failed
 | |
|     Example     : rc = changeNode( $callback, $nodeName, 'r', $newName );
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub changeNode {
 | |
|     my $callback = shift;
 | |
|     my $nodeName = shift;
 | |
|     my $changeType = shift;
 | |
|     my $newNode = shift;
 | |
|     
 | |
|     my $rc = 0;           # Assume everything works
 | |
|     my $retStrRef;
 | |
| 
 | |
|     # Remove the node from the /etc/hosts file
 | |
|     if (( $changeType eq 'r' ) or ( $changeType eq 'd' )) {
 | |
|         my $out = `/opt/xcat/sbin/makehosts -d $nodeName 2>&1`;
 | |
|         if ( $out ne '' ) {
 | |
|             my $rsp;
 | |
|             push @{$rsp->{data}}, "'makehosts -d' failed for $nodeName.  Node is still defined in xCAT MN's /etc/hosts file.  'makehosts' response: $out";
 | |
|             xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|             $rc = 1;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     # Remove the node.
 | |
|     if (( $changeType eq 'd' ) or ( $changeType eq 'do' )) {
 | |
|         my $retRef = xCAT::Utils->runxcmd({command => ['rmdef'], stdin=>['NO_NODE_RANGE'], arg => [ "-t", "node", "-o", $nodeName ]}, $request_command, 0, 2);
 | |
|         if ( $::RUNCMD_RC != 0 ) {
 | |
|             my $rsp;
 | |
|             $retStrRef = parse_runxcmd_ret($retRef);
 | |
|             push @{$rsp->{data}}, "Unable to remove node $nodeName from the xCAT tables.  rmdef response: $retStrRef->[1]";
 | |
|             push @{$rsp->{data}}, "-t". "node". "-o". $nodeName;
 | |
|             xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|             $rc = 1;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     # Rename the node.
 | |
|     if ( $changeType eq 'r' ) {
 | |
|         my $retRef = xCAT::Utils->runxcmd({command=>['chdef'], stdin=>['NO_NODE_RANGE'], arg=>[ '-t', 'node', '-o', $nodeName, '-n', $newNode, '--nocache' ]}, $request_command, 0, 2);
 | |
|         if ( $::RUNCMD_RC != 0 ) {
 | |
|             my $rsp;
 | |
|             $retStrRef = parse_runxcmd_ret($retRef);
 | |
|             push @{$rsp->{data}}, '-t'. 'node'. '-o'. $nodeName. '-n'. $newNode;
 | |
|             push @{$rsp->{data}}, "Unable to rename node $nodeName " .
 | |
|                 "to $newNode in the xCAT tables.  " .
 | |
|                 "The node definition for $nodeName will be removed.  " .
 | |
|                 "chdef response: $retStrRef->[1]";
 | |
|             xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|             $rc = 1;
 | |
|             changeNode( $callback, $nodeName, 'do' );
 | |
|         } else {
 | |
|             my $out = `/opt/xcat/sbin/makehosts $newNode 2>&1`;
 | |
|             if ( $out ne '' ) {
 | |
|                 my $rsp;
 | |
|                 push @{$rsp->{data}}, "'makehosts' failed for $newNode.  " .
 | |
|                     "The node definition for $newNode will be removed.  " .
 | |
|                     "'makehosts' response: $out";
 | |
|                 xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|                 $rc = 1;
 | |
|                 changeNode( $callback, $newNode, 'do' );
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     return $rc;
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3   createNode
 | |
| 
 | |
|     Description : Find an available xCAT nodename and create a node
 | |
|                   for the virtual machine and indicate it is a 
 | |
|                   discovered node.  Also, do a MAKEHOSTS so xCAT MN
 | |
|                   can access it by the node name.
 | |
|     Arguments   : Callback handle
 | |
|                   DNS name associated with the OS in the machine
 | |
|                   Desired name format template, if specified
 | |
|                   Current numeric adjustment value, used to get
 | |
|                       to the next available nodename.
 | |
|                   xCAT STANZA information in a string that will
 | |
|                        be used to create the node.
 | |
|                   Reference for the xCAT NODEs hash so that we
 | |
|                       can check for already known node names.
 | |
|     Returns     : Node name if created or empty string if an error occurred.
 | |
|                   Current numeric value
 | |
|     Example     : ( $node, $numeric ) = createNode($callback, $discoverable{$activeSystem}{'hostname'}, 
 | |
|                                         $args{'nodenameformat'}, $numeric, $retstr_gen, \%xcatNodes);
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub createNode {
 | |
|     my $callback = shift;
 | |
|     my $dnsName = shift;
 | |
|     my $nameFormat = shift;
 | |
|     my $numeric = shift;
 | |
|     my $stanzaInfo = shift;
 | |
|     my $xcatNodesRef = shift;
 | |
| 
 | |
|     my $attempts = 0;     # Number of attempts to find a usable node name
 | |
|     my $nodeName;         # Node name found or being checked
 | |
|     my $prefix = '';      # Node name prefix, used with templates
 | |
|     my $rsp;              # Message work variable
 | |
|     my $shortName;        # Short form of the DNS name
 | |
|     my $suffix = '';      # Node name suffix, initially none
 | |
|     my $templateType = 0; # Type of template; 0: none, 1: old style xCAT, 2: OpenStack (sprintf)
 | |
| 
 | |
|     # Determine the component parts of the new node name based on whether
 | |
|     # a template is specified.
 | |
|     if ( $nameFormat ) {
 | |
|         if ( $nameFormat =~ /#NNN/ ) {
 | |
|             # Old Style xCAT template e.g. node#NNN -> node001
 | |
|             $templateType = 1;
 | |
|             
 | |
|             # Deconstruct the name format template into its component parts.
 | |
|             my @fmtParts = split ( '#NNN', $nameFormat );
 | |
|             $prefix = $fmtParts[0];
 | |
|             $suffix = $fmtParts[1];
 | |
|         } elsif ( $nameFormat =~ /%/ ) {
 | |
|             # OpenStack style template, uses sprintf for formatting
 | |
|             $templateType = 2;
 | |
|         } else {
 | |
|             $nodeName = '';
 | |
|             push @{$rsp->{data}}, "Unrecognized node name template.  Nodes will not be discovered.";
 | |
|             xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|             goto FINISH_createNode;
 | |
|         }
 | |
| 
 | |
|         if ( $numeric eq '' ) {
 | |
|             $numeric = 0;
 | |
|         }
 | |
|     } else {
 | |
|         # Set up to use the DNS short name as the root of the node name.
 | |
|         my @nameParts = split( /\./, $dnsName );
 | |
|         $shortName = lc( $nameParts[0] );
 | |
|         $numeric = "";
 | |
|     }
 | |
| 
 | |
|     # Loop to find an available node name and reserve it by creating the
 | |
|     # node with minimal information.
 | |
|     while ( 1 ) {
 | |
|         # Create the next nodename
 | |
|         if ( $templateType == 1 ) {
 | |
|             $numeric = $numeric + 1;
 | |
|             my $numSize = length($numeric);
 | |
|             if ( $numSize < 3 ) {
 | |
|                 $numSize = 3;
 | |
|             }
 | |
|             my $format = "%0".$numSize."d";
 | |
|             $numeric = sprintf($format, $numeric);
 | |
|             $nodeName = $prefix.$numeric.$suffix;
 | |
|         } elsif ( $templateType == 2 ) {
 | |
|             $numeric = $numeric + 1;
 | |
|             $nodeName = sprintf($nameFormat, $numeric);
 | |
|         } else {
 | |
|             if ( $numeric ne '' ){
 | |
|                 $numeric += 1;
 | |
|             }
 | |
|             $nodeName = $shortName.$numeric;
 | |
|         }
 | |
| 
 | |
|         # Verify that the nodename is available.
 | |
|         if ( !$xcatNodesRef->{$nodeName} ) {
 | |
|             # Found an available node name
 | |
|             # Attempt to create the node with that name.
 | |
|             $attempts += 1;
 | |
|             my $retstr_gen = "$nodeName:\n$stanzaInfo";
 | |
|             my $retRef = xCAT::Utils->runxcmd({command=>["mkdef"], stdin=>[$retstr_gen], arg=>['-z']}, $request_command, 0, 2);
 | |
| 
 | |
|             if ( $::RUNCMD_RC == 0 ) {
 | |
|                 # Node created.  All done.
 | |
|                 $xcatNodesRef->{$nodeName} = 1;
 | |
|                 
 | |
|                 # Update the zvm table for the node to indicate that it is a discovered system.
 | |
|                 my %zvmProps = ( "discovered" => "1" );
 | |
|                 my $zvmTab = xCAT::Table->new('zvm');
 | |
|                 if ( !$zvmTab ) {
 | |
|                     # Node was created but there is not much we can do about it since
 | |
|                     # not being able to update the zvm table indicates a severe error.
 | |
|                     push @{$rsp->{data}}, "Could not open table: zvm.  $nodeName was created but discovered=1 could not be set in the zvm table.";
 | |
|                     xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|                 } else {
 | |
|                     $zvmTab->setAttribs( {node => $nodeName}, \%zvmProps );
 | |
|                     $zvmTab->commit();
 | |
|                 }
 | |
|                 last;
 | |
|             } else {
 | |
|                 if ( $attempts > 10 ) {
 | |
|                     # Quit trying to create a node after 10 attempts
 | |
|                     my $retStrRef = parse_runxcmd_ret($retRef);
 | |
|                     my $rsp;
 | |
|                     push @{$rsp->{data}}, "Unable to create a node, $nodeName.  Last attempt response: $retStrRef->[1]";
 | |
|                     xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|                     $nodeName = '';
 | |
|                     last;
 | |
|                 } else {
 | |
|                     # Assume xCAT daemon is unavailable.  Give it 15 seconds to come back 
 | |
|                     # before next attempt.
 | |
|                     sleep(15);
 | |
|                 }
 | |
|             } 
 | |
|         }
 | |
| 
 | |
|         # Did not find an available node name on this pass.
 | |
|         # Wipe out the nodename in case we exit the loop.  Also, ensure a numeric 
 | |
|         # is used next time around.
 | |
|         $nodeName = '';
 | |
|         if ( $numeric eq '' ){
 | |
|             $numeric = 0;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if ( $nodeName ne '' ) {
 | |
|         # Issue MAKEHOSTS so that xCAT MN can drive commands to the host using the node name.
 | |
|         # Note: If OpenStack changes the node name then we will have to redo this later.
 | |
|         my $out = `/opt/xcat/sbin/makehosts $nodeName 2>&1`;
 | |
|         if ( $out ne '' ) {
 | |
|             my $rsp;
 | |
|             push @{$rsp->{data}}, "'makehosts' failed for $nodeName.  Node creation is being undone.  'makehosts' response: $out";
 | |
|             xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|             changeNode( $callback, $nodeName, 'do' );
 | |
|             $nodeName = '';
 | |
|         }
 | |
|     }
 | |
| 
 | |
| FINISH_createNode:
 | |
|     return ( $nodeName, $numeric );
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3   findme
 | |
| 
 | |
|     Description : Handle the request form node to map and 
 | |
|                   define the request to a node.
 | |
|     Arguments   : request handle
 | |
|                   callback
 | |
|                   sub request
 | |
|     Returns     : 0 - No error
 | |
|                   non-zero - Error detected.
 | |
|     Example     : findme( $request, $callback, $request_command );
 | |
|     
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub findme {
 | |
|     my $request = shift;
 | |
|     my $callback = shift;
 | |
|     my $subreq = shift;
 | |
| 
 | |
|     my $SEQdiscover = getSiteVal("__SEQDiscover");
 | |
|     my $PCMdiscover = getSiteVal("__PCMDiscover");
 | |
|     my $ZVMdiscover = getSiteVal("__ZVMDiscover");
 | |
|     unless ( $ZVMdiscover ) {
 | |
|         if ( $SEQdiscover or $PCMdiscover ) {
 | |
|             # profile or sequential discovery is running, then just return 
 | |
|             # to make the other discovery handle it
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         # update the discoverydata table to have an undefined node
 | |
|         $request->{discoverymethod}->[0] = 'undef';
 | |
|         xCAT::DiscoveryUtils->update_discovery_data($request);
 | |
|         return;
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3   getOpenStackTemplate
 | |
| 
 | |
|     Description : Get the current template used by OpenStack
 | |
|                   for this host and the largest numeric
 | |
|                   value currently in use.
 | |
|     Arguments   : callback
 | |
|                   z/VM host node
 | |
|     Returns     : Template to be used for node naming
 | |
|                   Highest numeric value in use
 | |
|     Example     : my $out = getOpenStackTemplate( $callback, $zvmHost );
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub getOpenStackTemplate {
 | |
|     my ( $callback, $zvmHost ) = @_;
 | |
| 
 | |
|     my $out = '';
 | |
|     my %response = (
 | |
|         'template' => '',
 | |
|         'number' => '' );
 | |
| 
 | |
|     xCAT::MsgUtils->message( "S", "Calling $locOpenStackNodeNameInfo for $zvmHost" );
 | |
|     $out = `python $locOpenStackNodeNameInfo`;
 | |
|     xCAT::MsgUtils->message( "S", "Returned from $locOpenStackNodeNameInfo with $out" );
 | |
| 
 | |
|     if (( $out ne '' ) && ( $out !~ /^Error detected/ )) {
 | |
|         my @parts = split( /\s/, $out );
 | |
|         my $key;
 | |
|         foreach my $part ( @parts ) {
 | |
|             if ( $part eq 'Template:' ) {
 | |
|                 $key = 'template';
 | |
|             } elsif ( $part eq 'Number:' ) {
 | |
|                 $key = 'number';
 | |
|             } else {
 | |
|                 $part =~ s/^\s+|\s+$//g;    # Trim leading & ending blanks
 | |
|                 $response{$key} = $part;
 | |
|             }
 | |
|         }
 | |
|     } else {
 | |
|         my $rsp;
 | |
|         my @lines = split( /\n/, $out );
 | |
|         shift( @lines );
 | |
|         if ( @lines ) {
 | |
|             push @{$rsp->{data}}, @lines;
 | |
|         } else {
 | |
|             push @{$rsp->{data}}, "An error was detected in the nova instance name template."
 | |
|         }
 | |
|         xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|         $response{'template'} = '';
 | |
|     }
 | |
| 
 | |
| FINISH_getOpenStackTemplate:
 | |
|     return ( $response{'template'}, $response{'number'} );
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3   getRunningDiscTimestamp
 | |
| 
 | |
|     Description : Get the timestamp on a specific running
 | |
|                   discovery from the site table variable.
 | |
|     Arguments   : Callback handle
 | |
|                   z/VM host node
 | |
|     Returns     : Timestamp for the run that was specified or 
 | |
|                     empty string if a run was not found.
 | |
|     Example     : $ts = getRunningDiscTimestamp( 'zvm1' );
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub getRunningDiscTimestamp {
 | |
|     my $callback = shift;
 | |
|     my $zvmHost = shift;
 | |
| 
 | |
|     my $rsp;            # Response buffer for output messages
 | |
|     my $ts = '';        # Timestamp value
 | |
| 
 | |
|     my $val = getSiteVal("__ZVMDiscover");
 | |
|     if ( $val ) {
 | |
|         if ( $val =~ /zvmhost=$zvmHost,/ ) {
 | |
|             my @discoveries = split( /zvmhost=/, $val );
 | |
|             foreach my $discovery ( @discoveries ) {
 | |
|                 if ( $discovery =~ "^$zvmHost" ) {
 | |
|                     my @parts = split( ',', $discovery );
 | |
|                     if ( $parts[1] ) {
 | |
|                         $ts = $parts[1];
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     return $ts;
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3   getSiteVal
 | |
| 
 | |
|     Description : Bypasses a problem with get_site_attribute
 | |
|                   returning an old cashe value instead of
 | |
|                   the current value.
 | |
|     Arguments   : Name of attribute
 | |
|     Returns     : Value from the site table
 | |
|     Example     : ( $val ) = getSiteVal( '__ZVMDiscover' );
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub getSiteVal {
 | |
|     my $attribute = shift;
 | |
| 
 | |
|     my $response = '';        # Response buffer for return
 | |
| 
 | |
|     my $siteTab = xCAT::Table->new( "site", -autocommit=>1 );
 | |
|     my @results = $siteTab->getAttribs( { 'key'=>$attribute }, ('value') );
 | |
|     foreach my $id ( @results ) {
 | |
|         $response .= $id->{'value'};
 | |
|     }
 | |
|     $siteTab->close;
 | |
| 
 | |
|     return $response;
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3   handled_commands
 | |
| 
 | |
|     Description : Returns the supported commands and their handler.
 | |
|     Arguments   : None.
 | |
|     Returns     : Command handler hash for this module.
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub handled_commands {
 | |
|     return {
 | |
|         #findme             => 'zvmdiscovery',   # Not handle findme in this plugin, #4860
 | |
|         #nodediscoverdef   => 'zvmdiscovery',    # Handled by sequential discovery
 | |
|         nodediscoverls     => 'zvmdiscovery',
 | |
|         nodediscoverstart  => 'zvmdiscovery',
 | |
|         nodediscoverstatus => 'zvmdiscovery',
 | |
|         nodediscoverstop   => 'zvmdiscovery',
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3   nodediscoverls
 | |
| 
 | |
|     Description : List discovered z/VM systems.
 | |
|     Arguments   : callback
 | |
|                   arguments for nodediscoverls
 | |
|     Returns     : None.
 | |
|     Example     : nodediscoverls( $callback, $args );
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub nodediscoverls {
 | |
|     my $callback = shift;
 | |
|     my $args = shift;
 | |
| 
 | |
|     my %origArgs;                # Original arguments from the command invocation
 | |
|     my $maxNodeSize = 4;         # Maximum size of a nodename in the current list
 | |
|     my $maxHostSize = 6;         # Maximum size of a host nodename in the current list
 | |
|     my $maxUseridSize = 6;       # Maximum size of a userid in the current list
 | |
| 
 | |
|     # Determine which options were specified and their values.
 | |
|     if ( $args ) {
 | |
|         @ARGV = @$args;
 | |
|     }
 | |
| 
 | |
|     GetOptions(
 | |
|         't=s'         => \$origArgs{'type'},
 | |
|         'u=s'         => \$origArgs{'uuid'},
 | |
|         'l'           => \$origArgs{'long'},
 | |
|         'h|help'      => \$origArgs{'help'},
 | |
|         'v|version'   => \$origArgs{'ver'},
 | |
|         'z|zvmhost=s' => \$origArgs{'zvmHost'} );
 | |
| 
 | |
|     # If '-u' was specified then let seqdiscovery handle it as common output.
 | |
|     if ( $origArgs{'uuid'} ) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     # If z/VM discovery is running and the type was not already specified then
 | |
|     # we treat this as a z/VM type of listing.
 | |
|     my @ZVMDiscover = xCAT::TableUtils->get_site_attribute( "__ZVMDiscover" );
 | |
|     if ( $ZVMDiscover[0] ) {
 | |
|         $origArgs{'type'} = 'zvm';
 | |
|     }
 | |
| 
 | |
|     # Weed out invocations that this routine does not handle but instead
 | |
|     # leaves to sequential discovery to handle.
 | |
|     if ( $origArgs{'help'} ||
 | |
|          $origArgs{'ver'}  ||
 | |
|          ( $origArgs{'type'} && $origArgs{'type'} ne 'zvm' ))
 | |
|     {
 | |
|         # Sequential discovery will have handled these options.
 | |
|         return;
 | |
|     } elsif ( $origArgs{'zvmHost'} || ( $origArgs{'type'} && $origArgs{'type'} eq 'zvm' )) {
 | |
|         # z/VM related operands are handled here.
 | |
|     } else {
 | |
|         # Sequential discovery will have handled other combinations of options.
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     # If a zvmHost was specified then process it into an array
 | |
|     my %zvmHosts;
 | |
|     my @inputZvmHosts;
 | |
|     if ( $origArgs{'zvmHost'} ) {
 | |
|         if ( index( $origArgs{'zvmHost'}, ',' ) != -1 ) {
 | |
|             # Must have specified multiple host node names
 | |
|             my @hosts = split( /,/, $origArgs{'zvmHost'} );
 | |
|             foreach my $host ( @hosts ) {
 | |
|                 if ( !$host ) {
 | |
|                     # Tolerate zvmhost value beginning with a comma.  
 | |
|                     # It is wrong but not worth an error message.
 | |
|                     next;
 | |
|                 }
 | |
|                 push( @inputZvmHosts, $host );
 | |
|             }
 | |
|         } else {
 | |
|             push( @inputZvmHosts, $origArgs{'zvmHost'} );
 | |
|         }
 | |
|         %zvmHosts = map { $_ => 1 } @inputZvmHosts;
 | |
|     }
 | |
| 
 | |
|     # Get the list xCAT nodes and their userids.
 | |
|     my $zvmTab = xCAT::Table->new("zvm");
 | |
|     if ( !$zvmTab ) {
 | |
|         my $rsp;
 | |
|         push @{$rsp->{data}}, "Could not open table: zvm.";
 | |
|         xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|         goto FINISH_nodediscoverls;
 | |
|     }
 | |
|     my %xcatNodes;
 | |
|     my @attribs = ('node', 'userid');
 | |
|     my @nodes = $zvmTab->getAllAttribs( @attribs );
 | |
|     foreach my $nodeRef ( @nodes ) {
 | |
|         if ( !$nodeRef->{'node'} || !$nodeRef->{'userid'} ) {
 | |
|             next;
 | |
|         }
 | |
|         $xcatNodes{$nodeRef->{'node'}} = $nodeRef->{'userid'};
 | |
|     }
 | |
| 
 | |
|     # Get the list of discovered systems for the specified z/VMs.
 | |
|     my %discoveredNodes;
 | |
|     my $disTab = xCAT::Table->new('discoverydata');
 | |
|     if ( !$disTab ) {
 | |
|         my $rsp;
 | |
|         push @{$rsp->{data}}, "Could not open table: discoverydata.";
 | |
|         xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|         goto FINISH_nodediscoverls;
 | |
|     }
 | |
| 
 | |
|     my @disData = $disTab->getAllAttribsWhere( "method='zvm'", 'node', 'uuid', 'otherdata',
 | |
|                                                'method', 'discoverytime', 'arch', 'cpucount',
 | |
|                                                'memory');
 | |
|     foreach my $disRef ( @disData ) {
 | |
|         if ( !$disRef->{'uuid'} || !$disRef->{'node'} || !$disRef->{'otherdata'} ) {
 | |
|             next;
 | |
|         }
 | |
| 
 | |
|         my $host = $disRef->{'otherdata'};
 | |
|         $host =~ s/^zvmhost.//g;
 | |
| 
 | |
|         if ( !%zvmHosts | $zvmHosts{$host} ) {
 | |
|             my $node = $disRef->{'node'};
 | |
|             $discoveredNodes{$node}{'uuid'} = $disRef->{'uuid'};
 | |
|             $discoveredNodes{$node}{'host'} = $host;
 | |
|             if ( $xcatNodes{$node} ) {
 | |
|                 $discoveredNodes{$node}{'userid'} = $xcatNodes{$node};
 | |
|             }
 | |
|             $discoveredNodes{$node}{'method'} = $disRef->{'method'};
 | |
|             $discoveredNodes{$node}{'discoverytime'} = $disRef->{'discoverytime'};
 | |
|             $discoveredNodes{$node}{'arch'} = $disRef->{'arch'};
 | |
|             $discoveredNodes{$node}{'cpucount'} = $disRef->{'cpucount'};
 | |
|             $discoveredNodes{$node}{'memory'} = $disRef->{'memory'};
 | |
| 
 | |
|             # Update size of node and host node names if size has increased.
 | |
|             # This is used later when producing the output.
 | |
|             my $length = length( $host );
 | |
|             if ( $length > $maxHostSize ) {
 | |
|                 $maxHostSize = $length;
 | |
|             }
 | |
|             $length = length( $node );
 | |
|             if ( $length > $maxNodeSize ) {
 | |
|                 $maxNodeSize = $length;
 | |
|             }
 | |
|             $length = length( $discoveredNodes{$node}{'userid'} );
 | |
|             if ( $length > $maxUseridSize ) {
 | |
|                 $maxUseridSize = $length;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     # Produce the output
 | |
|     my $rsp;
 | |
|     my $discoverednum = keys %discoveredNodes;
 | |
|     push @{$rsp->{data}}, "Discovered $discoverednum nodes.";
 | |
|     if ( %discoveredNodes ) {
 | |
|         # Create the format string for the column output
 | |
|         if ( $maxHostSize > 20 ) {
 | |
|             $maxHostSize = 20;     # Set a maximum, individual lines may throw it off but we need to be reasonable.
 | |
|         }
 | |
|         $maxHostSize += 2;
 | |
|         if ( $maxNodeSize > 20 ) {
 | |
|             $maxNodeSize = 20;     # Set a maximum, individual lines may throw it off but we need to be reasonable.
 | |
|         }
 | |
|         $maxNodeSize += 2;
 | |
|         if ( $maxUseridSize > 20 ) {
 | |
|             $maxUseridSize = 20;     # Set a maximum, individual lines may throw it off but we need to be reasonable.
 | |
|         }
 | |
|         $maxUseridSize += 2;
 | |
| 
 | |
|         my $fmtString;
 | |
|         if ( !$origArgs{'long'} ) {
 | |
|             $fmtString = ' %-' . $maxNodeSize . 's%-' . $maxUseridSize . 's%-' . $maxHostSize . 's';
 | |
|             push @{$rsp->{data}}, sprintf( $fmtString, 'NODE', 'USERID', 'ZVM HOST' );
 | |
|         }
 | |
| 
 | |
|         # Create the output
 | |
|         foreach my $node (keys %discoveredNodes) {
 | |
|             if ( $origArgs{'long'} ) {
 | |
|                 push @{$rsp->{data}}, "Object uuid: $discoveredNodes{$node}{'uuid'}";
 | |
|                 push @{$rsp->{data}}, "    node=$node";
 | |
|                 push @{$rsp->{data}}, "    userid=$discoveredNodes{$node}{'userid'}";
 | |
|                 push @{$rsp->{data}}, "    host=$discoveredNodes{$node}{'host'}";
 | |
|                 push @{$rsp->{data}}, "    method=$discoveredNodes{$node}{'method'}";
 | |
|                 push @{$rsp->{data}}, "    discoverytime=$discoveredNodes{$node}{'discoverytime'}";
 | |
|                 push @{$rsp->{data}}, "    arch=$discoveredNodes{$node}{'arch'}";
 | |
|                 push @{$rsp->{data}}, "    cpucount=$discoveredNodes{$node}{'cpucount'}";
 | |
|                 push @{$rsp->{data}}, "    memory=$discoveredNodes{$node}{'memory'}";
 | |
|             } else {
 | |
|                 push @{$rsp->{data}}, sprintf( $fmtString,
 | |
|                                                $node,
 | |
|                                                $discoveredNodes{$node}{'userid'},
 | |
|                                                $discoveredNodes{$node}{'host'} );
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     xCAT::MsgUtils->message("I", $rsp, $callback);
 | |
| 
 | |
| FINISH_nodediscoverls:
 | |
|     return;
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3   nodediscoverstart
 | |
| 
 | |
|     Description : Initiate the z/VM discovery process.
 | |
|     Arguments   : callback
 | |
|                   arguments for nodediscoverstart
 | |
|     Returns     : None.
 | |
|     Example     : nodediscoverstart( $callback, $args );
 | |
|     
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub nodediscoverstart {
 | |
|     my $callback = shift;
 | |
|     my $args = shift;
 | |
| 
 | |
|     my $lock = 0;            # Lock word, 0: not obtained, 1: lock failed, other: lock handle
 | |
|     my @newZvmHosts;         # Array of z/VM host nodes on this command invocation
 | |
|     my %origArgs;            # Original arguments from the command invocation
 | |
|     my %parms;               # Parameters to pass along to start routine
 | |
|     my $rsp;                 # Response buffer for output messages
 | |
|     my %runningZvmHosts;     # List of z/VM host nodes from the __ZVMDiscover property in the site table
 | |
|     my $zvmHost;             # Short scope work parameter used to contain a z/VM host node name
 | |
| 
 | |
|     # Valid attributes for nodediscoverstart
 | |
|     my %validArgs = (
 | |
|         'defineto'          => 1,
 | |
|         'groups'            => 1,
 | |
|         'ipfilter'          => 1,
 | |
|         'nodenameformat'    => 1,
 | |
|         'useridfilter'      => 1,
 | |
|         'zvmhost'           => 1,
 | |
|         'openstackoperands' => 1,
 | |
|     );
 | |
| 
 | |
|     if ( $args ) {
 | |
|         @ARGV = @$args;
 | |
|     }
 | |
| 
 | |
|     $origArgs{'verbose'} = 0;     # Assume we are not doing verbose
 | |
|     my ($help, $ver); 
 | |
|     if (!GetOptions(
 | |
|         'h|help' => \$help,
 | |
|         'V|verbose' => \$origArgs{'verbose'},
 | |
|         'v|version' => \$ver)) {
 | |
|         # Sequential discovery will have produced an error message.
 | |
|         # We don't need another
 | |
|         return;
 | |
|     }
 | |
|     
 | |
|     if ( $help | $ver ) {
 | |
|         # Sequential discovery will have handled these options.
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     foreach ( @ARGV ) {
 | |
|         my ($name, $value) = split ('=', $_);
 | |
|         $origArgs{$name} = $value;
 | |
|     }
 | |
| 
 | |
|     if ( !defined( $origArgs{'zvmhost'} ) ) {
 | |
|         # If zvmhost parm is not present then this is not a z/VM discovery.
 | |
|         goto FINISH_NODEDISCOVERSTART;
 | |
|     }
 | |
| 
 | |
|     push @{$rsp->{data}}, "Processing: nodediscoverstart @$args";
 | |
|     xCAT::MsgUtils->message("I", $rsp, $callback, 1);
 | |
| 
 | |
|     # Check the running of sequential or profile-based discovery
 | |
|     my $SEQdiscover = getSiteVal("__SEQDiscover");
 | |
|     my $PCMdiscover = getSiteVal("__PCMDiscover");
 | |
|     if ( $PCMdiscover or $SEQdiscover ) {
 | |
|         push @{$rsp->{data}}, "z/VM Discovery cannot be run together with Sequential or Profile-based discovery";
 | |
|         xCAT::MsgUtils->message("E", $rsp, $callback, 1);
 | |
|         goto FINISH_NODEDISCOVERSTART;
 | |
|     }
 | |
| 
 | |
|     # Verify that specified filters are valid.
 | |
|     if ( defined( $origArgs{'ipfilter'} )) {
 | |
|         eval {''=~/$origArgs{'ipfilter'}/};
 | |
|         if ( $@ ) {
 | |
|             push @{$rsp->{data}}, "The ipfilter is not a valid regular expression: $@";
 | |
|             xCAT::MsgUtils->message( "E", $rsp, $callback, 1 );
 | |
|             goto FINISH_NODEDISCOVERSTART;
 | |
|         }
 | |
|     }
 | |
|     if ( defined( $origArgs{'useridfilter'} )) {
 | |
|         eval {''=~/$origArgs{'useridfilter'}/};
 | |
|         if ( $@ ) {
 | |
|             push @{$rsp->{data}}, "The useridfilter is not a valid regular expression: $@";
 | |
|             xCAT::MsgUtils->message( "E", $rsp, $callback, 1 );
 | |
|             goto FINISH_NODEDISCOVERSTART;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     # Set the default defineto option if none was specified and verify the value.
 | |
|     if ( ! defined( $origArgs{'defineto'} ) ) {
 | |
|         $origArgs{'defineto'} = 'both';
 | |
|     } else {
 | |
|         if (( $origArgs{'defineto'} ne 'both' ) and ( $origArgs{'defineto'} ne 'xcatonly' ) and
 | |
|             ( $origArgs{'defineto'} ne 'openstackonly' )) {
 | |
|             push @{$rsp->{data}}, "Specified 'defineto' value is not 'both', 'xcatonly' or " .
 | |
|                                   "'openstackonly': $origArgs{'defineto'}";
 | |
|             xCAT::MsgUtils->message( "E", $rsp, $callback, 1 );
 | |
|             goto FINISH_NODEDISCOVERSTART;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     # Verify that the OpenStack plugin is available.
 | |
|     if ( $origArgs{'defineto'} ne 'xcatonly' ) {
 | |
|         if ( !-e $locOpenStackDiscovery ) {
 | |
|             my $rsp;
 | |
|             push @{$rsp->{data}}, "$locOpenStackDiscovery does not exist.  " .
 | |
|                                   "Discovery cannot occur.";
 | |
|             xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|             goto FINISH_NODEDISCOVERSTART;
 | |
|         }
 | |
|         if ( $origArgs{'defineto'} ne 'both' ) {
 | |
|             if ( !-e $locOpenStackNodeNameInfo ) {
 | |
|                 my $rsp;
 | |
|                 push @{$rsp->{data}}, "$locOpenStackNodeNameInfo does not exist.  " .
 | |
|                                       "Discovery cannot occur.";
 | |
|                 xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|                 goto FINISH_NODEDISCOVERSTART;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     # Use sudo or not
 | |
|     # This looks in the passwd table for a key = sudoer
 | |
|     ($::SUDOER, $::SUDO) = xCAT::zvmUtils->getSudoer();
 | |
| 
 | |
|     # Obtain any ongoing z/VM discovery parms and get the list of z/VM hosts.
 | |
|     $lock = xCAT::Utils->acquire_lock( "nodemgmt", 0 );
 | |
|     if ( $lock == 1 ) {
 | |
|         push @{$rsp->{data}}, "Unable to acquire the 'nodemgmt' lock to protect __ZVMDiscover property in the xCAT site table from changes.";
 | |
|         xCAT::MsgUtils->message( "E", $rsp, $callback, 1 );
 | |
|         goto FINISH_NODEDISCOVERSTART;
 | |
|     }
 | |
| 
 | |
|     my $ZVMdiscover = getSiteVal( "__ZVMDiscover" );
 | |
|     if ( $ZVMdiscover ) {
 | |
|         if ( $ZVMdiscover =~ '^zvmhost=' ) {
 | |
|             my @discoveries = split(/zvmhost=/, $ZVMdiscover);
 | |
|             foreach my $activeParms ( @discoveries ) {
 | |
|                 if ( !$activeParms ) {
 | |
|                     next;
 | |
|                 }
 | |
|                 if ( index( $activeParms, ',' ) != -1 ) {
 | |
|                     $zvmHost = substr( $activeParms, 0, index( $activeParms, ',' ));
 | |
|                 } else {
 | |
|                     $zvmHost = $activeParms;
 | |
|                 }
 | |
|                 $runningZvmHosts{$zvmHost} = 1;
 | |
|             }
 | |
|         } else {
 | |
|             # Not an expected format, Drop it when we push out the new saved parameters.
 | |
|             push @{$rsp->{data}}, "Wrong format";
 | |
|             xCAT::MsgUtils->message("E", $rsp, $callback, 1);
 | |
|             $ZVMdiscover = '';
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     my %param;               # The valid parameters in a hash
 | |
|     my $textParam;           # The valid parameters in 'name=value,name=value...' format
 | |
|     my @newZvmhosts;         # Array of z/VM hosts to be added
 | |
|     my %zhcpServers;         # Hash of ZHCP servers for each new host to be discovered.
 | |
| 
 | |
|     # Validate the parameters
 | |
|     foreach my $name ( keys %origArgs ) {
 | |
|         if ( $name eq 'verbose' ) {
 | |
|             # Verbose is a hyphenated option and is not listed in the
 | |
|             # validArgs hash.  So we won't do a validation check on it.
 | |
|         } elsif ( !defined( $validArgs{$name} ) ) {
 | |
|             push @{$rsp->{data}}, "Argument \"$name\" is not valid.";
 | |
|             xCAT::MsgUtils->message( "E", $rsp, $callback, 1 );
 | |
|             goto FINISH_NODEDISCOVERSTART;
 | |
|         }
 | |
|         if ( !defined( $origArgs{$name} ) ) {
 | |
|             push @{$rsp->{data}}, "The parameter \"$name\" needs a value.";
 | |
|             xCAT::MsgUtils->message( "E", $rsp, $callback, 1 );
 | |
|             goto FINISH_NODEDISCOVERSTART;
 | |
|         }
 | |
| 
 | |
|         if (( $name eq 'nodenameformat' ) and ( index( $origArgs{$name}, '#NNN' ) == -1)) {
 | |
|             push @{$rsp->{data}}, "The parameter \"$name\" is missing the '#NNN' string.";
 | |
|             xCAT::MsgUtils->message( "E", $rsp, $callback, 1 );
 | |
|             goto FINISH_NODEDISCOVERSTART;
 | |
|         }
 | |
| 
 | |
|         # Invoke the OpenStack plugin to validate OpenStack related variables.
 | |
|         if (( $name eq 'openstackoperands' ) and 
 | |
|             (( $origArgs{'defineto'} eq 'both' ) || ( $origArgs{'defineto'} eq 'openstackonly' )) &&
 | |
|              defined( $origArgs{$name} )) {
 | |
|             $origArgs{$name} =~ s/^\'+|\'+$//g;
 | |
|             $origArgs{$name} =~ s/^\"+|\"+$//g;
 | |
|             xCAT::MsgUtils->message( "S", "Calling $locOpenStackDiscovery to validate parms: $origArgs{$name}" );
 | |
|             my $out = `python $locOpenStackDiscovery --validate $origArgs{$name}`;
 | |
|             chomp( $out );
 | |
|             xCAT::MsgUtils->message( "S", "Returned from $locOpenStackDiscovery with $out" );
 | |
|             if ( $out ne '0' ) {
 | |
|                 if ( $out eq '' ) {
 | |
|                     $out = "No response was received from $locOpenStackDiscovery for OpenStack operand validation.  z/VM discovery will not be started.";
 | |
|                 }
 | |
|                 push @{$rsp->{data}}, "$out";
 | |
|                 xCAT::MsgUtils->message( "E", $rsp, $callback, 1 );
 | |
|                 goto FINISH_NODEDISCOVERSTART;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         # Keep the valid parameters
 | |
|         if ( $name eq 'zvmhost' ) {
 | |
|             if ( index( $origArgs{$name}, ',' ) != -1 ) {
 | |
|                 # Must have specified multiple host node names
 | |
|                 my @hosts = split( /,/, $origArgs{$name} );
 | |
|                 foreach $zvmHost ( @hosts ) {
 | |
|                     if ( !$zvmHost ) {
 | |
|                         # Tolerate zvmhost value beginning with a comma.
 | |
|                         # It is wrong but not worth an error message.
 | |
|                         next;
 | |
|                     }
 | |
|                     push( @newZvmhosts, $zvmHost );
 | |
|                 }
 | |
|             } else {
 | |
|                 push( @newZvmhosts, $origArgs{$name} );
 | |
|             }
 | |
|             foreach $zvmHost ( @newZvmhosts ) {
 | |
|                 if ( exists( $runningZvmHosts{$zvmHost} )) {
 | |
|                     push @{$rsp->{data}}, "The node \"$zvmHost\" specified with the zvmhost parameter is already running z/VM discovery.";
 | |
|                     xCAT::MsgUtils->message( "E", $rsp, $callback, 1 );
 | |
|                     goto FINISH_NODEDISCOVERSTART;
 | |
|                 }
 | |
|             }
 | |
|         } else {
 | |
|             # Non-zvmhost parms get added to textParam string
 | |
|             $param{$name} = $origArgs{$name};
 | |
|             $param{$name} =~ s/^\s+|\s+$//g;
 | |
|             $textParam .= $name . '=' . $param{$name} . ' ';
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     $textParam =~ s/,\z//;
 | |
|     if ( $textParam ) {
 | |
|         $textParam =  $textParam;
 | |
|     }
 | |
| 
 | |
|     my ($sec,  $min,  $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
 | |
|     my $currTime = sprintf("%02d-%02d-%04d %02d:%02d:%02d",
 | |
|                            $mon + 1, $mday, $year + 1900, $hour, $min, $sec);
 | |
| 
 | |
|     # Save the discovery parameters to the site.  __ZVMDiscover which will be used by nodediscoverls/status/stop and findme.
 | |
|     foreach $zvmHost ( @newZvmhosts ) {
 | |
|         # Verify that the zvmHost node exists
 | |
|         my @reqProps = ( 'node' );
 | |
|         my $propVals = xCAT::zvmUtils->getNodeProps( 'nodetype', $zvmHost, @reqProps );
 | |
|         if ( !$propVals->{'node'} ) {
 | |
|             push @{$rsp->{data}}, "The z/VM host node is not a defined node.  " .
 | |
|                                   "The node $zvmHost is missing from the nodetype table.";
 | |
|             xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         # Verify that the node is a z/VM host and locate the ZHCP server for this host.
 | |
|         my @propNames = ( 'hcp', 'nodetype' );
 | |
|         $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $zvmHost, @propNames );
 | |
| 
 | |
|         if ( $propVals->{'nodetype'} ne 'zvm') {
 | |
|             push @{$rsp->{data}}, "The specified z/VM host $zvmHost does not appear to be a z/VM host.  " .
 | |
|                                   "The 'nodetype' property in the zvm table should be set to 'zvm'.";
 | |
|             xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         my $hcp = $propVals->{'hcp'};
 | |
|         if ( $hcp ) {
 | |
|             # Remember the ZHCP info so we can pass it along
 | |
|             $zhcpServers{$zvmHost} = $hcp;
 | |
|         } else {
 | |
|             push @{$rsp->{data}}, "The 'hcp' property is not defined in the zvm table for $zvmHost node.";
 | |
|             xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|             return;
 | |
|         }
 | |
| 
 | |
|         # Add the parms for the new z/VM host to the list of running servers and their parms
 | |
|         if ( $ZVMdiscover eq '' ) {
 | |
|             $ZVMdiscover = "zvmhost=$zvmHost,$currTime,$textParam";
 | |
|         } else {
 | |
|             $ZVMdiscover .= ",zvmhost=$zvmHost,$currTime,$textParam";
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     my $siteTab = xCAT::Table->new( "site", -autocommit=>1 );
 | |
|     $siteTab->setAttribs( {"key" => "__ZVMDiscover"}, {"value" => "$ZVMdiscover"} );
 | |
|     $siteTab->commit();
 | |
|     $siteTab->close();
 | |
| 
 | |
|     xCAT::Utils->release_lock( $lock, 1 );
 | |
|     $lock = 0;
 | |
| 
 | |
|     # Start each new discovery.
 | |
|     foreach $zvmHost ( @newZvmhosts ) {
 | |
|         startDiscovery( $callback, $zvmHost, $zhcpServers{$zvmHost}, $currTime, \%param );
 | |
|     }
 | |
| 
 | |
|     # Common exit point to ensure that any lock has been freed.
 | |
| FINISH_NODEDISCOVERSTART:
 | |
|     # Release the lock if we obtained it.
 | |
|     if (( $lock != 1 ) and ( $lock != 0 )) {
 | |
|         xCAT::Utils->release_lock( $lock, 1 );
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3   nodediscoverstatus
 | |
| 
 | |
|     Description : Display the z/VM discovery status.
 | |
|     Arguments   : callback
 | |
|                   arguments for nodediscoverstatus
 | |
|     Returns     : None.
 | |
|     Example     : nodediscoverstatus( $callback, $args );
 | |
|     
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub nodediscoverstatus {
 | |
|     my $callback = shift;
 | |
|     my $args = shift;
 | |
| 
 | |
|     my @inputZvmHosts;       # Input list of z/VM host nodes
 | |
|     my $rsp;                 # Response buffer for output messages
 | |
|     my @runningZvmHosts;     # z/VM host nodes being queried
 | |
|     my $zvmHost;             # Small scope variable to temporarily hold a host node value
 | |
| 
 | |
|     # Valid attributes for z/VM discovery
 | |
|     my ( $help, $ver );
 | |
|     if ( !GetOptions(
 | |
|         'h|help' => \$help,
 | |
|         'v|version' => \$ver,
 | |
|         'z|zvmhost=s' => \$zvmHost )) {
 | |
|         # Return if unrecognized parms found so other discoveries can respond.
 | |
|         goto FINISH_NODEDISCOVERSTATUS;
 | |
|     }
 | |
| 
 | |
|     # Return if the user asked for help or version because sequential discovery will handle that.
 | |
|     if ( $help or $ver ) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     # Return if sequential or profile discovery is running or all are stopped.
 | |
|     # Sequential discovery will handle the response in that case.
 | |
|     my $SEQdiscover = getSiteVal("__SEQDiscover");
 | |
|     my $PCMdiscover = getSiteVal("__PCMDiscover");
 | |
|     my $ZVMdiscover = getSiteVal("__ZVMDiscover");
 | |
|     if (( $PCMdiscover or $SEQdiscover ) or ( !$SEQdiscover and !$PCMdiscover and !$ZVMdiscover )) {
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     # Put any specified zvmhosts into a hash that we can query.
 | |
|     if ( $zvmHost ) {
 | |
|         if ( index( $zvmHost, ',' ) != -1 ) {
 | |
|             # Must have specified multiple host node names
 | |
|             my @hosts = split( /,/, $zvmHost );
 | |
|             foreach $zvmHost ( @hosts ) {
 | |
|                 if ( !$zvmHost ) {
 | |
|                     # Tolerate zvmhost value beginning with a comma.  
 | |
|                     # It is wrong but not worth an error message.
 | |
|                     next;
 | |
|                 }
 | |
|                 push( @inputZvmHosts, $zvmHost );
 | |
|             }
 | |
|         } else {
 | |
|             push( @inputZvmHosts, $zvmHost );
 | |
|         }
 | |
|     } 
 | |
|     my %inputZvmHostsHash = map { $_ => 1 } @inputZvmHosts;
 | |
| 
 | |
|     # Get the list of z/VM hosts.
 | |
|     my $newZVMdiscover;
 | |
|     if ( $ZVMdiscover ) {
 | |
|         if ( $ZVMdiscover =~ '^zvmhost=' ) {
 | |
|             my @discoveries = split( /zvmhost=/, $ZVMdiscover );
 | |
|             foreach my $activeParms ( @discoveries ) {
 | |
|                 if ( !$activeParms ) {
 | |
|                     next;
 | |
|                 }
 | |
|                 if ( index( $activeParms, ',' ) != -1 ) {
 | |
|                     $zvmHost = substr( $activeParms, 0, index( $activeParms, ',' ));
 | |
|                 } else {
 | |
|                     $zvmHost = $activeParms;
 | |
|                 }
 | |
|                 push( @runningZvmHosts, $zvmHost );
 | |
|                 if ( exists( $inputZvmHostsHash{$zvmHost} )) {
 | |
|                     $inputZvmHostsHash{$zvmHost} = 2;
 | |
|                 }
 | |
|             }
 | |
|         } else {
 | |
|             # Not an expected format, Drop it when we push out the new saved parameters.
 | |
|             push @{$rsp->{data}}, "__ZVMDiscover property in the xCAT site table is corrupted.  It has been cleared so that all z/VM discovery stops.  You may restart z/VM discovery.";
 | |
|             xCAT::MsgUtils->message( "E", $rsp, $callback, 1 );
 | |
|             
 | |
|             # Remove the site.__ZVMDiscover property
 | |
|             # We don't need a lock because we are whipping out the value and not trying to keep it around.
 | |
|             my $siteTab = xCAT::Table->new( "site", -autocommit=>1 );
 | |
|             $siteTab->delEntries({key => '__ZVMDiscover'});
 | |
|             $siteTab->commit();
 | |
|             $siteTab->close();
 | |
|             undef $siteTab;
 | |
|             goto FINISH_NODEDISCOVERSTATUS;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     if ( !@inputZvmHosts ) {
 | |
|         # Not a specific status request so let's remind them that sequential
 | |
|         # and Profile discovery are stopped.
 | |
|         push @{$rsp->{data}}, "Sequential discovery is stopped.";
 | |
|         push @{$rsp->{data}}, "Profile discovery is stopped.";
 | |
|         xCAT::MsgUtils->message( "I", $rsp, $callback, 1 );
 | |
|     }
 | |
| 
 | |
|     # Inform the user about any node that is specified as input but is not running discovery.
 | |
|     if ( %inputZvmHostsHash ) {
 | |
|         # --zvmhost was specified so indicate a response for each host.
 | |
|         foreach $zvmHost ( keys %inputZvmHostsHash ) {
 | |
|             if ( $inputZvmHostsHash{$zvmHost} == 1 ) {
 | |
|                 push @{$rsp->{data}}, "z/VM Discovery is stopped for: $zvmHost.";
 | |
|                 xCAT::MsgUtils->message( "I", $rsp, $callback );
 | |
|             } else {
 | |
|                 push @{$rsp->{data}}, "z/VM Discovery is started for: $zvmHost.";
 | |
|                 xCAT::MsgUtils->message( "I", $rsp, $callback );
 | |
|             }
 | |
|         }
 | |
|     } else {
 | |
|         # --zvmhost was not specified so give a single line response.
 | |
|         if ( @runningZvmHosts ) {
 | |
|             my $runningList;
 | |
|             foreach $zvmHost ( @runningZvmHosts ) {
 | |
|                 if ( $runningList ) {
 | |
|                     $runningList .= ', ' . $zvmHost;
 | |
|                 } else {
 | |
|                     $runningList = $zvmHost;
 | |
|                 }
 | |
|             }
 | |
|             push @{$rsp->{data}}, "z/VM Discovery is started for: $runningList";
 | |
|             xCAT::MsgUtils->message( "I", $rsp, $callback );
 | |
|         } else {
 | |
|             # No on-going z/VM discovery.
 | |
|             push @{$rsp->{data}}, "z/VM Discovery is stopped.";
 | |
|             xCAT::MsgUtils->message( "I", $rsp, $callback );
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     # Common exit point to ensure that any lock has been freed.
 | |
|     # Currently, we do not use locks in this routine.
 | |
| FINISH_NODEDISCOVERSTATUS:
 | |
|     return;
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3   nodediscoverstop
 | |
| 
 | |
|     Description : Stop the z/VM discovery process.
 | |
|     Arguments   : callback
 | |
|                   arguments for nodediscoverstop
 | |
|                   $auto option (not used by z/VM)
 | |
|     Returns     : None.
 | |
|     Example     : nodediscoverstop( $callback, $args, $auto );
 | |
|     
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub nodediscoverstop {
 | |
|     my $callback = shift;
 | |
|     my $args = shift;
 | |
|     my $auto = shift;
 | |
| 
 | |
|     my @inputZvmHosts;       # Input list of z/VM host nodes to stop
 | |
|     my $rsp;                 # Response buffer for output messages
 | |
|     my @stoppingZvmHosts;    # z/VM host nodes that can be stopped because they are running
 | |
|     my $zvmHost;             # Small scope variable to temporarily hold a host node value
 | |
| 
 | |
|     # Check for a running of z/VM discovery
 | |
|     my $ZVMdiscover = getSiteVal("__ZVMDiscover");
 | |
|     if ( !$ZVMdiscover ) {
 | |
|         # Return so one of the other discoveries can handle the response.
 | |
|         goto FINISH_NODEDISCOVERSTOP;
 | |
|     }
 | |
| 
 | |
|     # Handle parameters
 | |
|     if ( $args ) {
 | |
|         @ARGV = @$args;
 | |
|     }
 | |
| 
 | |
|     my ( $help, $ver );
 | |
|     if ( !GetOptions(
 | |
|         'h|help' => \$help,
 | |
|         'v|version' => \$ver,
 | |
|         'z|zvmhost=s' => \$zvmHost )) {}
 | |
| 
 | |
|     # Return if the user asked for help or version because sequential will handle that.
 | |
|     if ( $help or $ver ) {
 | |
|         goto FINISH_NODEDISCOVERSTOP;
 | |
|     }
 | |
| 
 | |
|     if ( $zvmHost ) {
 | |
|         if ( index( $zvmHost, ',' ) != -1 ) {
 | |
|             # Must have specified multiple host node names
 | |
|             my @hosts = split( /,/, $zvmHost );
 | |
|             foreach $zvmHost ( @hosts ) {
 | |
|                 if ( !$zvmHost ) {
 | |
|                     # Tolerate zvmhost value beginning with a comma.  
 | |
|                     # It is wrong but not worth an error message.
 | |
|                     next;
 | |
|                 }
 | |
|                 push( @inputZvmHosts, $zvmHost );
 | |
|             }
 | |
|         } else {
 | |
|             push( @inputZvmHosts, $zvmHost );
 | |
|         }
 | |
|     } else {
 | |
|         # If zvmhost parm is not present then this is not a z/VM discovery.
 | |
|         push @{$rsp->{data}}, "nodediscoverstop did not specify a --zvmhost property.";
 | |
|         xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|         goto FINISH_NODEDISCOVERSTOP;
 | |
|     }
 | |
|     my %inputZvmHostsHash = map { $_ => 1 } @inputZvmHosts;
 | |
| 
 | |
|     # Obtain any on-going z/VM discovery parms and get the list of z/VM hosts.
 | |
|     my $ZVMdiscover = getSiteVal("__ZVMDiscover");
 | |
|     my $newZVMdiscover;
 | |
|     if ( $ZVMdiscover ) {
 | |
|         if ( $ZVMdiscover =~ '^zvmhost=' ) {
 | |
|             my @discoveries = split( /zvmhost=/, $ZVMdiscover );
 | |
|             foreach my $activeParms ( @discoveries ) {
 | |
|                 if ( !$activeParms ) {
 | |
|                     next;
 | |
|                 }
 | |
|                 if ( index( $activeParms, ',' ) != -1 ) {
 | |
|                     $zvmHost = substr( $activeParms, 0, index( $activeParms, ',' ));
 | |
|                 } else {
 | |
|                     $zvmHost = $activeParms;
 | |
|                 }
 | |
| 
 | |
|                 if ( exists( $inputZvmHostsHash{$zvmHost} )) {
 | |
|                     $inputZvmHostsHash{$zvmHost} = 2;
 | |
|                     push( @stoppingZvmHosts, $zvmHost );
 | |
|                 }
 | |
|             }
 | |
|         } else {
 | |
|             # Not an expected format, Drop it when we push out the new saved parameters.
 | |
|             push @{$rsp->{data}}, "__ZVMDiscover property in the xCAT site table is corrupted.  It has been cleared so that all z/VM discovery stops.  You may restart z/VM discovery.";
 | |
|             xCAT::MsgUtils->message( "E", $rsp, $callback, 1 );
 | |
|             
 | |
|             # Remove the site.__ZVMDiscover property
 | |
|             my $siteTab = xCAT::Table->new( "site", -autocommit=>1 );
 | |
|             $siteTab->delEntries({key => '__ZVMDiscover'});
 | |
|             $siteTab->commit();
 | |
|             $siteTab->close();
 | |
|             undef $siteTab;
 | |
|             goto FINISH_NODEDISCOVERSTOP;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     # Inform the user about any node that is specified as input but is not running discovery.
 | |
|     foreach $zvmHost ( keys %inputZvmHostsHash ) {
 | |
|         if ( $inputZvmHostsHash{$zvmHost} == 1 ) {
 | |
|             push @{$rsp->{data}}, "z/VM discovery is not running for node: $zvmHost.";
 | |
|             xCAT::MsgUtils->message("I", $rsp, $callback);
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     # Stop the host discovery immediately, if possible.
 | |
|     foreach $zvmHost ( @stoppingZvmHosts ) {
 | |
|         stopDiscovery( $callback, $zvmHost, \@ARGV );
 | |
|     }
 | |
| 
 | |
|     # Common exit point.
 | |
| FINISH_NODEDISCOVERSTOP:
 | |
|     return;
 | |
| }
 | |
| 
 | |
| 
 | |
| #-----------------------------------------------------
 | |
| =head3  parse_runxcmd_ret
 | |
| 
 | |
|     Description : Get return of runxcmd and convert it into strings.
 | |
|     Arguments   : The return reference of runxcmd
 | |
|     Returns     : [$outstr, $errstr], A reference of list, placing 
 | |
|                   standard output and standard error message.
 | |
|     Example     : my $retStrRef = parse_runxcmd_ret($retRef);
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #-----------------------------------------------------
 | |
| sub parse_runxcmd_ret {
 | |
|     my $retRef = shift;
 | |
| 
 | |
|     my $msglistref;
 | |
|     my $outstr = "";
 | |
|     my $errstr = "";
 | |
|     if ($retRef){
 | |
|         if($retRef->{data}){
 | |
|             $msglistref = $retRef->{data};
 | |
|             $outstr = Dumper(@$msglistref);
 | |
|             xCAT::MsgUtils->message( 'S', "Command standard output: $outstr" );
 | |
|         }
 | |
|         if($retRef->{error}){
 | |
|             $msglistref = $retRef->{error};
 | |
|             $errstr =  Dumper(@$msglistref);
 | |
|             xCAT::MsgUtils->message( 'S', "Command error output: $errstr" );
 | |
|         }
 | |
|     }
 | |
|     return [$outstr, $errstr];
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3   process_request
 | |
| 
 | |
|     Description : Process a request and drive the function handler.
 | |
|     Arguments   : Request handle
 | |
|                   Callback handle
 | |
|                   Command that is requested
 | |
|     Returns     : None
 | |
|     Example     : process_request( $request, $callback, $request_command );
 | |
|     
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub process_request {
 | |
|     my $request = shift;
 | |
|     my $callback = shift;
 | |
|     $request_command = shift;
 | |
| 
 | |
|     my $command = $request->{command}->[0];
 | |
|     my $args = $request->{arg};
 | |
| 
 | |
|     if ($command eq "findme"){
 | |
|         if (defined($request->{discoverymethod}) and defined($request->{discoverymethod}->[0]) and ($request->{discoverymethod}->[0] ne 'undef')) {
 | |
| 
 | |
|             # The findme request had been processed by other module, just return
 | |
|             return;
 | |
|         }
 | |
|         findme( $request, $callback, $request_command );
 | |
|     } elsif ($command eq "nodediscoverls") {
 | |
|         nodediscoverls( $callback, $args );
 | |
|     } elsif ($command eq "nodediscoverstart") {
 | |
|         nodediscoverstart( $callback, $args );
 | |
|     } elsif ($command eq "nodediscoverstop") {
 | |
|         nodediscoverstop( $callback, $args );
 | |
|     } elsif ($command eq "nodediscoverstatus") {
 | |
|         nodediscoverstatus( $callback, $args );
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3   removeHostInfo
 | |
| 
 | |
|     Description : Remove z/VM host info from the __ZVMDiscover
 | |
|                   property in the site table.
 | |
|     Arguments   : Callback handle
 | |
|                   z/VM host node name
 | |
|     Returns     : None.
 | |
|     Example     : $rc = removeHostInfo( $callback, $zvmHost );
 | |
|     
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub removeHostInfo {
 | |
|     my $callback = shift;
 | |
|     my $zvmHost = shift;
 | |
| 
 | |
|     my $lock = 0;            # Lock word, 0: not obtained, 1: lock failed, other: lock handle
 | |
|     my $rsp;                 # Response buffer for output messages
 | |
| 
 | |
|     # Obtain any on-going z/VM discovery parms and get the list of z/VM hosts.
 | |
|     $lock = xCAT::Utils->acquire_lock( "nodemgmt", 0 );
 | |
|     if ( $lock == 1 ) {
 | |
|         push @{$rsp->{data}}, "Unable to acquire the 'nodemgmt' lock to protect __ZVMDiscover property in the xCAT site table.";
 | |
|         xCAT::MsgUtils->message( "E", $rsp, $callback, 1 );
 | |
|         goto FINISH_removeHostInfo;
 | |
|     }
 | |
| 
 | |
|     my $origZVMdiscover = getSiteVal("__ZVMDiscover");
 | |
|     my $newZVMdiscover;
 | |
|     if ( $origZVMdiscover ) {
 | |
|         if ( $origZVMdiscover =~ '^zvmhost=' ) {
 | |
|             my $currHost;
 | |
|             my @discoveries = split( /zvmhost=/, $origZVMdiscover );
 | |
|             foreach my $activeParms ( @discoveries ) {
 | |
|                 if ( !$activeParms ) {
 | |
|                     next;
 | |
|                 }
 | |
|                 if ( index( $activeParms, ',' ) != -1 ) {
 | |
|                     $currHost = substr( $activeParms, 0, index( $activeParms, ',' ));
 | |
|                 } else {
 | |
|                     $currHost = $activeParms;
 | |
|                 }
 | |
| 
 | |
|                 if ( $zvmHost ne $currHost ) {
 | |
|                     # Not stopping this host so keep it in the new __ZVMdiscover property.
 | |
|                     $activeParms =~ s/\,+$//;
 | |
|                     my $hostDiscParms = "zvmhost=$activeParms";
 | |
|                     if ( $newZVMdiscover ) {
 | |
|                         $newZVMdiscover = "$newZVMdiscover,$hostDiscParms";
 | |
|                     } else {
 | |
|                         $newZVMdiscover = $hostDiscParms;
 | |
|                     }
 | |
|                 }
 | |
|             }
 | |
|         } else {
 | |
|             # Not an expected format, Drop it when we push out the new saved parameters.
 | |
|             push @{$rsp->{data}}, "__ZVMDiscover property in the xCAT site table is corrupted.  It has been cleared so that all z/VM discovery stops.  You may restart z/VM discovery.";
 | |
|             xCAT::MsgUtils->message( "E", $rsp, $callback, 1 );
 | |
| 
 | |
|             # Remove the site table's '__ZVMDiscover property.
 | |
|             my $siteTab = xCAT::Table->new( "site", -autocommit=>1 );
 | |
|             $siteTab->delEntries({key => '__ZVMDiscover'});
 | |
|             $siteTab->commit();
 | |
|             $siteTab->close();
 | |
|             undef $siteTab;
 | |
|             goto FINISH_removeHostInfo;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     # Update the site table to have the remaining discovery host information.
 | |
|     my $siteTab = xCAT::Table->new( "site", -autocommit=>1 );
 | |
|     if ( !$newZVMdiscover ) {
 | |
|         $siteTab->delEntries({key => '__ZVMDiscover'});
 | |
|     } else {
 | |
|         $siteTab->setAttribs({"key" => "__ZVMDiscover"}, {"value" => "$newZVMdiscover"});
 | |
|     }
 | |
|     $siteTab->commit();
 | |
|     $siteTab->close();
 | |
|     undef $siteTab;
 | |
| 
 | |
|     # Common exit point so we can make certain to release any lock that is held.
 | |
| FINISH_removeHostInfo:
 | |
|     # Release the lock if we obtained it.
 | |
|     if (( $lock != 1 ) and ( $lock != 0 )) {
 | |
|         xCAT::Utils->release_lock( $lock, 1 );
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3   startDiscovery
 | |
| 
 | |
|     Description : Start z/VM discovery for a particular z/VM host.
 | |
|     Arguments   : Callback handle
 | |
|                   z/VM host node name
 | |
|                   ZHCP
 | |
|                   Start time of the discovery
 | |
|                   Hash of arguments specified on the nodediscoverstart 
 | |
|                     command and their values
 | |
|     Returns     : None
 | |
|     Example     : startDiscovery( $callback, $zvmHost, $hcp, $startTime, \%args );
 | |
|     
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub startDiscovery{
 | |
|     my $callback = shift;
 | |
|     my $zvmHost = shift;
 | |
|     my $hcp = shift;
 | |
|     my $initStartTime = shift;
 | |
|     my $argsRef = shift;
 | |
|     my %args = %$argsRef;
 | |
| 
 | |
|     my $numeric = "";             # Numeric portion of last generated node name
 | |
|     my $out;                      # Output work buffer
 | |
|     my $rc;                       # Return code
 | |
|     my $rsp;                      # Response buffer for output messages
 | |
|     my $startOpenStack = 0;       # Tell OpenStack provisioner to begin, 0: no, 1: yes
 | |
| 
 | |
|     push @{$rsp->{data}}, "z/VM discovery started for $zvmHost";
 | |
|     xCAT::MsgUtils->message( "I", $rsp, $callback );
 | |
| 
 | |
|     # Clean the entries in the discoverydata table for discovery method 'zvm'
 | |
|     # and the specific zvmHost that we are going to begin to discover.
 | |
|     my $disTab = xCAT::Table->new("discoverydata");
 | |
|     if ( !$disTab ) {
 | |
|         my $rsp;
 | |
|         push @{$rsp->{data}}, "Could not open table: discoverydata.";
 | |
|         xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|         goto FINISH_startDiscovery;
 | |
|     }
 | |
|     
 | |
|     my %keyhash;
 | |
|     $keyhash{'method'} = 'zvm';
 | |
|     $keyhash{'otherdata'} = "zvmhost." . $zvmHost;
 | |
|     $disTab->delEntries( \%keyhash );
 | |
|     $disTab->commit();
 | |
|     
 | |
|     # Handle 'openstackonly' discovery or get the template for 'both' discovery.
 | |
|     if ( $args{'defineto'} eq 'openstackonly' ) {
 | |
|         # Verify that OpenStack has a valid template to use when it is called 
 | |
|         # to handle the node.
 | |
|         my ( $osTemplate, $osNumeric ) = getOpenStackTemplate( $callback, $zvmHost );
 | |
|         if ( $osTemplate eq '' ) {
 | |
|             # An error was detected in the template and message produced leave now.
 | |
|             goto FINISH_startDiscovery;
 | |
|         }
 | |
|         # Discover the xCAT nodes available to OpenStack
 | |
|         $out = addPrevDisc( $callback, $zvmHost, $hcp, $initStartTime, \%args );
 | |
|         goto FINISH_startDiscovery;
 | |
|     } elsif ( $args{'defineto'} eq 'both') {
 | |
|         # Obtain the template and highest numeric value from OpenStack
 | |
|         my ( $osTemplate, $osNumeric ) = getOpenStackTemplate( $callback, $zvmHost );
 | |
|         if ( $osTemplate ne '' ) {
 | |
|             $args{'nodenameformat'} = $osTemplate;
 | |
|             $numeric = $osNumeric;
 | |
|         } else {
 | |
|             # An error was detected in the template and message produced leave now.
 | |
|             goto FINISH_startDiscovery;
 | |
|         }
 | |
|         
 | |
|         $startOpenStack = 1;
 | |
|     }
 | |
| 
 | |
|     # Get the current list of node names.
 | |
|     my @nodeNames;
 | |
|     my $nodelistTab = xCAT::Table->new('nodelist');
 | |
|     if ( !$nodelistTab ) {
 | |
|         push @{$rsp->{data}}, "Could not open table: nodelist.";
 | |
|         xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|         goto FINISH_startDiscovery;
 | |
|     }
 | |
| 
 | |
|     my @attribs = ('node');
 | |
|     my @nodes = $nodelistTab->getAllAttribs( @attribs );
 | |
|     foreach my $node ( @nodes ) {
 | |
|         push @nodeNames,$node->{'node'};
 | |
|     }
 | |
|     @nodes = sort @nodeNames;
 | |
|     my %xcatNodes = map { $_ => 1 } @nodes;
 | |
| 
 | |
|     # Obtain the list of logged on users.
 | |
|     $out = `ssh -q $::SUDOER\@$hcp $::SUDO $ZHCP_BIN/smcli "Image_Status_Query '-T *'"`;
 | |
|     $rc = $? >> 8;
 | |
|     if ( $rc == 255 ) {
 | |
|         push @{$rsp->{data}}, "z/VM discovery is unable to communicate with the zhcp system: $hcp";
 | |
|         xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|         goto FINISH_startDiscovery;
 | |
|     } elsif ( $rc != 0 ) {
 | |
|         my $rsp;
 | |
|         push @{$rsp->{data}}, "An unexpected return code $rc was received from " .
 | |
|                               "the zhcp server $hcp for an smcli Image_Status_Query " .
 | |
|                               "request.  SMAPI servers may be unavailable.  " .
 | |
|                               "Received response: $out";
 | |
|             
 | |
|         xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|         goto FINISH_startDiscovery;
 | |
|     }
 | |
| 
 | |
|     # Build the hash of running systems.
 | |
|     my @runningSystems = split( "\n", lc( $out ) );
 | |
| 
 | |
|     # Create a hash of discoverable systems by starting with the 
 | |
|     # list of running systems and removing any systems in the
 | |
|     # list of non-discoverable (known to be z/VM servers or 
 | |
|     # non-Linux systems).
 | |
|     my @nonDiscoverable = (
 | |
|         'auditor',  'autolog1', 'autolog2', 'avsvm',
 | |
|         'bldcms',   'bldnuc',   'bldracf',  'bldseg',
 | |
|         'cbdiodsp', 'cmsbatch',
 | |
|         'datamove', 'datamov2', 'datamov3', 'datamov4', 'diskacnt',
 | |
|         'dirmaint', 'dirmsat',  'dirmsat2', 'dirmsat3', 'dirmsat4',
 | |
|         'dtcens1',  'dtcens2',  'dtcsmapi', 'dtcvsw1',  'dtcvsw2',
 | |
|         'erep',
 | |
|         'ftpserve', 'gcs',      'gskadmin',
 | |
|         'ibmuser',  'imap',     'imapauth',
 | |
|         'ldapsrv',  'lohcost',
 | |
|         'maint',    'maint630', 'maint640',
 | |
|         'migmaint', 'monwrite', 'mproute',
 | |
|         'operator', 'operatns', 'opersymp', 'opncloud',
 | |
|         'osadmin1', 'osadmin2', 'osadmin3',
 | |
|         'osamaint', 'osasf',    'ovfdev62',
 | |
|         'perfsvm',  'persmapi', 'pmaint',   'portmap',
 | |
|         'racfsmf',  'racfvm',   'racmaint', 'rexecd',
 | |
|         'rscs',     'rscsauth', 'rscsdns',  'rxagent1',
 | |
|         'smtp',     'snmpd',    'snmpsuba', 'ssl',      'ssldcssm',
 | |
|         'sysadmin', 'sysmon',
 | |
|         'tcpip',    'tcpmaint', 'tsafvm',
 | |
|         'uftd',
 | |
|         'vmnfs',    'vmrmadmn', 'vmrmsvm',
 | |
|         'vmservp',  'vmservr',  'vmservu',  'vmservs',  'vsmevsrv',
 | |
|         'vsmguard', 'vsmproxy', 'vsmreqim', 'vsmreqin', 'vsmreqiu',
 | |
|         'vsmreqi6', 'vsmwork1', 'vsmwork2', 'vsmwork3', 'vsmwork4',
 | |
|         'vsmwork5', 'vsmwork6', 'vsmwork7', 'vsmwork8', 'vsmwork9',
 | |
|         'xcat',     'xcatserv', 'xchange',
 | |
|         'zhcp',     'zvmlxapp', 'zvmmaplx',
 | |
|         '4osasf40', '5684042j', '6vmdir30', '6vmhcd20', '6vmlen20',
 | |
|         '6vmptk30', '6vmrac30', '6vmrsc30', '6vmtcp30',
 | |
|     );
 | |
|     my %discoverable;
 | |
|     @discoverable {@runningSystems} = ( );
 | |
|     delete @discoverable{@nonDiscoverable};
 | |
| 
 | |
|     # Apply any user specified userid filter to the list to weed it further.
 | |
|     if ( $args{'useridfilter'} ) {
 | |
|         if ( $args{'verbose'} ) {
 | |
|             push @{$rsp->{data}}, "Applying useridfilter: '" . $args{'useridfilter'} . "'";
 | |
|             xCAT::MsgUtils->message( "I", $rsp, $callback );
 | |
|         }
 | |
|         foreach my $activeSystem ( keys %discoverable ) {
 | |
|             if ( $activeSystem !~ m/$args{'useridfilter'}/i ) {
 | |
|                 delete( $discoverable{$activeSystem} );
 | |
|                 if ( $args{'verbose'} ) {
 | |
|                     push @{$rsp->{data}}, "ignoring: $activeSystem - filtered by user";
 | |
|                     xCAT::MsgUtils->message( "I", $rsp, $callback );
 | |
|                 }
 | |
|             } else {
 | |
|                 if ( $args{'verbose'} ) {
 | |
|                     push @{$rsp->{data}}, "keeping: $activeSystem";
 | |
|                     xCAT::MsgUtils->message( "I", $rsp, $callback );
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     # Determine the long and short zhcp DNS name.
 | |
|     my ( $longName, $shortName );
 | |
|     if ( $hcp =~ /\./ ) {
 | |
|         $longName = lc( $hcp );
 | |
|         my @parts = split( /\./, $longName );
 | |
|         if ( $parts[0] ne '' ) {
 | |
|             $shortName = $parts[0];
 | |
|         }
 | |
|     } else {
 | |
|         $shortName = lc( $hcp );
 | |
|     }
 | |
|     if (( !defined $longName ) && ( -e '/etc/hosts' )) {
 | |
|         # Search /etc/hosts for the short name in a non-commented out portion of the lines and
 | |
|         # look for the long name (contains periods).  The short and long form can be in any order
 | |
|         # after the IP address.
 | |
|         $out = `cat /etc/hosts | sed 's/#\.*\$//g' | sed 's/\$/ /g' | grep -i " $shortName "`;
 | |
|         my @lines = split( /\n/, $out );
 | |
|         my @parts = split( / /, $lines[0] );
 | |
|         my $numParts = @parts;
 | |
|         for( my $i = 1; $i < $numParts; $i++ ) {
 | |
|             if ( $parts[$i] =~ /\./ ) {
 | |
|                 $longName = lc( $parts[$i] );
 | |
|                 last;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     # Get the list of systems that are known to xCAT already for this host.
 | |
|     my %knownToXCAT;
 | |
|     my @knownUserids;
 | |
|     my $zvmTab = xCAT::Table->new("zvm");
 | |
|     my @attribs = ('hcp', 'userid');
 | |
|     @nodes = $zvmTab->getAllAttribs( @attribs );
 | |
|     foreach my $nodeRef ( @nodes ) {
 | |
|         my $nodeHCP;
 | |
|         if ( $nodeRef->{'hcp'} && $nodeRef->{'userid'} ) {
 | |
|             $nodeHCP = lc( $nodeRef->{'hcp'} );
 | |
|             if ((( defined $longName) && ( $longName eq $nodeHCP )) || 
 | |
|                 (( defined $shortName) && ( $shortName eq $nodeHCP ))) {
 | |
|                 push @knownUserids, lc( $nodeRef->{'userid'} );
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     my %knownToXCAT = map { $_ => 1 } @knownUserids;
 | |
| 
 | |
|     # Weed out any systems that are already defined as xCAT nodes.
 | |
|     foreach my $activeSystem ( keys %discoverable ) {
 | |
|         if ( $knownToXCAT{$activeSystem} ) {
 | |
|             delete( $discoverable{$activeSystem} );
 | |
|             if ( $args{'verbose'} ) {
 | |
|                 push @{$rsp->{data}}, "ignoring: $activeSystem - already defined to xCAT";
 | |
|                 xCAT::MsgUtils->message( "I", $rsp, $callback );
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     my $numSystems = scalar( keys %discoverable );
 | |
|     xCAT::MsgUtils->message( "S", "Discovery for $zvmHost found $numSystems virtual machines." );
 | |
| 
 | |
|     # Perform a set of potentially long running functions.  We do this one 
 | |
|     # server at a time so that we can stop if we are told to do so.
 | |
|     # Loop through the list performing the following:
 | |
|     #   - See if discovery has been stopped early.
 | |
|     #   - Attempt to access the system to identify which server can be discovered.
 | |
|     #   - Contact the system to obtain system information.
 | |
|     #   - Create a xCAT node and update xCAT tables.
 | |
|     #   - Drive the OpenStack definition of the node, if requested.
 | |
|     my ($ipAddr,$ipVersion, $hostname);
 | |
|     foreach my $activeSystem ( keys %discoverable ) {
 | |
| 
 | |
|         # Exit if we have been asked to stop discovery for this host.
 | |
|         my $startTime = getRunningDiscTimestamp( $callback, $zvmHost );
 | |
|         if ( $startTime != $initStartTime ) {
 | |
|             # Start time for this run is different from start time in the site table.
 | |
|             # User must have stopped and restarted discovery for this host.
 | |
|             # End now to let other discovery handle the work.
 | |
|             push @{$rsp->{data}}, "Stopping due to a detected stop request.";
 | |
|             xCAT::MsgUtils->message("I", $rsp, $callback);
 | |
|             goto FINISH_startDiscovery;
 | |
|         }
 | |
| 
 | |
|         # Further refine the list by finding only systems which have a NICs with known IP addresses
 | |
|         # that will allow us to SSH into them.
 | |
|         $rc = xCAT::zvmUtils->findAccessIP( $callback, $activeSystem, $hcp, \%discoverable, \%args, $::SUDOER );
 | |
|         if ( $rc != 0 ) {
 | |
|             delete( $discoverable{$activeSystem} );
 | |
|             if ( $args{'verbose'} ) {
 | |
|                 push @{$rsp->{data}}, "ignoring: $activeSystem - could not access the virtual server.";
 | |
|                 xCAT::MsgUtils->message( "I", $rsp, $callback );
 | |
|             }
 | |
|             next;
 | |
|         }
 | |
| 
 | |
|         # Obtain the memory and CPU count from the active system information.
 | |
|         $out = `ssh -q $::SUDOER\@$hcp $::SUDO $ZHCP_BIN/smcli "Image_Active_Configuration_Query -T '$activeSystem'"`;
 | |
|         $rc = $? >> 8;
 | |
|         if ($rc == 255) {
 | |
|             delete( $discoverable{$activeSystem} );
 | |
|             push @{$rsp->{data}}, "z/VM discovery is unable to communicate with the zhcp system: $hcp";
 | |
|             xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|             next;
 | |
|         } elsif ( $rc != 0 ) {
 | |
|             my $rsp;
 | |
|             push @{$rsp->{data}}, "An unexpected return code $rc was received from " .
 | |
|                                   "the zhcp server $hcp for an smcli Image_Active_Configuration_Query " .
 | |
|                                   "request.  SMAPI servers may be unavailable.  " .
 | |
|                                   "Received response: $out";
 | |
|             xCAT::MsgUtils->message("E", $rsp, $callback);
 | |
|             next;
 | |
|         }
 | |
| 
 | |
|         my $memOut = `echo "$out" | egrep -i 'Memory:'`;
 | |
|         chomp $memOut;
 | |
|         my @parts = split( /Memory: /, $memOut );
 | |
|         @parts = split( / /, $parts[1] );
 | |
|         $discoverable{$activeSystem}{'memory'} = $parts[0].$parts[1];
 | |
|         my $cpuOut = `echo "$out" | egrep -i 'CPU count:'`;
 | |
|         chomp $cpuOut;
 | |
|         @parts = split( 'CPU count: ', $cpuOut );
 | |
|         $discoverable{$activeSystem}{'cpuCount'} = $parts[1];
 | |
| 
 | |
|         my $os = xCAT::zvmUtils->getOSFromIP( $callback, $activeSystem, $discoverable{$activeSystem}{'ipAddr'}, $discoverable{$activeSystem}{'ipVersion'} );
 | |
|         if ( $os ne '' ) {
 | |
|             $discoverable{$activeSystem}{'os'} = $os;
 | |
|         } else {
 | |
|             if ( $args{'verbose'} ) {
 | |
|                 push @{$rsp->{data}}, "ignoring: $activeSystem - unable to obtain OS version information from the operating system";
 | |
|                 xCAT::MsgUtils->message( "I", $rsp, $callback );
 | |
|             }
 | |
|             delete( $discoverable{$activeSystem} );
 | |
|             next;
 | |
|         }
 | |
| 
 | |
|         xCAT::MsgUtils->message( "S", "Discovery for $zvmHost is preparing to create a node for $activeSystem." );
 | |
| 
 | |
|         # Set up to define the node.
 | |
|         $discoverable{$activeSystem}{'uuid'} = xCAT::Utils::genUUID();
 | |
|         $discoverable{$activeSystem}{'openstackoperands'} = $args{'openstackoperands'};
 | |
| 
 | |
|         # Generate an xCAT node name for the newly discovered system.
 | |
|         my $node;
 | |
| 
 | |
|         # Create an xCAT node.
 | |
|         my $retstr_gen = '';
 | |
| 
 | |
|         $retstr_gen .= "    arch=s390x\n";
 | |
|         if ( $args{'groups'} ) {
 | |
|             $retstr_gen .= "    groups=$args{'groups'}\n";
 | |
|         } else {
 | |
|             $retstr_gen .= "    groups=all\n";
 | |
|         }
 | |
|         $retstr_gen .= "    hcp=$hcp\n";
 | |
|         if ( $discoverable{$activeSystem}{'hostname'} ) {
 | |
|             $retstr_gen .= "    hostnames=$discoverable{$activeSystem}{'hostname'}\n";
 | |
|         }
 | |
|         $retstr_gen .= "    ip=$discoverable{$activeSystem}{'ipAddr'}\n";
 | |
|         $retstr_gen .= "    mgt=zvm\n";
 | |
|         $retstr_gen .= "    objtype=node\n";
 | |
|         $retstr_gen .= "    os=$discoverable{$activeSystem}{'os'}\n";
 | |
|         $retstr_gen .= "    userid=$activeSystem\n";
 | |
| 
 | |
|         ( $node, $numeric ) = createNode( $callback, $discoverable{$activeSystem}{'hostname'}, $args{'nodenameformat'}, $numeric, $retstr_gen, \%xcatNodes );
 | |
|         if ( $node eq '' ) {
 | |
|             # If we cannot create a node then skip this one and go on to the next.
 | |
|             next;
 | |
|         }
 | |
|         $discoverable{$activeSystem}{'node'} = $node;
 | |
| 
 | |
|         # Start OpenStack Provisioning for this node, if desired.
 | |
|         if ( $startOpenStack ) {
 | |
|             my $openstackNodeName = addOpenStackSystem( $callback, $zvmHost, $hcp, $args{'verbose'}, $activeSystem, \%discoverable );
 | |
| 
 | |
|             if ( !$openstackNodeName ) {
 | |
|                 # Node was not created in OpenStack.  Remove it from xCAT.
 | |
|                 changeNode( $callback, $node, 'd' );
 | |
|                 next;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         updateDiscoverydata( $callback, 'add', $args{'verbose'}, $zvmHost, $activeSystem, \%discoverable );
 | |
|     }
 | |
| 
 | |
|     # Common exit point.
 | |
| FINISH_startDiscovery:
 | |
|     my $startTime = getRunningDiscTimestamp( $callback, $zvmHost );
 | |
|     if ( $startTime == $initStartTime ) {
 | |
|         my @stopArgs = ();
 | |
|         stopDiscovery( $callback, $zvmHost, \@stopArgs );
 | |
|     }
 | |
|     return;
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3   stopDiscovery
 | |
| 
 | |
|     Description : Stop z/VM discovery for a particular z/VM host.
 | |
|     Arguments   : Callback handle
 | |
|                   z/VM host node name
 | |
|                   Array of arguments specified on nodediscoverstop or 
 | |
|                     an empty array if this is an internal call.
 | |
|     Returns     : None.
 | |
|     Example     : stopDiscovery( $callback, $zvmHost, \@args );
 | |
|     
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub stopDiscovery{
 | |
|     my $callback = shift;
 | |
|     my $zvmHost = shift;
 | |
|     my $argsRef = shift;
 | |
|     my @args = @$argsRef;
 | |
| 
 | |
|     my $rsp;
 | |
|     push @{$rsp->{data}}, "z/VM discovery is being stopped for $zvmHost.";
 | |
|     xCAT::MsgUtils->message( "I", $rsp, $callback, 1 );
 | |
| 
 | |
|     # Get the hcp from the zvm table.
 | |
|     my @propNames = ( 'hcp', 'nodetype' );
 | |
|     my $propVals = xCAT::zvmUtils->getNodeProps( 'zvm', $zvmHost, @propNames );
 | |
|     my $hcp = $propVals->{'hcp'};
 | |
| 
 | |
|     # Get the list of discovered systems from the zvm table.
 | |
|     my $zvmTab = xCAT::Table->new('zvm');
 | |
|     if ( !$zvmTab ) {
 | |
|         push @{$rsp->{data}}, "Could not open table: zvm.";
 | |
|         xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     my %discoveredNodes;
 | |
|     my @zvmData = $zvmTab->getAllAttribsWhere( "hcp='$hcp'", 'node', 'userid' );
 | |
|     foreach ( @zvmData ) {
 | |
|         $discoveredNodes{$_->{'node'}} = $_->{'userid'};
 | |
|     }
 | |
| 
 | |
|     # Go though the discoverydata table and display the z/VM discovery entries
 | |
|     my $disTab = xCAT::Table->new('discoverydata');
 | |
|     if ( !$disTab ) {
 | |
|         push @{$rsp->{data}}, "Could not open table: discoverydata.";
 | |
|         xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     my @disData = $disTab->getAllAttribsWhere( "method='zvm' and otherdata='zvmhost.$zvmHost'", 'node' );
 | |
|     push @{$rsp->{data}}, "Discovered ".($#disData+1)." nodes running on $zvmHost.";
 | |
| 
 | |
|     if ( @disData ) {
 | |
|         push @{$rsp->{data}}, sprintf("    %-20s%-8s", 'NODE', 'z/VM USERID');
 | |
|         foreach ( @disData ) {
 | |
|              push @{$rsp->{data}}, sprintf("    %-20s%-8s", $_->{'node'}, $discoveredNodes{$_->{'node'}} ); 
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     removeHostInfo( $callback, $zvmHost );
 | |
|     
 | |
|     xCAT::MsgUtils->message( "I", $rsp, $callback );
 | |
|     xCAT::MsgUtils->message( "I", "z/VM discovery stopped for z/VM host: $zvmHost" );
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| 
 | |
| =head3  updateDiscoverydata
 | |
| 
 | |
|     Description : Update the discoverydata table.
 | |
|     Arguments   : Callback handle
 | |
|                   function: 'add' is the only function
 | |
|                     currently supported.
 | |
|                   verbose flag
 | |
|                   z/VM host node name
 | |
|                   Virtual machine userid
 | |
|                   discoverable hash which contains lots of properties
 | |
|     Returns     : None.
 | |
|     Example     : updateDiscoverydata( $callback, 'add', $verbose, $zvmHost,
 | |
|                                        $activeSystem, \%discoverable ):
 | |
|     
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------
 | |
| sub updateDiscoverydata{
 | |
|     my ( $callback, $function, $verbose, $zvmHost, $activeSystem, $discoverableRef ) = @_;
 | |
|     my %discoverable = %$discoverableRef;
 | |
| 
 | |
|     my %discoverInfo;
 | |
|     my $disTab = xCAT::Table->new("discoverydata");
 | |
|     if ( !$disTab ) {
 | |
|         my $rsp;
 | |
|         push @{$rsp->{data}}, "Could not open table: discoverydata.";
 | |
|         xCAT::MsgUtils->message( "E", $rsp, $callback );
 | |
|         goto FINISH_updateDiscoverydata;
 | |
|     }
 | |
| 
 | |
|     if ( $function = 'add' ) {
 | |
|         # Create a row in the discoverydata table to represent this discovered system.
 | |
|         $discoverInfo{'arch'} = "s390x";
 | |
|         $discoverInfo{'cpucount'} = $discoverable{$activeSystem}{'cpuCount'};
 | |
|         $discoverInfo{'memory'} = $discoverable{$activeSystem}{'memory'};
 | |
|         $discoverInfo{'method'} = "zvm";
 | |
|         $discoverInfo{'node'} = $discoverable{$activeSystem}{'node'};
 | |
|         $discoverInfo{'otherdata'} = 'zvmhost.' . $zvmHost;
 | |
| 
 | |
|         # Set the discovery time.
 | |
|         my ($sec,  $min,  $hour, $mday, $mon, $year, $wday, $yday, $isdst) = localtime(time);
 | |
|         my $currtime = sprintf("%02d-%02d-%04d %02d:%02d:%02d",
 | |
|                                $mon + 1, $mday, $year + 1900, $hour, $min, $sec);
 | |
|         $discoverInfo{'discoverytime'} = $currtime;
 | |
| 
 | |
|         # Update the discoverydata table.
 | |
|         $disTab->setAttribs({uuid => $discoverable{$activeSystem}{'uuid'}}, \%discoverInfo);
 | |
|         $disTab->commit();
 | |
|     }
 | |
| 
 | |
| FINISH_updateDiscoverydata:
 | |
|     return;
 | |
| }
 | |
| 1;
 |