mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-31 03:12:30 +00:00 
			
		
		
		
	
		
			
				
	
	
		
			488 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			488 lines
		
	
	
		
			14 KiB
		
	
	
	
		
			Perl
		
	
	
		
			Executable File
		
	
	
	
	
| #!/usr/bin/env perl
 | |
| # IBM(c) 2015 EPL license http://www.eclipse.org/legal/epl-v10.html
 | |
| 
 | |
| package xCAT_plugin::makentp;
 | |
| 
 | |
| BEGIN
 | |
| {
 | |
|     $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat';
 | |
| }
 | |
| use lib "$::XCATROOT/lib/perl";
 | |
| 
 | |
| use Getopt::Long;
 | |
| use xCAT::Usage;
 | |
| use xCAT::NetworkUtils;
 | |
| use xCAT::TableUtils;
 | |
| use xCAT::Utils;
 | |
| use XML::Simple;
 | |
| no strict;
 | |
| use Data::Dumper;
 | |
| use Socket;
 | |
| 
 | |
| my %globalopt;
 | |
| 
 | |
| #-------------------------------------------------------------------------------
 | |
| 
 | |
| =head1  xCAT_plugin:makentp
 | |
| =head2    Package Description
 | |
|     Handles ntp server setup on a xCAT management node.
 | |
| =cut
 | |
| 
 | |
| #-------------------------------------------------------------------------------
 | |
| 
 | |
| 
 | |
| #--------------------------------------------------------------------------------
 | |
| 
 | |
| =head3   send_msg
 | |
|       Invokes the callback with the specified message
 | |
|     Arguments:
 | |
|         request: request structure for plguin calls
 | |
|         ecode: error code. 0 for succeful.
 | |
|         msg: messages to be displayed.
 | |
|     Returns:
 | |
|         none
 | |
| =cut
 | |
| 
 | |
| #--------------------------------------------------------------------------------
 | |
