mirror of
				https://github.com/xcat2/xcat-core.git
				synced 2025-10-31 03:12:30 +00:00 
			
		
		
		
	the noboot nic names, parse out the interface names for the tagged vlans without the physical name in the string
		
			
				
	
	
		
			375 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
			
		
		
	
	
			375 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			Perl
		
	
	
	
	
	
| package xCAT_plugin::mknb;
 | |
| use strict;
 | |
| use File::Temp qw(tempdir);
 | |
| use xCAT::Utils;
 | |
| use xCAT::TableUtils;
 | |
| use File::Path;
 | |
| use File::Copy;
 | |
| 
 | |
| sub handled_commands {
 | |
|     return {
 | |
|         mknb => 'mknb',
 | |
|     };
 | |
| }
 | |
| 
 | |
| sub process_request {
 | |
|     my $request  = shift;
 | |
|     my $callback = shift;
 | |
|     my $serialport;
 | |
|     my $serialspeed;
 | |
|     my $serialflow;
 | |
|     my %nobootnicips = ();
 | |
|     my $initrd_file = undef;
 | |
|     my $xcatdport   = 3001;
 | |
|     my @entries     = xCAT::TableUtils->get_site_attribute("defserialport");
 | |
|     my $t_entry     = $entries[0];
 | |
|     if (defined($t_entry)) {
 | |
|         $serialport = $t_entry;
 | |
|     }
 | |
| 
 | |
|     @entries = xCAT::TableUtils->get_site_attribute("defserialspeed");
 | |
|     $t_entry = $entries[0];
 | |
|     if (defined($t_entry)) {
 | |
|         $serialspeed = $t_entry;
 | |
|     }
 | |
| 
 | |
|     @entries = xCAT::TableUtils->get_site_attribute("defserialflow");
 | |
|     $t_entry = $entries[0];
 | |
|     if (defined($t_entry)) {
 | |
|         $serialflow = $t_entry;
 | |
|     }
 | |
| 
 | |
|     @entries = xCAT::TableUtils->get_site_attribute("xcatdport");
 | |
|     $t_entry = $entries[0];
 | |
|     if (defined($t_entry)) {
 | |
|         $xcatdport = $t_entry;
 | |
|     }
 | |
|     
 | |
|     @entries = xCAT::TableUtils->get_site_attribute("dhcpinterfaces");
 | |
|     $t_entry = $entries[0];
 | |
|     if (defined($t_entry)) {
 | |
|         my %nobootnics = ();
 | |
|         foreach my $dhcpif (split /;/, $t_entry) {
 | |
|             if ($dhcpif =~ /\|/) {
 | |
|                 my $isself = 0;
 | |
|                 (my $ngroup, $dhcpif) = split /\|/, $dhcpif;
 | |
|                 foreach my $host (noderange($ngroup)) {
 | |
|                     unless(xCAT::NetworkUtils->thishostisnot($host)) {
 | |
|                         $isself = 1;
 | |
|                     }
 | |
|                 }
 | |
|                 unless(xCAT::NetworkUtils->thishostisnot($ngroup)) {
 | |
|                     $isself = 1;
 | |
|                 }
 | |
|                 unless ($isself) {
 | |
|                     next;
 | |
|                 }
 | |
|             }
 | |
|             foreach (split /[,\s]+/, $dhcpif) {
 | |
|                 my ($nicname, $flag) = split /:/;
 | |
|                 if ($flag and $flag =~ /noboot/i) {
 | |
|                     $nobootnics{$nicname} = 1; 
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|         my $nicips = xCAT::NetworkUtils->get_nic_ip();
 | |
|         foreach (keys $nicips) {
 | |
|             # To support tagged vlan, create entries in the hash for the 
 | |
|             # interface name removing the physical interface ending:
 | |
|             # 'enP1p12s0f0.2@enP1p12s0f0' => 'enP1p12s0f0.2'
 | |
|             if ($_ =~ "@") {
 | |
|                 my $newkey = $_;
 | |
|                 $newkey =~ s/\@.*//g;
 | |
|                 $$nicips{$newkey} = ${nicips}->{$_};
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         foreach (keys %nobootnics)  {
 | |
|             if (defined($nicips->{$_})) {
 | |
|                 $nobootnicips{$nicips->{$_}} = 1;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     my $tftpdir = xCAT::TableUtils->getTftpDir();
 | |
|     my $arch    = $request->{arg}->[0];
 | |
|     if (!$arch) {
 | |
|         $callback->({ error => "Need to specify architecture (x86, x86_64 or ppc64)" }, { errorcode => [1] });
 | |
|         return;
 | |
|     } elsif ($arch eq "ppc64le" or $arch eq "ppc64el") {
 | |
|         $callback->({ data => "The arch:$arch is not supported at present, pls use \"ppc64\" instead" });
 | |
|         return;
 | |
|     }
 | |
|     unless (-d "$::XCATROOT/share/xcat/netboot/$arch" or -d "$::XCATROOT/share/xcat/netboot/genesis/$arch") {
 | |
|         $callback->({ error => "Unable to find directory $::XCATROOT/share/xcat/netboot/$arch or $::XCATROOT/share/xcat/netboot/genesis/$arch", errorcode => [1] });
 | |
|         return;
 | |
|     }
 | |
|     my $configfileonly = $request->{arg}->[1];
 | |
|     if ($configfileonly and $configfileonly ne "-c" and $configfileonly ne "--configfileonly") {
 | |
|         $callback->({ error => "The option $configfileonly is not supported", errorcode => [1] });
 | |
|         return;
 | |
|     } elsif ($configfileonly) {
 | |
|         goto CREAT_CONF_FILE;
 | |
|     }
 | |
|     unless (-r "/root/.ssh/id_rsa.pub") {
 | |
|         if (-r "/root/.ssh/id_rsa") {
 | |
|             $callback->({ data => ["Extracting ssh public key from private key"] });
 | |
|             my $rc = system('ssh-keygen -y -f /root/.ssh/id_rsa > /root/.ssh/id_rsa.pub');
 | |
|             if ($rc) {
 | |
|                 $callback->({ error => ["Failure executing ssh-keygen for root"], errorcode => [1] });
 | |
|             }
 | |
|         } else {
 | |
|             $callback->({ data => ["Generating ssh private key for root"] });
 | |
|             my $rc = system('ssh-keygen -t rsa -q -b 2048 -N "" -f  /root/.ssh/id_rsa');
 | |
|             if ($rc) {
 | |
|                 $callback->({ error => ["Failure executing ssh-keygen for root"], errorcode => [1] });
 | |
|             }
 | |
|         }
 | |
|     }
 | |
|     my $tempdir = tempdir("mknb.$$.XXXXXX", TMPDIR => 1);
 | |
|     unless ($tempdir) {
 | |
|         $callback->({ error => ["Failed to create a temporary directory"], errorcode => [1] });
 | |
|         return;
 | |
|     }
 | |
|     unless (-e "$tftpdir/xcat") {
 | |
|         mkpath("$tftpdir/xcat");
 | |
|     }
 | |
|     my $rc;
 | |
|     my $invisibletouch = 0;
 | |
|     if (-e "$::XCATROOT/share/xcat/netboot/genesis/$arch") {
 | |
|         $rc = system("cp -a $::XCATROOT/share/xcat/netboot/genesis/$arch/fs/* $tempdir");
 | |
|         $rc = system("cp -a $::XCATROOT/share/xcat/netboot/genesis/$arch/kernel $tftpdir/xcat/genesis.kernel.$arch");
 | |
|         $invisibletouch = 1;
 | |
|     } else {
 | |
|         $rc = system("cp -a $::XCATROOT/share/xcat/netboot/$arch/nbroot/* $tempdir");
 | |
|     }
 | |
|     if ($rc) {
 | |
|         system("rm -rf $tempdir");
 | |
|         if ($invisibletouch) {
 | |
|             $callback->({ error => ["Failed to copy  $::XCATROOT/share/xcat/netboot/genesis/$arch/fs contents"], errorcode => [1] });
 | |
|         } else {
 | |
|             $callback->({ error => ["Failed to copy  $::XCATROOT/share/xcat/netboot/$arch/nbroot/ contents"], errorcode => [1] });
 | |
|         }
 | |
|         return;
 | |
|     }
 | |
|     my $sshdir;
 | |
|     if ($invisibletouch) {
 | |
|         $sshdir = "/.ssh";
 | |
|     } else {
 | |
|         $sshdir = "/root/.ssh";
 | |
|     }
 | |
|     mkpath($tempdir . "$sshdir");
 | |
|     chmod(0700, $tempdir . "$sshdir");
 | |
|     copy("/root/.ssh/id_rsa.pub", "$tempdir$sshdir/authorized_keys");
 | |
|     chmod(0600, "$tempdir$sshdir/authorized_keys");
 | |
|     if (not $invisibletouch and -r "/etc/xcat/hostkeys/ssh_host_rsa_key") {
 | |
|         copy("/etc/xcat/hostkeys/ssh_host_rsa_key", "$tempdir/etc/ssh_host_rsa_key");
 | |
|         copy("/etc/xcat/hostkeys/ssh_host_dsa_key", "$tempdir/etc/ssh_host_dsa_key");
 | |
|         chmod(0600, <$tempdir/etc/ssh_*>);
 | |
|     }
 | |
|     unless ($invisibletouch or -r "$tempdir/etc/ssh_host_rsa_key") {
 | |
|         system("ssh-keygen -t rsa -f $tempdir/etc/ssh_host_rsa_key -C '' -N ''");
 | |
|         system("ssh-keygen -t dsa -f $tempdir/etc/ssh_host_dsa_key -C '' -N ''");
 | |
|     }
 | |
|     my $lzma_exit_value = 1;
 | |
|     if ($invisibletouch) {
 | |
|         my $done = 0;
 | |
|         if (-x "/usr/bin/lzma") {    #let's reclaim some of that size...
 | |
|             $callback->({ data => ["Creating genesis.fs.$arch.lzma in $tftpdir/xcat"] });
 | |
|             system("cd $tempdir; find . | cpio -o -H newc | lzma -C crc32 -9 > $tftpdir/xcat/genesis.fs.$arch.lzma");
 | |
|             $lzma_exit_value = $? >> 8;
 | |
|             if ($lzma_exit_value) {
 | |
|                 $callback->({ data => ["Creating genesis.fs.$arch.lzma in $tftpdir/xcat failed, falling back to gzip"] });
 | |
|                 unlink("$tftpdir/xcat/genesis.fs.$arch.lzma");
 | |
|             } else {
 | |
|                 $done        = 1;
 | |
|                 $initrd_file = "$tftpdir/xcat/genesis.fs.$arch.lzma";
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         if (not $done) {
 | |
|             $callback->({ data => ["Creating genesis.fs.$arch.gz in $tftpdir/xcat"] });
 | |
|             system("cd $tempdir; find . | cpio -o -H newc | gzip -9 > $tftpdir/xcat/genesis.fs.$arch.gz");
 | |
|             $initrd_file = "$tftpdir/xcat/genesis.fs.$arch.gz";
 | |
|         }
 | |
|     } else {
 | |
|         $callback->({ data => ["Creating nbfs.$arch.gz in $tftpdir/xcat"] });
 | |
|         system("cd $tempdir; find . | cpio -o -H newc | gzip -9 > $tftpdir/xcat/nbfs.$arch.gz");
 | |
|         $initrd_file = "$tftpdir/xcat/nbfs.$arch.gz";
 | |
|     }
 | |
|     system("rm -rf $tempdir");
 | |
|     unless ($initrd_file) {
 | |
|         $callback->({ data => ["Creating filesystem file in $tftpdir/xcat failed"] });
 | |
|         return;
 | |
|     }
 | |
| 
 | |
|   CREAT_CONF_FILE:
 | |
|     if ($configfileonly) {
 | |
|         unless (-e "$tftpdir/xcat/genesis.kernel.$arch") {
 | |
|             $callback->({ error => ["No kernel file found in $tftpdir/xcat, pls run \"mknb $arch\" instead."], errorcode => [1] });
 | |
|             return;
 | |
|         }
 | |
|         if (-e "$tftpdir/xcat/genesis.fs.$arch.lzma") {
 | |
|             $initrd_file = "$tftpdir/xcat/genesis.fs.$arch.lzma";
 | |
|         } elsif (-e "$tftpdir/xcat/genesis.fs.$arch.gz") {
 | |
|             $initrd_file = "$tftpdir/xcat/genesis.fs.$arch.gz";
 | |
|         } elsif (-e "$tftpdir/xcat/nbfs.$arch.gz") {
 | |
|             $initrd_file = "$tftpdir/xcat/nbfs.$arch.gz";
 | |
|         } else {
 | |
|             $callback->({ error => ["No filesystem file found in $tftpdir/xcat, pls run \"mknb $arch\" instead."], errorcode => [1] });
 | |
|             return;
 | |
|         }
 | |
|     }
 | |
|     my $hexnets  = xCAT::NetworkUtils->my_hexnets();
 | |
|     my $normnets = xCAT::NetworkUtils->my_nets();
 | |
|     my $consolecmdline;
 | |
|     if (defined($serialport) and $serialspeed) {
 | |
|         if ($arch =~ /ppc/) {
 | |
|             $consolecmdline = "console=tty0 console=hvc$serialport,$serialspeed";
 | |
|         } else {
 | |
|             $consolecmdline = "console=tty0 console=ttyS$serialport,$serialspeed";
 | |
|         }
 | |
|         if ($serialflow =~ /cts/ or $serialflow =~ /hard/) {
 | |
|             $consolecmdline .= "n8r";
 | |
|         }
 | |
|     }
 | |
|     my $cfgfile;
 | |
|     if ($arch =~ /x86/) {
 | |
|         mkpath("$tftpdir/xcat/xnba/nets");
 | |
|         chmod(0755, "$tftpdir/xcat/xnba");
 | |
|         chmod(0755, "$tftpdir/xcat/xnba/nets");
 | |
|         mkpath("$tftpdir/pxelinux.cfg");
 | |
|         chmod(0755, "$tftpdir/pxelinux.cfg");
 | |
|         if (-r "/usr/lib/syslinux/pxelinux.0") {
 | |
|             copy("/usr/lib/syslinux/pxelinux.0", "$tftpdir/pxelinux.0");
 | |
|         } elsif (-r "/usr/share/syslinux/pxelinux.0") {
 | |
|             copy("/usr/share/syslinux/pxelinux.0", "$tftpdir/pxelinux.0");
 | |
|         }
 | |
|         if (-r "$tftpdir/pxelinux.0") {
 | |
|             chmod(0644, "$tftpdir/pxelinux.0");
 | |
|         }
 | |
|     } elsif ($arch =~ /ppc/) {
 | |
|         mkpath("$tftpdir/pxelinux.cfg/p/");
 | |
|     }
 | |
|     my $dopxe = 0;
 | |
|     foreach (keys %{$normnets}) {
 | |
|         my $net = $_;
 | |
|         my $nicip = $normnets->{$net};
 | |
|         $net =~ s/\//_/;
 | |
|         if (defined($nobootnicips{$nicip})) {
 | |
|             if ($arch =~ /ppc/ and -r "$tftpdir/pxelinux.cfg/p/$net") {
 | |
|                 unlink("$tftpdir/pxelinux.cfg/p/$net");
 | |
|             }
 | |
|             next;
 | |
|         }
 | |
|         $dopxe = 0;
 | |
|         if ($arch =~ /x86/) {    #only do pxe if just x86 or x86_64 and no x86
 | |
|             if ($arch =~ /x86_64/ and not $invisibletouch) {
 | |
|                 if (-r "$tftpdir/xcat/xnba/nets/$net") {
 | |
|                     my $cfg;
 | |
|                     my @contents;
 | |
|                     open($cfg, "<", "$tftpdir/xcat/xnba/nets/$net");
 | |
|                     @contents = <$cfg>;
 | |
|                     close($cfg);
 | |
|                     if (grep (/x86_64/, @contents)) {
 | |
|                         $dopxe = 1;
 | |
|                     }
 | |
|                 } else {
 | |
|                     $dopxe = 1;
 | |
|                 }
 | |
|             } else {
 | |
|                 $dopxe = 1;
 | |
|             }
 | |
|         }
 | |
|         if ($dopxe) {
 | |
|             my $cfg;
 | |
|             open($cfg, ">", "$tftpdir/xcat/xnba/nets/$net");
 | |
|             print $cfg "#!gpxe\n";
 | |
|             if ($invisibletouch) {
 | |
|                 print $cfg 'imgfetch -n kernel http://${next-server}/tftpboot/xcat/genesis.kernel.' . "$arch quiet xcatd=" . $normnets->{$_} . ":$xcatdport $consolecmdline BOOTIF=01-" . '${netX/machyp}' . "\n";
 | |
|                 if ($lzma_exit_value) {
 | |
|                     print $cfg 'imgfetch -n nbfs http://${next-server}/tftpboot/xcat/genesis.fs.' . "$arch.gz\n";
 | |
|                 } else {
 | |
|                     print $cfg 'imgfetch -n nbfs http://${next-server}/tftpboot/xcat/genesis.fs.' . "$arch.lzma\n";
 | |
|                 }
 | |
|             } else {
 | |
|                 print $cfg 'imgfetch -n kernel http://${next-server}/tftpboot/xcat/nbk.' . "$arch quiet xcatd=" . $normnets->{$_} . ":$xcatdport $consolecmdline\n";
 | |
|                 print $cfg 'imgfetch -n nbfs http://${next-server}/tftpboot/xcat/nbfs.' . "$arch.gz\n";
 | |
|             }
 | |
|             print $cfg "imgload kernel\n";
 | |
|             print $cfg "imgexec kernel\n";
 | |
|             close($cfg);
 | |
|             if ($invisibletouch and $arch =~ /x86_64/) {    #UEFI time
 | |
|                 open($cfg, ">", "$tftpdir/xcat/xnba/nets/$net.elilo");
 | |
|                 print $cfg "default=\"xCAT Genesis (" . $normnets->{$_} . ")\"\n";
 | |
|                 print $cfg "   delay=5\n";
 | |
|                 print $cfg '   image=/tftpboot/xcat/genesis.kernel.' . "$arch\n";
 | |
|                 print $cfg "   label=\"xCAT Genesis (" . $normnets->{$_} . ")\"\n";
 | |
|                 if ($lzma_exit_value) {
 | |
|                     print $cfg "   initrd=/tftpboot/xcat/genesis.fs.$arch.gz\n";
 | |
|                 } else {
 | |
|                     print $cfg "   initrd=/tftpboot/xcat/genesis.fs.$arch.lzma\n";
 | |
|                 }
 | |
|                 print $cfg "   append=\"quiet xcatd=" . $normnets->{$_} . ":$xcatdport destiny=discover $consolecmdline BOOTIF=%B\"\n";
 | |
|                 close($cfg);
 | |
|                 open($cfg, ">", "$tftpdir/xcat/xnba/nets/$net.uefi");
 | |
|                 print $cfg "#!gpxe\n";
 | |
|                 print $cfg 'chain http://${next-server}/tftpboot/xcat/elilo-x64.efi -C /tftpboot/xcat/xnba/nets/' . "$net.elilo\n";
 | |
|                 close($cfg);
 | |
|             }
 | |
|         } elsif ($arch =~ /ppc/) {
 | |
|             open($cfgfile, ">", "$tftpdir/pxelinux.cfg/p/$net");
 | |
|             print $cfgfile "default \"xCAT Genesis (" . $normnets->{$_} . ")\"\n";
 | |
|             print $cfgfile "   delay=10\n";
 | |
|             print $cfgfile "   label \"xCAT Genesis (" . $normnets->{$_} . ")\"\n";
 | |
|             print $cfgfile "   kernel http://" . $normnets->{$_} . ":80/$tftpdir/xcat/genesis.kernel.$arch\n";
 | |
|             print $cfgfile "   initrd http://" . $normnets->{$_} . ":80/$initrd_file\n";
 | |
|             print $cfgfile '   append "quiet xcatd=' . $normnets->{$_} . ":$xcatdport $consolecmdline\"\n";
 | |
|             close($cfgfile);
 | |
|         }
 | |
|     }
 | |
|     $dopxe = 0;
 | |
|     foreach (keys %{$hexnets}) {
 | |
|         $dopxe = 0;
 | |
|         if ($arch =~ /x86/) {    #only do pxe if just x86 or x86_64 and no x86
 | |
|             if ($arch =~ /x86_64/) {
 | |
|                 if (-r "$tftpdir/pxelinux.cfg/" . uc($_)) {
 | |
|                     my $pcfg;
 | |
|                     open($pcfg, "<", "$tftpdir/pxelinux.cfg/" . uc($_));
 | |
|                     my @pcfgcontents = <$pcfg>;
 | |
|                     close($pcfg);
 | |
|                     if (grep (/x86_64/, @pcfgcontents)) {
 | |
|                         $dopxe = 1;
 | |
|                     }
 | |
|                 } else {
 | |
|                     $dopxe = 1;
 | |
|                 }
 | |
|             } else {
 | |
|                 $dopxe = 1;
 | |
|             }
 | |
|         }
 | |
|         if ($dopxe) {
 | |
|             open($cfgfile, ">", "$tftpdir/pxelinux.cfg/" . uc($_));
 | |
|             print $cfgfile "DEFAULT xCAT\n";
 | |
|             print $cfgfile "  LABEL xCAT\n";
 | |
|             print $cfgfile "  KERNEL xcat/nbk.$arch\n";
 | |
|             print $cfgfile "  APPEND initrd=xcat/nbfs.$arch.gz quiet xcatd=" . $hexnets->{$_} . ":$xcatdport $consolecmdline\n";
 | |
|             close($cfgfile);
 | |
|         } elsif ($arch =~ /ppc/) {
 | |
|             open($cfgfile, ">", "$tftpdir/etc/" . lc($_));
 | |
|             print $cfgfile "default \"xCAT Genesis (" . $normnets->{$_} . ")\"\n";
 | |
|             print $cfgfile "   delay=10\n";
 | |
|             print $cfgfile "   label \"xCAT Genesis (" . $normnets->{$_} . ")\"\n";
 | |
|             print $cfgfile "   kernel http://" . $hexnets->{$_} . ":80/$tftpdir/xcat/genesis.kernel.$arch\n";
 | |
|             print $cfgfile "   initrd http://" . $hexnets->{$_} . ":80/$initrd_file\n";
 | |
|             print $cfgfile '   append "quiet xcatd=' . $hexnets->{$_} . ":$xcatdport $consolecmdline\"\n";
 | |
|             close($cfgfile);
 | |
|         }
 | |
|     }
 | |
|     if ($configfileonly) {
 | |
|         $callback->({ data => ["Write netboot config file done"] });
 | |
|     }
 | |
| }
 | |
| 
 | |
| 1;
 |