From 203d7025ada03cb10da0880ec0211b007ef5d1ba Mon Sep 17 00:00:00 2001 From: Jarrod Johnson Date: Tue, 24 Sep 2013 20:58:48 -0400 Subject: [PATCH] Phase 1 of SVC plugin implementation This commit is able to create storage in an existing mdisk grp. It hardcodes the iogrp to 0 for now. The next step is to make hosts and vhostmap. mkhost -name -hbawwpn -force And then map them together: mkvdiskhostmap -host -force If boot, store the wwn into storage.osvolume for future use. Commands to do: attachstorage detachstorage showstorage rmstorage suspect frontending: lsmdiskgrp to show state of avail space will be appropriate --- perl-xCAT/xCAT/Schema.pm | 14 +- xCAT-server/lib/perl/xCAT/SSHInteract.pm | 11 +- xCAT-server/lib/xcat/plugins/svc.pm | 205 +++++++++++++++++++++++ 3 files changed, 226 insertions(+), 4 deletions(-) create mode 100644 xCAT-server/lib/xcat/plugins/svc.pm diff --git a/perl-xCAT/xCAT/Schema.pm b/perl-xCAT/xCAT/Schema.pm index bc4d38fa6..9f2f705de 100644 --- a/perl-xCAT/xCAT/Schema.pm +++ b/perl-xCAT/xCAT/Schema.pm @@ -267,11 +267,14 @@ virtsd => { }, storage => { - cols => [qw(node osvolume size state storagepool hypervisor fcprange volumetag comments disable)], + cols => [qw(node osvolume size state storagepool hypervisor fcprange volumetag type controller comments disable)], keys => [qw(node)], table_descr => 'Node storage resources', descriptions => { node => 'The node name', + controller => 'The management address to attach/detach new volumes. + In the scenario involving multiple controllers, this data must be + passed as argument rather than by table value', osvolume => "Specification of what storage to place the node OS image onto. Examples include: localdisk (Install to first non-FC attached disk) usbdisk (Install to first USB mass storage device seen) @@ -281,6 +284,7 @@ storage => { storagepool => 'Name of storage pool where the volume is assigned.', hypervisor => 'Name of the hypervisor where the volume is configured.', fcprange => 'A range of acceptable fibre channels that the volume can use. Examples include: 3B00-3C00;4B00-4C00.', + type => 'The plugin used to drive storage configuration (e.g. svc)', volumetag => 'A specific tag used to identify the volume in the autoyast or kickstart template.', comments => 'Any user-written notes.', disable => "Set to 'yes' or '1' to comment out this row.", @@ -2219,6 +2223,14 @@ my @nodeattrs = ( tabentry => 'storage.osvolume', access_tabentry => 'storage.node=attr:node', }, + {attr_name => 'storagcontroller', + tabentry => 'storage.controller', + access_tabentry => 'storage.node=attr:node', + }, + {attr_name => 'storagetype', + tabentry => 'storage.type', + access_tabentry => 'storage.node=attr:node', + }, ###################### # vm table # ###################### diff --git a/xCAT-server/lib/perl/xCAT/SSHInteract.pm b/xCAT-server/lib/perl/xCAT/SSHInteract.pm index be26fb5e2..9f95e8a7c 100644 --- a/xCAT-server/lib/perl/xCAT/SSHInteract.pm +++ b/xCAT-server/lib/perl/xCAT/SSHInteract.pm @@ -66,14 +66,19 @@ sub new { $self->print($password); my $nextline = $self->getline(); chomp($nextline); - while ($nextline =~ /^\s*$/) { + while ($nextline =~ /^\s*$/ or $nextline =~ /^Last login:/) { $nextline = $self->get(); chomp($nextline); } if ($nextline =~ /password:/i or $nextline =~ /Permission denied, please try again/ or $nextline =~ /disconnect from/) { die "Incorrect Password"; - } elsif ($nextline =~ /$promptex/) { - *$self->{_xcatsshinteract}->{_atprompt}=1; + } else { + while ($nextline =~ /^Last login:/) { + $nextline = $self->get(); + } + if ($nextline =~ /$promptex/) { + *$self->{_xcatsshinteract}->{_atprompt}=1; + } } } elsif ($match =~ /$promptex/) { *$self->{_xcatsshinteract}->{_atprompt}=1; diff --git a/xCAT-server/lib/xcat/plugins/svc.pm b/xCAT-server/lib/xcat/plugins/svc.pm new file mode 100644 index 000000000..a9990be10 --- /dev/null +++ b/xCAT-server/lib/xcat/plugins/svc.pm @@ -0,0 +1,205 @@ +# IBM(c) 2013 EPL license http://www.eclipse.org/legal/epl-v10.html +#---------------------------------------------------------------------- + +# Plugin to interface with IBM SVC managed storage +# +use strict; + +package xCAT_plugin::svc; + +use xCAT::SvrUtils qw/sendmsg/; +use xCAT::SSHInteract; +use Getopt::Long; +Getopt::Long::Configure("bundling"); +Getopt::Long::Configure("pass_through"); + +my $callback; +my $dorequest; +my %controllersessions; + +sub handled_commands { + return { + mkstorage => "storage:type", + rmstorage => "storage:type", + } +} + +sub mkstorage { + my $request = shift; + my $ctx = shift; + my @nodes = @{$request->{node}}; + my $shared = 0; + my $controller; + my $pool; + my $size; + my $boot = 0; + unless (ref $request->{arg}) { + die "TODO: usage"; + } + @ARGV = @{$request->{arg}}; + unless (GetOptions( + 'shared' => \$shared, + 'controller=s' => \$controller, + 'boot' => \$boot, + 'size=f' => \$size, + 'pool=s' => \$pool, + )) { + foreach (@nodes) { + sendmsg([1,"Error parsing arguments"],$callback,$_); + } + } + if ($shared and $boot) { + foreach (@nodes) { + sendmsg([1,"Storage can not be both shared and boot"],$callback,$_); + } + } + my $storagetab = xCAT::Table->new('storage'); + my $storents = $storagetab->getNodesAttribs(\@nodes, + [qw/controller storagepool size/]); + if ($shared) { + unless ($size) { + foreach (@nodes) { + sendmsg([1, + "Size for shared volumes must be specified as an argument" + ], $callback,$_); + } + } + unless ($pool) { + $pool = assure_identical_table_values(\@nodes, $storents, 'storagepool'); + } + unless ($controller) { + $controller = assure_identical_table_values(\@nodes, $storents, 'controller'); + } + unless (defined $pool and defined $controller) { + return; + } + my $lun = create_lun(controller=>$controller, size=>$size, pool=>$pool); + my $wwns = get_wwns(@nodes); + } else { + foreach my $node (@nodes) { + mkstorage_single(node=>$node, size=>$size, pool=>$pool, + boot=>$boot, controller=>$controller, + cfg=>$storents->{$node}); + } + } +} + +sub got_wwns { + use Data::Dumper; + print Dumper(@_); +} + +sub get_wwns { + my @nodes = @_; + my %request = ( + node => \@nodes, + command => [ 'rinv' ], + arg => [ 'wwn' ] + ); + use Data::Dumper; + print Dumper(\%request); + $dorequest->(\%request, \&got_wwns); +} + +my $globaluser; +my $globalpass; +sub get_svc_creds { + my $controller = shift; + if ($globaluser and $globalpass) { + return { 'user' => $globaluser, 'pass' => $globalpass } + } + my $passtab = xCAT::Table->new('passwd',-create=>0); + my $passent = $passtab->getAttribs({key=>'svc'}, qw/username password/); + $globaluser = $passent->{username}; + $globalpass = $passent->{password}; + return { 'user' => $globaluser, 'pass' => $globalpass } +} + +sub establish_session { + my %args = @_; + my $controller = $args{controller}; + if ($controllersessions{$controller}) { + return $controllersessions{$controller}; + } + #need to establish a new session + my $cred = get_svc_creds($controller); + my $sess = new xCAT::SSHInteract(-username=>$cred->{user}, + -password=>$cred->{pass}, + -host=>$controller, + -output_record_separator=>"\r", + #Errmode=>"return", + #Input_Log=>"/tmp/svcdbgl", + Prompt=>'/>$/'); + unless ($sess and $sess->atprompt) { die "TODO: cleanly handle bad login" } + $controllersessions{$controller} = $sess; + return $sess; +} + +sub create_lun { + my %args = @_; + my $session = establish_session(%args); + my $pool = $args{pool}; + my $size = $args{size}; + my @result = $session->cmd("mkvdisk -iogrp io_grp0 -mdiskgrp $pool -size $size -unit gb"); + if ($result[0] =~ m/Virtual Disk, id \[(\d*)\], successfully created/) { + my $diskid = $1; + my $name; + my $wwn; + @result = $session->cmd("lsvdisk $diskid"); + foreach (@result) { + chomp; + if (/^name (.*)\z/) { + $name = $1; + } elsif (/^vdisk_UID (.*)\z/) { + $wwn = $1; + } + } + return { name => $name, id => $diskid, wwn => $wwn }; + } +} + +sub assure_identical_table_values { + my $nodes = shift; + my $storents = shift; + my $attribute = shift; + my $lastval; + foreach my $node (@$nodes) { + my $sent = $storents->{$node}->[0]; + unless ($sent) { + sendmsg([1, "No $attribute in arguments or table"], + $callback, $node); + return undef; + } + my $currval = $storents->{$node}->{$attribute}; + unless ($currval) { + sendmsg([1, "No $attribute in arguments or table"], + $callback, $node); + return undef; + } + if ($lastval and $currval ne $lastval) { + sendmsg([1, + "$attribute mismatch in table config, try specifying as argument"], + $callback, $node); + return undef; + } + } + return $lastval; +} + +sub mkstorage_single { + my %args = @_; +} + +sub process_request { + my $request = shift; + $callback = shift; + $dorequest = shift; + if ($request->{command}->[0] eq 'mkstorage') { + mkstorage($request); + } + foreach (values %controllersessions) { + $_->close(); + } +} + +1;