#!/usr/bin/env perl #--------------------------------------------------------- # Configure cumulus/onie switches #--------------------------------------------------------- BEGIN { $::XCATROOT = $ENV{'XCATROOT'} ? $ENV{'XCATROOT'} : '/opt/xcat'; $::XCATDIR = $ENV{'XCATDIR'} ? $ENV{'XCATDIR'} : '/etc/xcat'; } use lib "$::XCATROOT/lib/perl"; use strict; use Socket; use Getopt::Long; use Expect; use Net::Ping; use xCAT::Usage; use xCAT::NodeRange; use xCAT::NetworkUtils; use xCAT::Utils; use xCAT::Table; use xCAT::MsgUtils; Getopt::Long::Configure("bundling"); $Getopt::Long::ignorecase = 0; #global variables my @nodes; my @filternodes; #--------------------------------------------------------- #Main # parse the options if ( !GetOptions( 'h|help' => \$::HELP, 'switches=s' => \$::SWITCH, 'port=s' => \$::PORT, 'vlan=s' => \$::VLAN, 'snmp' => \$::SNMP, 'ssh' => \$::SSH, 'license=s' => \$::LICENSE, 'ntp' => \$::NTP, 'all' => \$::ALL, ) ) { &usage; exit(1); } # display the usage if -h or --help is specified if ($::HELP) { &usage; exit(0); } if ($::SWITCH) { my @filternodes = xCAT::NodeRange::noderange( $::SWITCH ); if (nodesmissed) { my $nodenotdefined = join(',', nodesmissed); xCAT::MsgUtils->message("I","The following nodes are not defined in xCAT DB: $nodenotdefined"); } # check switch type my $switchestab = xCAT::Table->new('switches'); my $switches_hash = $switchestab->getNodesAttribs(\@filternodes,['switchtype']); foreach my $fsw (@filternodes) { if (($switches_hash->{$fsw}->[0]->{switchtype}) =~ /onie/) { push @nodes, $fsw; } else { xCAT::MsgUtils->message("E","The $fsw is not cumulus switch, will not config"); } } unless (@nodes) { xCAT::MsgUtils->message("E","No Valid Switch to process"); exit(1); } } else { xCAT::MsgUtils->message("E","Invalid flag, please provide switches with --switches"); &usage; exit(1); } my $switches = join(",",@nodes); my $cmd; my $vlan; my $port; my $sub_req; my $rc; if (($::SSH) || ($::ALL)) { config_ssh(); } if ($::LICENSE) { install_license(); } if ($::SNMP) { config_snmp(); } if ($::NTP) { config_ntp(); } if ($::VLAN) { #config_vlan(); } sub config_ssh { my $password = "CumulusLinux!"; my $userid = "cumulus"; my $timeout = 10; my $keyfile = "/root/.ssh/id_rsa.pub"; my $rootkey = `cat /root/.ssh/id_rsa.pub`; my $cmd; my @config_switches; my $nodetab = xCAT::Table->new('hosts'); my $nodehash = $nodetab->getNodesAttribs(\@nodes,['ip','otherinterfaces']); foreach my $switch (@nodes) { #remove old host key from /root/.ssh/known_hosts $cmd = `ssh-keygen -R $switch`; my $static_ip = $nodehash->{$switch}->[0]->{ip}; my $discover_ip = $nodehash->{$switch}->[0]->{otherinterfaces}; my $ssh_ip; my $p = Net::Ping->new(); if ($p->ping($static_ip)) { $ssh_ip = $static_ip; } elsif ($p->ping($discover_ip)) { $ssh_ip = $discover_ip; } else { print "$switch is not reachable\n"; next; } my ($exp, $errstr) = cumulus_connect($ssh_ip, $userid, $password, $timeout); if (!defined $exp) { print ("connect failed $errstr\n"); next; } my $ret; my $err; ($ret, $err) = cumulus_exec($exp, "mkdir -p /root/.ssh"); ($ret, $err) = cumulus_exec($exp, "chmod 700 /root/.ssh"); ($ret, $err) = cumulus_exec($exp, "echo \"$rootkey\" >/root/.ssh/authorized_keys"); ($ret, $err) = cumulus_exec($exp, "chmod 644 /root/.ssh/authorized_keys"); #config dhcp ip address to static if ($ssh_ip eq $discover_ip) { ($ret, $err) = cumulus_exec($exp, "ifconfig eth0 $static_ip"); } $exp->hard_close(); push (@config_switches, $switch); } if (@config_switches) { #update switch status my $csw = join(",",@config_switches); $cmd = "chdef $csw status=ssh_configured otherinterfaces="; $rc= xCAT::Utils->runcmd($cmd, 0); print "ssh configured for $csw\n"; if ($::ALL) { $cmd = "updatenode $csw -P hardeths,enablesnmp,configinterface"; $rc= xCAT::Utils->runcmd($cmd, 0); if ($::RUNCMD_RC != 0) { xCAT::MsgUtils->message("E","Failed to run updatenode, please check the switch"); } $cmd = "chdef $csw status=configured"; $rc= xCAT::Utils->runcmd($cmd, 0); print "switch: $csw configured\n"; } } } sub cumulus_connect { my $server = shift; my $userid = shift; my $password = shift; my $timeout = shift; my $ssh = Expect->new; my $command = 'ssh'; my @parameters = ($userid . "@" . $server); $ssh->debug(0); $ssh->log_stdout(0); # suppress stdout output.. $ssh->slave->stty(qw(sane -echo)); unless ($ssh->spawn($command, @parameters)) { my $err = $!; $ssh->soft_close(); my $rsp; return(undef, "unable to run command $command $err\n"); } $ssh->expect($timeout, [ "-re", qr/WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED/, sub {die "WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED!\n"; } ], [ "-re", qr/\(yes\/no\)\?\s*$/, sub { $ssh->send("yes\n"); exp_continue; } ], [ "-re", qr/ password:/, sub {$ssh->send("$password\n"); exp_continue; } ], [ "-re", qr/:~\$/, sub { $ssh->send("sudo su\n"); exp_continue; } ], [ "-re", qr/ password for cumulus:/, sub { $ssh->send("$password\n"); exp_continue; } ], [ "-re", qr/.*\/home\/cumulus#/, sub { $ssh->clear_accum(); } ], [ timeout => sub { die "No login.\n"; } ] ); $ssh->clear_accum(); return ($ssh); } sub cumulus_exec { my $exp = shift; my $cmd = shift; my $timeout = shift; my $prompt = shift; $timeout = 10 unless defined $timeout; $prompt = qr/.*\/home\/cumulus#/ unless defined $prompt; $exp->clear_accum(); $exp->send("$cmd\n"); my ($mpos, $merr, $mstr, $mbmatch, $mamatch) = $exp->expect(6, "-re", $prompt); if (defined $merr) { return(undef,$merr); } return($mbmatch); } # for cumulus switch, need to set the license file sub install_license { my @config_switches; print "install_license\n"; my $license_file = "/root/license.txt"; my $file_name = "/root/license.txt"; if ($::LICENSE) { $license_file = $::LICENSE; } print "file = $license_file\n"; if (!(-e $license_file) ) { print "license file $license_file does not exist\n"; return; } foreach my $switch (@nodes) { my $cmd = "xdcp $switch $license_file $file_name"; $rc= xCAT::Utils->runcmd($cmd, 0); if ($::RUNCMD_RC != 0) { xCAT::MsgUtils->message("E","Failed to xscp $license_file to $switch"); next; } $cmd = "xdsh $switch '/usr/cumulus/bin/cl-license -i $file_name' "; $rc= xCAT::Utils->runcmd($cmd, 0); if ($::RUNCMD_RC != 0) { xCAT::MsgUtils->message("E","Failed to $cmd to $switch"); next; } push (@config_switches, $switch); } if (@config_switches) { my $csw = join(",",@config_switches); print "license is installed on $csw\n"; } } #get snmp attributes from switches tabele and setup secure SNMP v3 sub config_snmp { my $switchestab = xCAT::Table->new('switches'); my $switches_hash = $switchestab->getNodesAttribs(\@nodes,['username','password','privacy','auth']); foreach my $switch (@nodes) { #check if xdsh works $cmd = "xdsh $switch date"; $rc= xCAT::Utils->runcmd($cmd, 0); if ($::RUNCMD_RC != 0) { xCAT::MsgUtils->message("E","xdsh command to $switch failed"); next; } my $username = $switches_hash->{$switch}->[0]->{username}; my $password = $switches_hash->{$switch}->[0]->{password}; my $auth = $switches_hash->{$switch}->[0]->{auth}; my $privacy = $switches_hash->{$switch}->[0]->{privacy}; my $privpwd; if (defined $privacy) { $privpwd = $password; } my $libconf = "/var/lib/snmp/snmpd.conf"; my $etcconf = "/etc/snmp/snmpd.conf"; my $cmd_prefix = "xdsh $switch "; my $cmd; $cmd = $cmd . "systemctl stop snmpd.service;"; $cmd = $cmd . "sed -i '/$username/d' $libconf;"; $cmd = $cmd . "sed -i '/$username/d' $etcconf;"; $cmd = $cmd . "echo 'createUser $username $auth $password $privacy $privpwd' >> $etcconf;"; $cmd = $cmd . "echo 'rwuser $username' >> $etcconf;"; $cmd = $cmd . "systemctl start snmpd.service;"; my $dshcmd = $cmd_prefix . " \"" . $cmd . "\""; $rc= xCAT::Utils->runcmd($dshcmd, 0); if ($::RUNCMD_RC != 0) { xCAT::MsgUtils->message("E","Failed to update snmpd.conf for $switch"); next; } print "Add username=$username, password=$password, privacy=$privacy, auth=$auth to snmp service for $switch \n"; } } sub config_ntp { my @config_switches; my $cmd; my $master = `hostname -i`; my $file = "temp.txt"; open(FILE , ">$file") or die "cannot open file $file\n"; print FILE "#This file is created by xCAT \n"; print FILE "driftfile /var/lib/ntp/drift\n"; print FILE "disable auth\n"; print FILE "restrict 127.0.0.1\n"; print FILE "server $master iburst\n"; print FILE "interface listen eth0\n"; foreach my $switch (@nodes) { #check if xdsh works $cmd = "xdsh $switch date"; $rc= xCAT::Utils->runcmd($cmd, 0); if ($::RUNCMD_RC != 0) { xCAT::MsgUtils->message("E","xdsh command to $switch failed"); next; } my $cmd_line = "echo 'US/Eastern'>/etc/timezone;dpkg-reconfigure --frontend noninteractive tzdata"; print "$cmd_line\n"; $cmd = "xdsh $switch $cmd_line"; if ($::RUNCMD_RC != 0) { print "Failed to update ntp timezone\n"; xCAT::MsgUtils->message("E","Failed to update ntp timezone for $switch"); next; } print "$cmd\n"; $cmd = "xdcp $switch $file"; $rc= xCAT::Utils->runcmd($cmd, 0); $cmd = "xdsh $switch 'cp /etc/ntp.conf /etc/ntp.conf.orig;cp $file /etc/ntp.conf;rm -fr $file;systemctl restart ntp;systemctl enable ntp' "; $rc= xCAT::Utils->runcmd($cmd, 0); if ($::RUNCMD_RC != 0) { xCAT::MsgUtils->message("E","Failed to update ntp for $switch"); next; } push (@config_switches, $switch); } close FILE; $cmd = `rm -rf $file`; if (@config_switches) { #update switch status my $csw = join(",",@config_switches); $cmd = "chdef $csw status=ntp_configured"; $rc= xCAT::Utils->runcmd($cmd, 0); } } #--------------------------------------------------------- =head3 usage Displays message for -h option =cut #--------------------------------------------------------- sub usage { print "Usage: configonie -h│--help configonie --switches switchnames --ssh configonie --switches switchnames --license filename configonie --switches switchnames --snmp configonie --switches switchnames --ntp To setup ssh passwordless, change ip to static, enable snmp configuration and configure basic interface : configonie --switches switchnames --all \n"; }