| sub send_msg {
 | |
| 
 | |
|     my $request = shift;
 | |
|     my $ecode   = shift;
 | |
|     my $msg     = shift;
 | |
|     my %output;
 | |
| 
 | |
|     # Called from child process - send to parent
 | |
|     if (exists($request->{pipe})) {
 | |
|         my $out = $request->{pipe};
 | |
| 
 | |
|         $output{errorcode} = $ecode;
 | |
|         $output{data}      = \@_;
 | |
|         print $out freeze([ \%output ]);
 | |
|         print $out "\nENDOFFREEZE6sK4ci\n";
 | |
|     }
 | |
| 
 | |
|     # Called from parent - invoke callback directly
 | |
|     elsif (exists($request->{callback})) {
 | |
|         my $callback = $request->{callback};
 | |
|         $output{errorcode} = $ecode;
 | |
|         $output{data}->[0] = $msg;
 | |
|         $callback->(\%output);
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| #--------------------------------------------------------------------------------
 | |
| 
 | |
| =head3   handled_commands
 | |
|       It returns a list of commands handled by this plugin.
 | |
|     Arguments:
 | |
|        none
 | |
|     Returns:
 | |
|        a list of commands.
 | |
| =cut
 | |
| 
 | |
| #--------------------------------------------------------------------------------
 | |
| sub handled_commands {
 | |
|     return ({ makentp => "makentp" });
 | |
| }
 | |
| 
 | |
| 
 | |
| #--------------------------------------------------------------------------------
 | |
| 
 | |
| =head3   parse_args
 | |
|       Parse the command line options and operands.
 | |
|     Arguments:
 | |
|         request: the request structure for plugin
 | |
|     Returns:
 | |
|         Usage string or error message.
 | |
|         0 if no user promp needed.
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #--------------------------------------------------------------------------------
 | |
| sub parse_args {
 | |
| 
 | |
|     my $request = shift;
 | |
|     my $args    = $request->{arg};
 | |
|     my $cmd     = $request->{command};
 | |
|     my %opt;
 | |
| 
 | |
|     # Responds with usage statement
 | |
|     local *usage = sub {
 | |
|         my $usage_string = xCAT::Usage->getUsage($cmd);
 | |
|         send_msg($request, 0, " $usage_string");
 | |
|         return ([ $_[0], $usage_string ]);
 | |
|     };
 | |
| 
 | |
|     # No command-line arguments - use defaults
 | |
|     if (!defined($args)) {
 | |
|         return (0);
 | |
|     }
 | |
| 
 | |
|     # Checks case in GetOptions, allows opts
 | |
|     # to be grouped (e.g. -vx), and terminates
 | |
|     # at the first unrecognized option.
 | |
|     @ARGV                     = @$args;
 | |
|     $Getopt::Long::ignorecase = 0;
 | |
|     Getopt::Long::Configure("bundling");
 | |
|     Getopt::Long::Configure("no_pass_through");
 | |
| 
 | |
|     # Process command-line flags
 | |
|     if (!GetOptions(\%opt,
 | |
|             qw(h|help V|Verbose v|version a|all))) {
 | |
|         return (usage());
 | |
|     }
 | |
| 
 | |
|     # Option -V for verbose output
 | |
|     if (exists($opt{V})) {
 | |
|         $globalopt{verbose} = 1;
 | |
|     }
 | |
| 
 | |
|     if (exists($opt{a})) {
 | |
|         $globalopt{a} = 1;
 | |
|     }
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| 
 | |
| #--------------------------------------------------------------------------------
 | |
| 
 | |
| =head3   preprocess_request
 | |
|       Parse the arguments and display the usage or the version string. 
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #--------------------------------------------------------------------------------
 | |
| sub preprocess_request {
 | |
|     my $req = shift;
 | |
|     if ($req->{_xcatpreprocessed}->[0] == 1) { return [$req]; }
 | |
|     my $callback = shift;
 | |
| 
 | |
|     my $command  = $req->{command}->[0];
 | |
|     my $extrargs = $req->{arg};
 | |
|     my @exargs   = ($req->{arg});
 | |
|     if (ref($extrargs)) {
 | |
|         @exargs = @$extrargs;
 | |
|     }
 | |
| 
 | |
|     # Build hash to pass around
 | |
|     my %request;
 | |
|     $request{arg}      = $extrargs;
 | |
|     $request{callback} = $callback;
 | |
|     $request{command}  = $command;
 | |
| 
 | |
|     my $usage_string = xCAT::Usage->parseCommand($command, @exargs);
 | |
|     if ($usage_string) {
 | |
|         $callback->({ data => [$usage_string] });
 | |
|         $req = {};
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|     my $result = parse_args(\%request);
 | |
|     if (ref($result) eq 'ARRAY') {
 | |
|         send_msg(\%request, 1, @$result);
 | |
|         return (1);
 | |
|     }
 | |
| 
 | |
|     # add current request
 | |
|     my @result  = ();
 | |
|     my $reqcopy = {%$req};
 | |
|     $reqcopy->{_xcatpreprocessed}->[0] = 1;
 | |
|     if (xCAT::Utils->isMN() && exists($globalopt{a})) {
 | |
|         $reqcopy->{_all}->[0] = 1;
 | |
|     }
 | |
|     if (exists($globalopt{verbose})) {
 | |
|         $reqcopy->{_verbose}->[0] = 1;
 | |
|     }
 | |
|     push @result, $reqcopy;
 | |
| 
 | |
|     return \@result;
 | |
| }
 | |
| 
 | |
| #--------------------------------------------------------------------------------
 | |
| 
 | |
| =head3   process_request
 | |
|     Pasrse the arguments and call the correspondent functions
 | |
|     to do switch discovery. 
 | |
| 
 | |
| =cut
 | |
| 
 | |
| #--------------------------------------------------------------------------------
 | |
| sub process_request {
 | |
|     my $req      = shift;
 | |
|     my $callback = shift;
 | |
|     my $sub_req  = shift;
 | |
| 
 | |
|     # Build hash to pass around
 | |
|     my %request;
 | |
|     $request{arg}      = $req->{arg};
 | |
|     $request{callback} = $callback;
 | |
|     $request{command}  = $req->{command}->[0];
 | |
| 
 | |
|     my $verbose;
 | |
|     if ($req->{_verbose}->[0] == 1) {
 | |
|         $verbose = 1;
 | |
|     }
 | |
| 
 | |
|     my @nodeinfo = xCAT::NetworkUtils->determinehostname();
 | |
|     my $nodename = pop @nodeinfo;
 | |
| 
 | |
|     if (xCAT::Utils->isMN()) {
 | |
|         send_msg(\%request, 0, "configuring management node: $nodename.");
 | |
|     } else {
 | |
|         send_msg(\%request, 0, "configuring service node: $nodename.");
 | |
|     }
 | |
| 
 | |
|     #check if ntp is installed or not
 | |
|     if ($verbose) {
 | |
|         send_msg(\%request, 0, " ...checking if nptd is installed.");
 | |
|     }
 | |
|     if (!-f "/usr/sbin/ntpd") {
 | |
|         send_msg(\%request, 1, "Please make sure ntpd is installed on $nodename.");
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     #configure the ntp configuration file
 | |
|     if ($verbose) {
 | |
|         send_msg(\%request, 0, " ...backing up the ntp configuration file /etc/ntp.conf.");
 | |
|     }
 | |
|     my $ntpcfg           = "/etc/ntp.conf";
 | |
|     my $ntpcfgbackup     = "/etc/ntp.conf.orig";
 | |
|     my $ntpxcatcfgbackup = "/etc/ntp.conf.xcatbackup";
 | |
|     if (-e $ntpcfg) {
 | |
|         if (!-e $ntpcfgbackup) {
 | |
| 
 | |
|             # if original backup does not already exist
 | |
|             my $cmd = "mv $ntpcfg $ntpcfgbackup";
 | |
|             my $result = xCAT::Utils->runcmd($cmd, 0);
 | |
|             if ($::RUNCMD_RC != 0) {
 | |
|                 send_msg(\%request, 1, "Error from command:$cmd\n    $result");
 | |
|                 return 1;
 | |
|             }
 | |
|         }
 | |
|         else {
 | |
|             # backup xcat cfg
 | |
|             my $cmd = "rm $ntpxcatcfgbackup;mv $ntpcfg $ntpxcatcfgbackup";
 | |
|             my $result = xCAT::Utils->runcmd($cmd, 0);
 | |
|             if ($::RUNCMD_RC != 0) {
 | |
|                 send_msg(\%request, 1, "Error from command:$cmd\n    $result.");
 | |
|                 return 1;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     # get site.extntpservers for mn, for sn use mn as the server
 | |
|     my $ntp_servers;
 | |
|     my $ntp_master;
 | |
|     my $ntp_attrib;
 | |
|     if (xCAT::Utils->isMN()) {
 | |
|         $ntp_attrib = "extntpservers";
 | |
|     } else {
 | |
|         $ntp_attrib = "ntpservers";
 | |
|     }
 | |
|     my @entries     = xCAT::TableUtils->get_site_attribute($ntp_attrib);
 | |
|     my $ntp_servers = $entries[0];
 | |
| 
 | |
|     if (!xCAT::Utils->isMN() && ((!$ntp_servers) || (($ntp_servers) && ($ntp_servers =~ /<xcatmaster>/)))) {
 | |
|         my $retdata = xCAT::ServiceNodeUtils->readSNInfo($nodename);
 | |
|         $ntp_servers = $retdata->{'master'};
 | |
|     }
 | |
| 
 | |
|     if ($verbose) {
 | |
|         send_msg(\%request, 0, " ...changing the ntp configuration file /etc/ntp.conf.\n    ntp servers are: $ntp_servers");
 | |
|     }
 | |
| 
 | |
|     # create ntp server config file
 | |
|     open(CFGFILE, ">$ntpcfg")
 | |
|       or xCAT::MsgUtils->message('SE',
 | |
|         "Cannot open $ntpcfg for NTP update. \n");
 | |
| 
 | |
|     if (defined($ntp_servers) && $ntp_servers) {
 | |
|         my @npt_server_array = split(',', $ntp_servers);
 | |
| 
 | |
|         # add ntp servers one by one
 | |
|         foreach my $ntps (@npt_server_array) {
 | |
|             if (!$ntp_master) { $ntp_master = $ntps; }
 | |
|             print CFGFILE "server ";
 | |
|             print CFGFILE "$ntps\n";
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     my $os          = xCAT::Utils->osver("all");
 | |
| 
 | |
|     #for sles, /var/lib/ntp/drift is a dir
 | |
|     if (xCAT::Utils->isAIX()) {
 | |
|         print CFGFILE "driftfile /etc/ntp.drift\n";
 | |
|         print CFGFILE "tracefile /etc/ntp.trace\n";
 | |
|         print CFGFILE "disable auth\n";
 | |
|         print CFGFILE "broadcastclient\n";
 | |
|     } elsif ($os =~ /sles/) {
 | |
|         print CFGFILE "driftfile /var/lib/ntp/drift/ntp.drift\n";
 | |
|         print CFGFILE "disable auth\n";
 | |
|     } else {
 | |
|         print CFGFILE "driftfile /var/lib/ntp/drift\n";
 | |
|         print CFGFILE "disable auth\n";
 | |
|     }
 | |
| 
 | |
|     #add xCAT mn/sn itself as a server
 | |
|     print CFGFILE "server 127.127.1.0\n";
 | |
|     print CFGFILE "fudge 127.127.1.0 stratum 10\n";
 | |
| 
 | |
|     close CFGFILE;
 | |
| 
 | |
|     my $ntp_service = "ntpserver";
 | |
| 
 | |
|     #stop ntpd
 | |
|     if ($verbose) {
 | |
|         send_msg(\%request, 0, " ...stopping $ntp_service");
 | |
|     }
 | |
|     my $rc = xCAT::Utils->stopservice($ntp_service);
 | |
|     if ($rc != 0) {
 | |
|         send_msg(\%request, 1, "Failed to stop nptd on $nodename.");
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     #update the time now
 | |
|     if ($ntp_master) {
 | |
|         my $cmd;
 | |
|         if ($os =~ /sles/) {
 | |
|             if (-f "/usr/sbin/rcntpd") {
 | |
|                 $cmd = "/usr/sbin/rcntpd ntptimeset";
 | |
|             } elsif (-f "/usr/sbin/rcntp") {
 | |
|                 $cmd = "/usr/sbin/rcntp ntptimeset";
 | |
|             } else {
 | |
|                 $cmd = "sntp -P no -r $ntp_master";
 | |
|             }
 | |
|         } else {
 | |
|             $cmd = "ntpdate -t5 $ntp_master";
 | |
|         }
 | |
|         if ($verbose) {
 | |
|             send_msg(\%request, 0, " ...updating the time now. $cmd");
 | |
|         }
 | |
|         my $result = xCAT::Utils->runcmd($cmd, 0);
 | |
|         if ($verbose) {
 | |
|             send_msg(\%request, 0, "    $result");
 | |
|         }
 | |
|         if ($::RUNCMD_RC != 0) {
 | |
|             send_msg(\%request, 1, "Error from command $cmd\n    $result.");
 | |
|             return 1;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     #setup the hardware clock
 | |
|     my $hwcmd = "/sbin/hwclock --systohc --utc";
 | |
|     if ($verbose) {
 | |
|         send_msg(\%request, 0, " ...updating the hwclock now. $hwcmd");
 | |
|     }
 | |
|     my $hwresult = xCAT::Utils->runcmd($hwcmd, 0);
 | |
|     if ($verbose) {
 | |
|         send_msg(\%request, 0, "    $hwresult");
 | |
|     }
 | |
|     if ($::RUNCMD_RC != 0) {
 | |
|         send_msg(\%request, 1, "Error from command $hwcmd\n    $hwresult.");
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     my $grep_cmd;
 | |
|     my $rc;
 | |
| 
 | |
|     #setup the RTC is UTC format, which will be used by os
 | |
|     if ($os =~ /sles/) {
 | |
|         $grep_cmd = "grep -i HWCLOCK /etc/sysconfig/clock";
 | |
|         $rc = xCAT::Utils->runcmd($grep_cmd, 0);
 | |
|         if ($::RUNCMD_RC == 0) {
 | |
|             `sed -i 's/.*HWCLOCK.*/HWCLOCK=\"-u\"/' /etc/sysconfig/clock`;
 | |
|         } else {
 | |
|             `echo HWCLOCK=\"-u\" >> /etc/sysconfig/clock`;
 | |
|         }
 | |
|     } elsif (-f "/etc/debian_version") {
 | |
|         `sed -i 's/.*UTC.*/UTC=\"yes\"/' /etc/default/rcS`;
 | |
|     } else {
 | |
|         if (-f "/etc/sysconfig/clock") {
 | |
|             $grep_cmd = "grep -i utc /etc/sysconfig/clock";
 | |
|             $rc = xCAT::Utils->runcmd($grep_cmd, 0);
 | |
|             if ($::RUNCMD_RC == 0) {
 | |
|                 `sed -i 's/.*UTC.*/UTC=\"yes\"/' /etc/sysconfig/clock`;
 | |
|             } else {
 | |
|                 `echo UTC=\"yes\" >> /etc/sysconfig/clock`;
 | |
|             }
 | |
|         } else {
 | |
|             `type -P timedatectl >/dev/null 2>&1`;
 | |
|             `timedatectl set-local-rtc 0`;
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     #update the hardware clock automaticly
 | |
|     if (-f "/etc/sysconfig/ntpd") {
 | |
|         $grep_cmd = "grep -i SYNC_HWCLOCK /etc/sysconfig/ntpd";
 | |
|         $rc = xCAT::Utils->runcmd($grep_cmd, 0);
 | |
|         if ($::RUNCMD_RC == 0) {
 | |
|             `sed -i 's/.*SYNC_HWCLOCK.*/SYNC_HWCLOCK=\"yes\"/' /etc/sysconfig/ntpd`;
 | |
|         } else {
 | |
|             `echo SYNC_HWCLOCK=\"yes\" >> /etc/sysconfig/ntpd`;
 | |
|         }
 | |
|     } elsif (-f "/etc/sysconfig/ntp") {
 | |
|         `sed -i 's/.*SYNC_HWCLOCK.*/NTPD_FORCE_SYNC_HWCLOCK_ON_STARTUP=\"yes\"/' /etc/sysconfig/ntp`;
 | |
|         `sed -i 's/^NTPD_FORCE_SYNC_ON.*/NTPD_FORCE_SYNC_ON_STARTUP=\"yes\"/' /etc/sysconfig/ntp`;
 | |
|         `sed -i 's/.*RUN_CHROOTED.*/NTPD_RUN_CHROOTED=\"yes\"/' /etc/sysconfig/ntp`;
 | |
|     } else {
 | |
|         my $cron_file = "/etc/cron.daily/xcatsethwclock";
 | |
|         if (!-f "$cron_file") {
 | |
|             `echo "#!/bin/sh" > $cron_file`;
 | |
|             `echo "/sbin/hwclock --systohc --utc" >> $cron_file`;
 | |
|             `chmod a+x $cron_file`;
 | |
| 
 | |
|             #service cron restart
 | |
|             xCAT::Utils->startservice("cron");
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     #start ntpd
 | |
|     if ($verbose) {
 | |
|         send_msg(\%request, 0, " ...starting $ntp_service");
 | |
|     }
 | |
|     my $rc = xCAT::Utils->startservice($ntp_service);
 | |
|     if ($rc != 0) {
 | |
|         send_msg(\%request, 1, "Failed to start nptd on $nodename.");
 | |
|         return 1;
 | |
|     }
 | |
| 
 | |
|     #enable ntpd for node reboot
 | |
|     if ($verbose) {
 | |
|         send_msg(\%request, 0, " ...enabling $ntp_service");
 | |
|     }
 | |
|     xCAT::Utils->enableservice($ntp_service);
 | |
| 
 | |
|     #now handle sn that has ntpserver=1 set in servicenode table.
 | |
|     # this part is called by makentp -a.
 | |
|     if ($req->{_all}->[0] == 1) {
 | |
|         my @servicenodes = xCAT::ServiceNodeUtils->getSNList('ntpserver');
 | |
|         if (@servicenodes > 0) {
 | |
|             send_msg(\%request, 0, "configuring service nodes: @servicenodes");
 | |
|             my $ret =
 | |
|               xCAT::Utils->runxcmd(
 | |
|                 {
 | |
|                     command => ['updatenode'],
 | |
|                     node    => \@servicenodes,
 | |
|                     arg     => [ "-P", "setupntp" ],
 | |
|                 },
 | |
|                 $sub_req, -1, 1
 | |
|               );
 | |
|             my $retcode=$::RUNCMD_RC;
 | |
|             my $msg;
 | |
|             foreach my $line (@$ret) {
 | |
|                 $msg .= "$line\n";
 | |
|             }
 | |
|             send_msg(\%request, $retcode, "$msg");
 | |
|         }
 | |
|     }
 | |
| 
 | |
| 
 | |
|     return;
 | |
| }
 | |
| 
 | |
| 
 | |
| 1;
 | |
| 
 |