diff --git a/xCAT-server-2.0/lib/xcat/plugins/dhcp.pm b/xCAT-server-2.0/lib/xcat/plugins/dhcp.pm index 0fa74370a..58f30b4a2 100644 --- a/xCAT-server-2.0/lib/xcat/plugins/dhcp.pm +++ b/xCAT-server-2.0/lib/xcat/plugins/dhcp.pm @@ -12,460 +12,620 @@ use IPC::Open2; use xCAT::Utils; my @dhcpconf; #Hold DHCP config file contents to be written back. -my @nrn; # To hold output of netstat -rn to be consulted throughout process +my @nrn; # To hold output of netstat -rn to be consulted throughout process my $domain; my $omshell; -my $statements; #Hold custom statements to be slipped into host declarations +my $statements; #Hold custom statements to be slipped into host declarations my $callback; - -sub handled_commands { - return { - makedhcp => "dhcp", - } +sub handled_commands +{ + return {makedhcp => "dhcp",}; } - -sub delnode { - my $node = shift; - my $inetn = inet_aton($node); - my $mactab = xCAT::Table->new('mac'); - if ($mactab) { $ent = $mactab->getNodeAttribs($node,[qw(mac)]); } - if ($ent and $ent->{mac}) { - my @macs = split(/\|/,$ent->{mac}); - my $mace; - foreach $mace (@macs) { - my $mac; - my $hname; - ($mac,$hname) = split (/!/,$mace); - unless ($hname) { $hname = $node; } - print $omshell "new host\n"; - print $omshell "set name = \"$hname\"\n"; #Find and destroy conflict name - print $omshell "open\n"; - print $omshell "remove\n"; - print $omshell "close\n"; - if ($mac) { - print $omshell "new host\n"; - print $omshell "set hardware-address = ".$mac."\n"; #find and destroy mac conflict - print $omshell "open\n"; - print $omshell "remove\n"; - print $omshell "close\n"; - } - if ($inetn) { - my $ip; - if (inet_aton($hname)) { - $ip = inet_ntoa(inet_aton($hname));; - } - if ($ip) { - print $omshell "new host\n"; - print $omshell "set ip-address = $ip\n"; #find and destroy ip conflict - print $omshell "open\n"; - print $omshell "remove\n"; - print $omshell "close\n"; - } - } - } - } - print $omshell "new host\n"; - print $omshell "set name = \"$node\"\n"; #Find and destroy conflict name - print $omshell "open\n"; - print $omshell "remove\n"; - print $omshell "close\n"; - if ($inetn) { - my $ip = inet_ntoa(inet_aton($node));; - unless ($ip) { return; } +sub delnode +{ + my $node = shift; + my $inetn = inet_aton($node); + + my $mactab = xCAT::Table->new('mac'); + if ($mactab) { $ent = $mactab->getNodeAttribs($node, [qw(mac)]); } + if ($ent and $ent->{mac}) + { + my @macs = split(/\|/, $ent->{mac}); + my $mace; + foreach $mace (@macs) + { + my $mac; + my $hname; + ($mac, $hname) = split(/!/, $mace); + unless ($hname) { $hname = $node; } + print $omshell "new host\n"; + print $omshell + "set name = \"$hname\"\n"; #Find and destroy conflict name + print $omshell "open\n"; + print $omshell "remove\n"; + print $omshell "close\n"; + + if ($mac) + { + print $omshell "new host\n"; + print $omshell "set hardware-address = " . $mac + . "\n"; #find and destroy mac conflict + print $omshell "open\n"; + print $omshell "remove\n"; + print $omshell "close\n"; + } + if ($inetn) + { + my $ip; + if (inet_aton($hname)) + { + $ip = inet_ntoa(inet_aton($hname)); + } + if ($ip) + { + print $omshell "new host\n"; + print $omshell + "set ip-address = $ip\n"; #find and destroy ip conflict + print $omshell "open\n"; + print $omshell "remove\n"; + print $omshell "close\n"; + } + } + } + } print $omshell "new host\n"; - print $omshell "set ip-address = $ip\n"; #find and destroy ip conflict + print $omshell "set name = \"$node\"\n"; #Find and destroy conflict name print $omshell "open\n"; print $omshell "remove\n"; print $omshell "close\n"; - } + if ($inetn) + { + my $ip = inet_ntoa(inet_aton($node)); + unless ($ip) { return; } + print $omshell "new host\n"; + print $omshell "set ip-address = $ip\n"; #find and destroy ip conflict + print $omshell "open\n"; + print $omshell "remove\n"; + print $omshell "close\n"; + } } +sub addnode +{ -sub addnode { -#Use omshell to add the node. -#the process used is blind typing commands that should work -#it tries to delet any conflicting entries matched by name and -#hardware address and ip address before creating a brand now one -#unfortunate side effect: dhcpd.leases can look ugly over time, when -#doing updates would keep it cleaner, good news, dhcpd restart cleans -#up the lease file the way we would want anyway. - my $node = shift; - my $ent; - my $nrtab = xCAT::Table->new('noderes'); - my $lstatements = $statements; - my $guess_next_server=0; - if ($nrtab) { - my $ent; - $ent = $nrtab->getNodeAttribs($node,['tftpserver']); - if ($ent and $ent->{tftpserver}) { - $lstatements = 'next-server '.inet_ntoa(inet_aton($ent->{tftpserver})).';'.$statements; - } else { - $guess_next_server=1; - } - #else { - # $ent = $nrtab->getNodeAttribs($node,['servicenode']); - # if ($ent and $ent->{servicenode}) { - # $statements = 'next-server = \"'.inet_ntoa(inet_aton($ent->{servicenode})).'\";'.$statements; - # } - #} - } else { - $guess_next_server=1; - } - my $mactab = xCAT::Table->new('mac'); - unless ($mactab) { - $callback->({error=>["Unable to open mac table, it may not exist yet"],errorcode=>[1]}); - return; - } - $ent = $mactab->getNodeAttribs($node,[qw(mac)]); - unless ($ent and $ent->{mac}) { - $callback->({error=>["Unable to find mac address for $node"],errorcode=>[1]}); - return; - } - my @macs = split(/\|/,$ent->{mac}); - my $mace; - foreach $mace (@macs) { - my $mac; - my $hname; - $hname = ""; - ($mac,$hname) = split (/!/,$mace); - unless ($hname) { $hname = $node; } #Default to hostname equal to nodename - unless ($mac) { next; } #Skip corrupt format - my $inetn; - $inetn=""; - if ($hname eq '*NOIP*') { - $inetn = "DENIED"; - $hname = $node."-noip".$mac; - $hname =~ s/://g; - } else { - $inetn = inet_aton($hname); - } - unless ($inetn) { - syslog("local1|err","xCAT DHCP plugin unable to resolve IP for $hname (for $node)"); - return; - } - my $ip; - $ip=""; - if ($inetn eq "DENIED") { - $ip = "DENIED"; - } else { - $ip = inet_ntoa(inet_aton($hname));; - } - if ($guess_next_server and $ip ne "DENIED") { - my $nxtsrv = xCAT::Utils->my_ip_facing($hname); - if ($nxtsrv) { - $lstatements = "next-server $nxtsrv;$statements"; - } - } - syslog("local4|err","Setting $node ($hname|$ip) to ".$mac); - print $omshell "new host\n"; - print $omshell "set name = \"$hname\"\n"; #Find and destroy conflict name - print $omshell "open\n"; - print $omshell "remove\n"; - print $omshell "close\n"; - print $omshell "new host\n"; - print $omshell "set ip-address = $ip\n"; #find and destroy ip conflict - print $omshell "open\n"; - print $omshell "remove\n"; - print $omshell "close\n"; - print $omshell "new host\n"; - print $omshell "set hardware-address = ".$mac."\n"; #find and destroy mac conflict - print $omshell "open\n"; - print $omshell "remove\n"; - print $omshell "close\n"; - print $omshell "new host\n"; - print $omshell "set name = \"$hname\"\n"; - print $omshell "set hardware-address = ".$mac."\n"; - print $omshell "set hardware-type = 1\n"; - if ($ip eq "DENIED") { #Blacklist this mac to preclude confusion, give best shot at things working - print $omshell "set statements = \"deny booting;\"\n"; - } else { - print $omshell "set ip-address = $ip\n"; - if ($lstatements) { - print $omshell "set statements = \"$lstatements\"\n"; - } - } - - print $omshell "create\n"; - print $omshell "close\n"; - unless (grep /#definition for host $node aka host $hname/,@dhcpconf) { - push @dhcpconf,"#definition for host $node aka host $hname can be found in the dhcpd.leases file\n"; - } - } -} -sub preprocess_request { - my $req = shift; - $callback = shift; - if ($req->{_xcatdest}) { return [$req]; } #Exit if the packet has been preprocessed in its history - my @requests = ({%$req}); #Start with a straight copy to reflect local instance - my $sitetab = xCAT::Table->new('site'); - (my $ent) = $sitetab->getAttribs({key=>'xcatservers'},'value'); - $sitetab->close; - if ($ent and $ent->{value}) { - foreach (split /,/,$ent->{value}) { - if (xCAT::Utils->thishostisnot($_)) { - my $reqcopy = {%$req}; - $reqcopy->{'_xcatdest'} = $_; - push @requests,$reqcopy; - } - } - } - if (scalar(@requests) > 1) { #hierarchy detected, enforce more rigorous sanity - my $ntab = xCAT::Table->new('networks'); - if ($ntab) { - foreach (@{$ntab->getAllEntries()}) { - if ($_->{dynamicrange} and not $_->{dhcpserver}) { - $callback->({error=>["Hierarchy requested, therefore networks.dhcpserver must be set for net=".$_->{net}.""],errorcode=>[1]}); - return []; - } - } - } - } - - return \@requests; -} - -sub process_request { - my $req = shift; - $callback = shift; - my $sitetab = xCAT::Table->new('site'); - my %activenics; - my $querynics=1; - if ($sitetab) { - my $href; - ($href) = $sitetab->getAttribs({key=>'dhcpinterfaces'},'value'); - unless ($href and $href->{value}) { #LEGACY: singular keyname for old style site value - ($href) = $sitetab->getAttribs({key=>'dhcpinterface'},'value'); - } - if ($href and $href->{value}) { - foreach (split /[,\s]+/,$href->{value}) { - $activenics{$_} = 1; - $querynics=0; - } - } - ($href) = $sitetab->getAttribs({key=>'domain'},'value'); - unless ($href and $href->{value}) { - $callback->({error=>["No domain defined in site tabe"],errorcode=>[1]}); - return; - } - $domain = $href->{value}; - } - - @dhcpconf = (); - unless ($req->{arg} or $req->{node}) { - $callback->({data=>["Usage: makedhcp <-n> "]}); - return; - } - if (grep /^-n$/,@{$req->{arg}}) { - if (-e "/etc/dhcpd.conf") { - my $bakname = "/etc/dhcpd.conf.xcatbak"; - rename("/etc/dhcpd.conf",$bakname); - } - } else { - open($rconf,"/etc/dhcpd.conf"); # Read file into memory - if ($rconf) { - while (<$rconf>) { - push @dhcpconf,$_; - } - close($rconf); - } - unless ($dhcpconf[0] =~ /^#xCAT/) { #Discard file if not xCAT originated, like 1.x did - @dhcpconf = (); - } - } - @nrn = split /\n/,`/bin/netstat -rn`; - splice @nrn,0,2; #get rid of header - if ($querynics) { #Use netstat to determine activenics only when no site ent. - foreach (@nrn) { - my @ent = split /\s+/; - if ($ent[0] eq "169.254.0.0") { - next; - } - if ($ent[7] =~ m/(ipoib|ib|vlan|bond|eth|myri|man|wlan)/) { #Mask out many types of interfaces, like xCAT 1.x - $activenics{$ent[7]} = 1; - } - } - } - unless ($dhcpconf[0]) { #populate an empty config with some starter data... - newconfig(); - } - foreach (keys %activenics) { - addnic($_); - } - if (grep /^-a$/,@{$req->{arg}}) { - if (grep /-d$/,@{$req->{arg}}) { - $req->{node} = []; - my $nodelist = xCAT::Table->new('nodelist'); - my @entries = ($nodelist->getAllNodeAttribs([qw(node)])); - foreach (@entries) { - push @{$req->{node}},$_->{node}; - } - } else { - $req->{node} = []; - my $mactab = xCAT::Table->new('mac'); - my @entries = ($mactab->getAllNodeAttribs([qw(mac)])); - foreach (@entries) { - push @{$req->{node}},$_->{node}; - } - } - } - - if ($req->{node}) { - @ARGV = @{$req->{arg}}; - $statements=""; - GetOptions( - 's|statements=s' => \$statements - ); - - - - my $passtab = xCAT::Table->new('passwd'); + #Use omshell to add the node. + #the process used is blind typing commands that should work + #it tries to delet any conflicting entries matched by name and + #hardware address and ip address before creating a brand now one + #unfortunate side effect: dhcpd.leases can look ugly over time, when + #doing updates would keep it cleaner, good news, dhcpd restart cleans + #up the lease file the way we would want anyway. + my $node = shift; my $ent; - ($ent) = $passtab->getAttribs({key=>"omapi"},qw(username password)); - unless ($ent->{username} and $ent->{password}) { return; } # TODO sane err - #Have nodes to update - #open2($omshellout,$omshell,"/usr/bin/omshell"); - open($omshell,"|/usr/bin/omshell > /dev/null"); - - print $omshell "key ".$ent->{username}." \"".$ent->{password}."\"\n"; - print $omshell "connect\n"; - foreach(@{$req->{node}}) { - if (grep /^-d$/,@{$req->{arg}}) { - delnode $_; - } else { - unless (xCAT::Utils->nodeonmynet($_)) { - next; + my $nrtab = xCAT::Table->new('noderes'); + my $lstatements = $statements; + my $guess_next_server = 0; + if ($nrtab) + { + my $ent; + $ent = $nrtab->getNodeAttribs($node, ['tftpserver']); + if ($ent and $ent->{tftpserver}) + { + $lstatements = + 'next-server ' + . inet_ntoa(inet_aton($ent->{tftpserver})) . ';' + . $statements; } - addnode $_; - } + else + { + $guess_next_server = 1; + } + + #else { + # $ent = $nrtab->getNodeAttribs($node,['servicenode']); + # if ($ent and $ent->{servicenode}) { + # $statements = 'next-server = \"'.inet_ntoa(inet_aton($ent->{servicenode})).'\";'.$statements; + # } + #} } - close($omshell); - } - foreach (@nrn) { - my @line = split /\s+/; - if ($ent[0] eq "169.254.0.0") { - next; + else + { + $guess_next_server = 1; } - if ($activenics{$line[7]} and $line[3] !~ /G/) { - addnet($line[0],$line[2]); + my $mactab = xCAT::Table->new('mac'); + unless ($mactab) + { + $callback->( + { + error => ["Unable to open mac table, it may not exist yet"], + errorcode => [1] + } + ); + return; + } + $ent = $mactab->getNodeAttribs($node, [qw(mac)]); + unless ($ent and $ent->{mac}) + { + $callback->( + { + error => ["Unable to find mac address for $node"], + errorcode => [1] + } + ); + return; + } + my @macs = split(/\|/, $ent->{mac}); + my $mace; + foreach $mace (@macs) + { + my $mac; + my $hname; + $hname = ""; + ($mac, $hname) = split(/!/, $mace); + unless ($hname) + { + $hname = $node; + } #Default to hostname equal to nodename + unless ($mac) { next; } #Skip corrupt format + my $inetn; + $inetn = ""; + if ($hname eq '*NOIP*') + { + $inetn = "DENIED"; + $hname = $node . "-noip" . $mac; + $hname =~ s/://g; + } + else + { + $inetn = inet_aton($hname); + } + unless ($inetn) + { + syslog( + "local1|err", + "xCAT DHCP plugin unable to resolve IP for $hname (for $node)" + ); + return; + } + my $ip; + $ip = ""; + if ($inetn eq "DENIED") + { + $ip = "DENIED"; + } + else + { + $ip = inet_ntoa(inet_aton($hname)); + } + if ($guess_next_server and $ip ne "DENIED") + { + my $nxtsrv = xCAT::Utils->my_ip_facing($hname); + if ($nxtsrv) + { + $lstatements = "next-server $nxtsrv;$statements"; + } + } + syslog("local4|err", "Setting $node ($hname|$ip) to " . $mac); + print $omshell "new host\n"; + print $omshell + "set name = \"$hname\"\n"; #Find and destroy conflict name + print $omshell "open\n"; + print $omshell "remove\n"; + print $omshell "close\n"; + print $omshell "new host\n"; + print $omshell "set ip-address = $ip\n"; #find and destroy ip conflict + print $omshell "open\n"; + print $omshell "remove\n"; + print $omshell "close\n"; + print $omshell "new host\n"; + print $omshell "set hardware-address = " . $mac + . "\n"; #find and destroy mac conflict + print $omshell "open\n"; + print $omshell "remove\n"; + print $omshell "close\n"; + print $omshell "new host\n"; + print $omshell "set name = \"$hname\"\n"; + print $omshell "set hardware-address = " . $mac . "\n"; + print $omshell "set hardware-type = 1\n"; + + if ($ip eq "DENIED") + { #Blacklist this mac to preclude confusion, give best shot at things working + print $omshell "set statements = \"deny booting;\"\n"; + } + else + { + print $omshell "set ip-address = $ip\n"; + if ($lstatements) + { + print $omshell "set statements = \"$lstatements\"\n"; + } + } + + print $omshell "create\n"; + print $omshell "close\n"; + unless (grep /#definition for host $node aka host $hname/, @dhcpconf) + { + push @dhcpconf, + "#definition for host $node aka host $hname can be found in the dhcpd.leases file\n"; + } } - } - writeout(); } -sub addnet { - my $net = shift; - my $mask = shift; - my $nic; - unless (grep /\} # $net\/$mask subnet_end/,@dhcpconf) { - foreach (@nrn) { # search for relevant NIC - my @ent = split /\s+/; - if ($ent[0] eq "169.254.0.0") { - next; - } - if ($ent[0] eq $net and $ent[2] eq $mask) { - $nic=$ent[7]; - } +sub preprocess_request +{ + my $req = shift; + $callback = shift; + if ($req->{_xcatdest}) + { + return [$req]; + } #Exit if the packet has been preprocessed in its history + my @requests = + ({%$req}); #Start with a straight copy to reflect local instance + my @sn = xCAT::Utils->getSNList(dhcpserver); + foreach my $s (@sn) + { + my $reqcopy = {%$req}; + $reqcopy->{'_xcatdest'} = $s; + push @requests, $reqcopy; } - print "Need to add $net $mask under $nic\n"; - my $idx=0; - while ($idx <= $#dhcpconf) { - if ($dhcpconf[$idx] =~ /\} # $nic nic_end\n/) { - last; - } - $idx++; - } - unless ($dhcpconf[$idx] =~ /\} # $nic nic_end\n/) { - return 1; #TODO: this is an error condition - } - # if here, means we found the idx before which to insert - my $nettab = xCAT::Table->new("networks"); - my $nameservers; - my $gateway; - my $tftp; - my $range; - my $myip; - $myip = xCAT::Utils->my_ip_facing($net); - if ($nettab) { - my ($ent) = $nettab->getAttribs({net=>$net,mask=>$mask},qw(tftpserver nameservers gateway dynamicrange dhcpserver)); - if ($ent and $ent->{nameservers}) { - $nameservers = $ent->{nameservers}; - } else { - $callback->({warning=>["No $net specific entry for nameservers, and dhcp plugin not sourcing from site yet (TODO)"]}); - } - if ($ent and $ent->{tftpserver}) { - $tftp = $ent->{tftpserver}; - } else { #presume myself to be it, dhcp no longer does this for us - $tftp = $myip; - } - if ($ent and $ent->{gateway}) { - $gateway = $ent->{gateway}; - } - if ($ent and $ent->{dynamicrange}) { - unless ($ent->{dhcpserver} and xCAT::Utils->thishostisnot($ent->{dhcpserver})) { #If specific, only one dhcp server gets a dynamic range - $range = $ent->{dynamicrange}; - $range =~ s/[,-]/ /g; + if (scalar(@requests) > 1) + { #hierarchy detected, enforce more rigorous sanity + my $ntab = xCAT::Table->new('networks'); + if ($ntab) + { + foreach (@{$ntab->getAllEntries()}) + { + if ($_->{dynamicrange} and not $_->{dhcpserver}) + { + $callback->({error=>["Hierarchy requested, therefore networks.dhcpserver must be set for net=".$_->{net}.""],errorcode=>[1]}); + return []; + } + } } - } else { - $callback->({warning=>["No dynamic range specified for $net, unknown systems on this network will not receive an address"]}); - } - } else { - $callback->({error=>["Unable to open networks table, please run makenetworks"],errorcode=>[1]}); - return 1; } - my @netent; - my $maskn = unpack("N",inet_aton($mask)); - my $netn = unpack("N",inet_aton($net)); - @netent = ( - " subnet $net netmask $mask {\n", - " max-lease-time 43200;\n", - " min-lease-time 43200;\n", - " default-lease-time 43200;\n" - ); - if ($gateway) { - my $gaten = unpack("N",inet_aton($gateway)); - if (($gaten & $maskn) == ($maskn & $netn)) { - push @netent," option routers $gateway;\n"; - } else { - $callback->({error=>["Specified gateway $gateway is not valid for $net/$mask, must be on same network"],errorcode=>[1]}); - } - } - if ($tftp) { - push @netent," next-server $tftp;\n"; - } - push @netent," option log-servers $myip;\n"; - push @netent," option ntp-servers $myip;\n"; - push @netent," option domain-name \"$domain\";\n"; - if ($nameservers) { - push @netent," option domain-name-servers $nameservers;\n"; - } - push @netent," if option client-architecture = 00:00 { #x86\n"; - push @netent," filename \"pxelinux.0\";\n"; - push @netent," } else if option client-architecture = 00:02 { #ia64\n "; - push @netent," filename \"elilo.efi\";\n"; - push @netent," } else if substring(filename,0,1) = null { #otherwise, provide yaboot if the client isn't specific\n "; - push @netent," filename \"/yaboot\";\n"; - push @netent," }\n"; - if ($range) { push @netent," range dynamic-bootp $range;\n" }; - push @netent," } # $net\/$mask subnet_end\n"; - splice(@dhcpconf,$idx,0,@netent); - } + return \@requests; } +sub process_request +{ + my $req = shift; + $callback = shift; + my $sitetab = xCAT::Table->new('site'); + my %activenics; + my $querynics = 1; + if ($sitetab) + { + my $href; + ($href) = $sitetab->getAttribs({key => 'dhcpinterfaces'}, 'value'); + unless ($href and $href->{value}) + { #LEGACY: singular keyname for old style site value + ($href) = $sitetab->getAttribs({key => 'dhcpinterface'}, 'value'); + } + if ($href and $href->{value}) + { + foreach (split /[,\s]+/, $href->{value}) + { + $activenics{$_} = 1; + $querynics = 0; + } + } + ($href) = $sitetab->getAttribs({key => 'domain'}, 'value'); + unless ($href and $href->{value}) + { + $callback->( + {error => ["No domain defined in site tabe"], errorcode => [1]} + ); + return; + } + $domain = $href->{value}; + } + @dhcpconf = (); + unless ($req->{arg} or $req->{node}) + { + $callback->({data => ["Usage: makedhcp <-n> "]}); + return; + } + if (grep /^-n$/, @{$req->{arg}}) + { + if (-e "/etc/dhcpd.conf") + { + my $bakname = "/etc/dhcpd.conf.xcatbak"; + rename("/etc/dhcpd.conf", $bakname); + } + } + else + { + open($rconf, "/etc/dhcpd.conf"); # Read file into memory + if ($rconf) + { + while (<$rconf>) + { + push @dhcpconf, $_; + } + close($rconf); + } + unless ($dhcpconf[0] =~ /^#xCAT/) + { #Discard file if not xCAT originated, like 1.x did + @dhcpconf = (); + } + } + @nrn = split /\n/, `/bin/netstat -rn`; + splice @nrn, 0, 2; #get rid of header + if ($querynics) + { #Use netstat to determine activenics only when no site ent. + foreach (@nrn) + { + my @ent = split /\s+/; + if ($ent[0] eq "169.254.0.0") + { + next; + } + if ($ent[7] =~ m/(ipoib|ib|vlan|bond|eth|myri|man|wlan)/) + { #Mask out many types of interfaces, like xCAT 1.x + $activenics{$ent[7]} = 1; + } + } + } + unless ($dhcpconf[0]) + { #populate an empty config with some starter data... + newconfig(); + } + foreach (keys %activenics) + { + addnic($_); + } + if (grep /^-a$/, @{$req->{arg}}) + { + if (grep /-d$/, @{$req->{arg}}) + { + $req->{node} = []; + my $nodelist = xCAT::Table->new('nodelist'); + my @entries = ($nodelist->getAllNodeAttribs([qw(node)])); + foreach (@entries) + { + push @{$req->{node}}, $_->{node}; + } + } + else + { + $req->{node} = []; + my $mactab = xCAT::Table->new('mac'); + my @entries = ($mactab->getAllNodeAttribs([qw(mac)])); + foreach (@entries) + { + push @{$req->{node}}, $_->{node}; + } + } + } + if ($req->{node}) + { + @ARGV = @{$req->{arg}}; + $statements = ""; + GetOptions('s|statements=s' => \$statements); + + my $passtab = xCAT::Table->new('passwd'); + my $ent; + ($ent) = $passtab->getAttribs({key => "omapi"}, qw(username password)); + unless ($ent->{username} and $ent->{password}) + { + return; + } # TODO sane err + #Have nodes to update + #open2($omshellout,$omshell,"/usr/bin/omshell"); + open($omshell, "|/usr/bin/omshell > /dev/null"); + + print $omshell "key " + . $ent->{username} . " \"" + . $ent->{password} . "\"\n"; + print $omshell "connect\n"; + foreach (@{$req->{node}}) + { + if (grep /^-d$/, @{$req->{arg}}) + { + delnode $_; + } + else + { + unless (xCAT::Utils->nodeonmynet($_)) + { + next; + } + addnode $_; + } + } + close($omshell); + } + foreach (@nrn) + { + my @line = split /\s+/; + if ($ent[0] eq "169.254.0.0") + { + next; + } + if ($activenics{$line[7]} and $line[3] !~ /G/) + { + addnet($line[0], $line[2]); + } + } + writeout(); +} + +sub addnet +{ + my $net = shift; + my $mask = shift; + my $nic; + unless (grep /\} # $net\/$mask subnet_end/, @dhcpconf) + { + foreach (@nrn) + { # search for relevant NIC + my @ent = split /\s+/; + if ($ent[0] eq "169.254.0.0") + { + next; + } + if ($ent[0] eq $net and $ent[2] eq $mask) + { + $nic = $ent[7]; + } + } + print "Need to add $net $mask under $nic\n"; + my $idx = 0; + while ($idx <= $#dhcpconf) + { + if ($dhcpconf[$idx] =~ /\} # $nic nic_end\n/) + { + last; + } + $idx++; + } + unless ($dhcpconf[$idx] =~ /\} # $nic nic_end\n/) + { + return 1; #TODO: this is an error condition + } + + # if here, means we found the idx before which to insert + my $nettab = xCAT::Table->new("networks"); + my $nameservers; + my $gateway; + my $tftp; + my $range; + my $myip; + $myip = xCAT::Utils->my_ip_facing($net); + if ($nettab) + { + my ($ent) = + $nettab->getAttribs({net => $net, mask => $mask}, + qw(tftpserver nameservers gateway dynamicrange dhcpserver)); + if ($ent and $ent->{nameservers}) + { + $nameservers = $ent->{nameservers}; + } + else + { + $callback->( + { + warning => [ + "No $net specific entry for nameservers, and dhcp plugin not sourcing from site yet (TODO)" + ] + } + ); + } + if ($ent and $ent->{tftpserver}) + { + $tftp = $ent->{tftpserver}; + } + else + { #presume myself to be it, dhcp no longer does this for us + $tftp = $myip; + } + if ($ent and $ent->{gateway}) + { + $gateway = $ent->{gateway}; + } + if ($ent and $ent->{dynamicrange}) + { + unless ($ent->{dhcpserver} + and xCAT::Utils->thishostisnot($ent->{dhcpserver})) + { #If specific, only one dhcp server gets a dynamic range + $range = $ent->{dynamicrange}; + $range =~ s/[,-]/ /g; + } + } + else + { + $callback->( + { + warning => [ + "No dynamic range specified for $net, unknown systems on this network will not receive an address" + ] + } + ); + } + } + else + { + $callback->( + { + error => + ["Unable to open networks table, please run makenetworks"], + errorcode => [1] + } + ); + return 1; + } + + my @netent; + my $maskn = unpack("N", inet_aton($mask)); + my $netn = unpack("N", inet_aton($net)); + @netent = ( + " subnet $net netmask $mask {\n", + " max-lease-time 43200;\n", + " min-lease-time 43200;\n", + " default-lease-time 43200;\n" + ); + if ($gateway) + { + my $gaten = unpack("N", inet_aton($gateway)); + if (($gaten & $maskn) == ($maskn & $netn)) + { + push @netent, " option routers $gateway;\n"; + } + else + { + $callback->( + { + error => [ + "Specified gateway $gateway is not valid for $net/$mask, must be on same network" + ], + errorcode => [1] + } + ); + } + } + if ($tftp) + { + push @netent, " next-server $tftp;\n"; + } + push @netent, " option log-servers $myip;\n"; + push @netent, " option ntp-servers $myip;\n"; + push @netent, " option domain-name \"$domain\";\n"; + if ($nameservers) + { + push @netent, " option domain-name-servers $nameservers;\n"; + } + push @netent, " if option client-architecture = 00:00 { #x86\n"; + push @netent, " filename \"pxelinux.0\";\n"; + push @netent, + " } else if option client-architecture = 00:02 { #ia64\n "; + push @netent, " filename \"elilo.efi\";\n"; + push @netent, + " } else if substring(filename,0,1) = null { #otherwise, provide yaboot if the client isn't specific\n "; + push @netent, " filename \"/yaboot\";\n"; + push @netent, " }\n"; + if ($range) { push @netent, " range dynamic-bootp $range;\n" } + push @netent, " } # $net\/$mask subnet_end\n"; + splice(@dhcpconf, $idx, 0, @netent); + } +} + +sub addnic +{ + my $nic = shift; + my $firstindex = 0; + my $lastindex = 0; + unless (grep /} # $nic nic_end/, @dhcpconf) + { #add a section if not there + print "Adding NIC $nic\n"; + push @dhcpconf, "shared-network $nic {\n"; + push @dhcpconf, "\} # $nic nic_end\n"; + } -sub addnic { - my $nic = shift; - my $firstindex=0; - my $lastindex=0; - unless (grep /} # $nic nic_end/,@dhcpconf) { #add a section if not there - print "Adding NIC $nic\n"; - push @dhcpconf,"shared-network $nic {\n"; - push @dhcpconf,"\} # $nic nic_end\n"; - } #return; #Don't touch it, it should already be fine.. #my $idx=0; #while ($idx <= $#dhcpconf) { @@ -483,53 +643,68 @@ sub addnic { #print Dumper(\@dhcpconf); } - -sub writeout { - my $targ; - open($targ,'>',"/etc/dhcpd.conf"); - foreach (@dhcpconf) { - print $targ $_; - } - close($targ) +sub writeout +{ + my $targ; + open($targ, '>', "/etc/dhcpd.conf"); + foreach (@dhcpconf) + { + print $targ $_; + } + close($targ); } -sub newconfig { -# This function puts a standard header in and enough to make omapi work. - my $passtab = xCAT::Table->new('passwd',-create=>1); - push @dhcpconf,"#xCAT generated dhcp configuration\n"; - push @dhcpconf,"\n"; - push @dhcpconf,"authoritative;\n"; - push @dhcpconf,"ddns-update-style none;\n"; - push @dhcpconf,"option client-architecture code 93 = unsigned integer 16;\n"; - push @dhcpconf,"\n"; - push @dhcpconf,"omapi-port 7911;\n"; #Enable omapi... - push @dhcpconf,"key xcat_key {\n"; - push @dhcpconf," algorithm hmac-md5;\n"; - (my $passent) = $passtab->getAttribs({key=>omapi,username=>'xcat_key'},'password'); - my $secret = encode_base64(genpassword(32)); #Random from set of 62^32 - chomp $secret; - if ($passent->{password}) { $secret = $passent->{password}; } else { - $callback->({data=>["The dhcp server must be restarted for OMAPI function to work"]}); - $passtab->setAttribs({key=>omapi},{username=>'xcat_key',password=>$secret}); - } +sub newconfig +{ + # This function puts a standard header in and enough to make omapi work. + my $passtab = xCAT::Table->new('passwd', -create => 1); + push @dhcpconf, "#xCAT generated dhcp configuration\n"; + push @dhcpconf, "\n"; + push @dhcpconf, "authoritative;\n"; + push @dhcpconf, "ddns-update-style none;\n"; + push @dhcpconf, + "option client-architecture code 93 = unsigned integer 16;\n"; + push @dhcpconf, "\n"; + push @dhcpconf, "omapi-port 7911;\n"; #Enable omapi... + push @dhcpconf, "key xcat_key {\n"; + push @dhcpconf, " algorithm hmac-md5;\n"; + (my $passent) = + $passtab->getAttribs({key => omapi, username => 'xcat_key'}, 'password'); + my $secret = encode_base64(genpassword(32)); #Random from set of 62^32 + chomp $secret; + if ($passent->{password}) { $secret = $passent->{password}; } + else + { + $callback->( + { + data => + ["The dhcp server must be restarted for OMAPI function to work"] + } + ); + $passtab->setAttribs({key => omapi}, + {username => 'xcat_key', password => $secret}); + } - push @dhcpconf," secret \"".$secret."\";\n"; - push @dhcpconf,"};\n"; - push @dhcpconf,"omapi-key xcat_key;\n"; + push @dhcpconf, " secret \"" . $secret . "\";\n"; + push @dhcpconf, "};\n"; + push @dhcpconf, "omapi-key xcat_key;\n"; } -sub genpassword { -#Generate a pseudo-random password of specified length - my $length = shift; - my $password=''; - my $characters= 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890'; - srand; #have to reseed, rand is not rand otherwise - while (length($password) < $length) { - $password .= substr($characters,int(rand 63),1); - } - return $password; -} +sub genpassword +{ + #Generate a pseudo-random password of specified length + my $length = shift; + my $password = ''; + my $characters = + 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890'; + srand; #have to reseed, rand is not rand otherwise + while (length($password) < $length) + { + $password .= substr($characters, int(rand 63), 1); + } + return $password; +} 1;