package xCAT_plugin::iscsi; use strict; use xCAT::Table; use Socket; use File::Path; use File::Basename; use Getopt::Long; Getopt::Long::Configure("bundling"); Getopt::Long::Configure("pass_through"); sub handled_commands { return { "setupiscsidev" => "iscsi", }; } sub get_tid { #generate a unique tid given a node for tgtadm to use my $node = shift; my $tid = unpack("N",inet_aton($node)); $tid = $tid & ((2**31)-1); return $tid; } sub preprocess_request { my $request = shift; my $callback = shift; my @requests = (); my %iscsiserverhash; if ($request->{_xcatpreprocessed}->[0] == 1) { return [$request]; } my $iscsitab = xCAT::Table->new('iscsi'); foreach my $node (@{$request->{node}}) { my $tent = $iscsitab->getNodeAttribs($node,['server']); if ($tent and $tent->{server}) { $iscsiserverhash{$tent->{server}}->{$node} = 1; } else { $callback->({error=>["No iscsi.server for $node, aborting request"]}); return []; } } foreach my $iscsis (keys %iscsiserverhash) { my $reqcopy = {%$request}; $reqcopy->{'_xcatdest'} = $iscsis; $reqcopy->{_xcatpreprocessed}->[0] = 1; $reqcopy->{node} = [ keys %{$iscsiserverhash{$iscsis}} ]; push @requests,$reqcopy; } return \@requests; } sub process_request { my $request = shift; my $callback = shift; unless (-x "/usr/sbin/tgtadm") { $callback->({error=>"/usr/sbin/tgtadm does not exist, iSCSI plugin currently requires it, please install scsi-target-utils package under CentOS, RHEL, or Fedora. SLES support is not yet implemented",errorcode=>[1]}); return; } my $lunsize = 4096; if ($request->{arg}) { @ARGV=@{$request->{arg}}; GetOptions( "size|s=i" => \$lunsize, ); } my $iscsitab = xCAT::Table->new('iscsi'); my @nodes = @{$request->{node}}; my $sitetab = xCAT::Table->new('site'); unless ($sitetab) { $callback->({error=>"Fatal error opening site table",errorcode=>[1]}); return; } my $domain; (my $ipent) = $sitetab->getAttribs({key=>'domain'},'value'); if ($ipent and $ipent->{value}) { $domain = $ipent->{value}; } ($ipent) = $sitetab->getAttribs({key=>'iscsidir'},'value'); my $iscsiprefix; if ($ipent and $ipent->{value}) { $iscsiprefix = $ipent->{value}; } foreach my $node (@nodes) { my $fileloc; my %rsp; %rsp=(name=>[$node]); my $iscsient = $iscsitab->getNodeAttribs($node,['file']); if ($iscsient and $iscsient->{file}) { $fileloc = $iscsient->{file}; unless ($fileloc =~ /^\//) { unless ($iscsiprefix) { $rsp{error}=["$node: Unable to identify file to back iSCSI LUN, no iscsidir in site table and iscsi.file entry for node is a relative path"]; $rsp{errorcode}=[1]; $callback->({node=>[\%rsp]}); %rsp=(name=>[$node]); next; } $fileloc=$iscsiprefix."/".$iscsient->{file}; } } else { unless ($iscsiprefix) { $rsp{error}=["$node: Unable to identify file to back iSCSI LUN, no iscsidir in site table nor iscsi.file entry for node (define at least either)"]; $rsp{errorcode}=[1]; $callback->({node=>[\%rsp]}); %rsp=(name=>[$node]); next; } $fileloc = "$iscsiprefix/$node"; $iscsitab->setNodeAttribs($node,{file=>$fileloc}); } unless (-d dirname($fileloc)) { mkpath dirname($fileloc); } unless (-f $fileloc) { $rsp{name}=[$node]; $rsp{data}=["Creating $fileloc ($lunsize MB)"]; $callback->({node=>[\%rsp]}); %rsp=(name=>[$node]); $lunsize -= 1; my $rc = system("dd if=/dev/zero of=$fileloc bs=1M count=1 seek=$lunsize"); $lunsize += 1; if ($rc) { $rsp{error}=["dd process exited with return code $rc"]; $rsp{errorcode} = [1]; $callback->({node=>[\%rsp]}); %rsp=(name=>[$node]); next; } } my $targname; my $lun; $iscsient = $iscsitab->getNodeAttribs($node,['target','lun']); if ($iscsient and $iscsient->{target}) { $targname = $iscsient->{target}; } if ($iscsient and defined($iscsient->{lun})) { $lun = $iscsient->{lun}; } else { $lun = '1'; $iscsitab->setNodeAttribs($node,{lun=>$lun}); } unless ($targname) { my @date = localtime; my $year = 1900+$date[5]; my $month = $date[4]; $targname = "iqn.$year-$month.$domain:$node"; $iscsitab->setNodeAttribs($node,{target=>$targname}); } system("tgtadm --mode target --op delete --tid ".get_tid($node)." -T $targname"); my $rc = system("tgtadm --mode target --op new --tid ".get_tid($node)." -T $targname"); if ($rc) { $rsp{error}=["tgtadm --mode target --op new --tid ".get_tid($node)." -T $targname returned $rc"]; if ($rc == 27392) { push @{$rsp{error}},"This likely indicates the need to do /etc/init.d/tgtd start"; } $rsp{errorcode} = [1]; $callback->({node=>[\%rsp]}); %rsp=(name=>[$node]); next; } $rc = system("tgtadm --mode logicalunit --op new --tid ".get_tid($node)." --lun 1 --backing-store $fileloc --device-type disk"); if ($rc) { $rsp{error}=["tgtadm --mode logicalunit --op new --tid ".get_tid($node)." --lun 1 --backing-store $fileloc returned $rc"]; $rsp{errorcode} = [1]; $callback->({node=>[\%rsp]}); %rsp=(name=>[$node]); next; } $rc = system("tgtadm --mode target --op bind --tid ".get_tid($node)." -I ".inet_ntoa(inet_aton($node))); if ($rc) { $rsp{error}=["tgtadm --mode target --op bind --tid ".get_tid($node)." -I ".inet_ntoa(inet_aton($node)) . " returned $rc"]; $rsp{errorcode} = [1]; $callback->({node=>[\%rsp]}); %rsp=(name=>[$node]); } else { $rsp{data}=["iSCSI LUN configured"]; $callback->({node=>[\%rsp]}); %rsp=(name=>[$node]); } } } 1;