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 <name> -hbawwpn <wwpn> -force

And then map them together:
mkvdiskhostmap -host <host> -force <vdisk>

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
This commit is contained in:
Jarrod Johnson 2013-09-24 20:58:48 -04:00
parent 14696db19f
commit 25dd2ce800
3 changed files with 226 additions and 4 deletions

View File

@ -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.",
@ -2218,6 +2222,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 #
######################

View File

@ -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;

View File

@ -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;