From 7c5a4ba731d90aab2ca09c4df4eb07ada38ee290 Mon Sep 17 00:00:00 2001 From: vallard Date: Fri, 9 Jul 2010 06:24:18 +0000 Subject: [PATCH] Added support for local datastores: vmfs:// works. If the datastore is not found on the node it will try to create it with the first free disk it finds. If it finds no space, it errors out git-svn-id: https://svn.code.sf.net/p/xcat/code/xcat-core/trunk@6684 8638fb3e-16cb-4fca-ae20-7b5d299a9bcd --- xCAT-server/lib/xcat/plugins/esx.pm | 149 ++++++++++++++++++++-------- 1 file changed, 110 insertions(+), 39 deletions(-) diff --git a/xCAT-server/lib/xcat/plugins/esx.pm b/xCAT-server/lib/xcat/plugins/esx.pm index 5c907bc1b..3bd86d81e 100644 --- a/xCAT-server/lib/xcat/plugins/esx.pm +++ b/xCAT-server/lib/xcat/plugins/esx.pm @@ -417,7 +417,7 @@ sub validate_licenses { } my @newlicenses; foreach (@{$tablecfg{prodkey}->{$hyp}}) { - if ($_->{product} eq 'esx') { + if (defined($_->{product}) and $_->{product} eq 'esx') { my $key = uc($_->{key}); unless (grep /$key/,@licenses) { push @newlicenses,$key; @@ -1671,11 +1671,14 @@ sub register_vm {#Attempt to register existing instance of a VM $hyphash{$hyp}->{pool} = $hyphash{$hyp}->{conn}->get_view(mo_ref=>$hyphash{$hyp}->{hostview}->parent,properties=>['resourcePool'])->resourcePool; } + # Try to add an existing VM to the machine folder my $success = eval { $task = $hyphash{$hyp}->{vmfolder}->RegisterVM_Task(path=>getcfgdatastore($node,$hyphash{$hyp}->{datastoremap})." /$node/$node.vmx",name=>$node,pool=>$hyphash{$hyp}->{pool},asTemplate=>0); }; + # if we couldn't add it then it means it wasn't created yet. So we create it. if ($@ or not $success) { - print $@; + #if (ref($@) eq 'SoapFault') { + # if (ref($@->detail) eq 'NotFound') { register_vm_callback(undef, { node => $node, disksize => $disksize, @@ -1715,7 +1718,35 @@ sub register_vm_callback { $args->{blockedfun}->(%{$args->{blockedargs}}); } } - + + +sub getURI { + my $method = shift; + my $location = shift; + my $uri = ''; + + if($method =~ /nfs/){ + + (my $server,my $path) = split/\//,$location,2; + $server =~ s/:$//; #tolerate habitual colons + my $servern = inet_aton($server); + unless ($servern) { + sendmsg([1,"could not resolve '$server' to an address from vm.storage/vm.cfgstore"]); + } + $server = inet_ntoa($servern); + $uri = "nfs://$server/$path"; + }elsif($method =~ /vmfs/){ + (my $name, undef) = split /\//,$location,2; + $name =~ s/:$//; #remove a : if someone put it in for some reason. + $uri = "vmfs://$name"; + }else{ + sendmsg([1,"Unsupported VMware Storage Method: $method. Please use 'vmfs or nfs'"]); + } + + return $uri; +} + + sub getcfgdatastore { my $node = shift; my $dses = shift; @@ -1727,14 +1758,7 @@ sub getcfgdatastore { } $cfgdatastore =~ s/=.*//; (my $method,my $location) = split /:\/\//,$cfgdatastore,2; - (my $server,my $path) = split/\//,$location,2; - $server =~ s/:$//; #tolerate habitual colons - my $servern = inet_aton($server); - unless ($servern) { - sendmsg([1,"could not resolve '$server' to an address from vm.storage/vm.cfgstore"]); - } - $server = inet_ntoa($servern); - my $uri = "nfs://$server/$path"; + my $uri = getURI($method,$location); $cfgdatastore = "[".$dses->{$uri}."]"; #$cfgdatastore =~ s/,.*$//; #these two lines of code were kinda pointless #$cfgdatastore =~ s/\/$//; @@ -1784,7 +1808,7 @@ sub getguestid { my $nodeos = $tablecfg{nodetype}->{$node}->[0]->{os}; my $nodearch = $tablecfg{nodetype}->{$node}->[0]->{arch}; foreach (keys %guestidmap) { - if ($nodeos =~ /$_/) { + if (defined($nodeos) and $nodeos =~ /$_/) { if ($nodearch eq 'x86_64') { $nodeos=$guestidmap{$_}."64Guest"; } else { @@ -1797,7 +1821,7 @@ sub getguestid { } } unless ($osfound) { - if ($nodearch eq 'x86_64') { + if (defined($nodearch) and $nodearch eq 'x86_64') { $nodeos="otherGuest64"; } else { $nodeos="otherGuest"; @@ -1845,8 +1869,9 @@ sub build_cfgspec { } else { $uuid=xCAT::Utils::genUUID(); } + my $vpdtab = xCAT::Table->new('vpd'); - $vpdtab->setNodeAttribs($node,{uuid=>$uuid}); + $vpdtab->setNodeAttribs($node,{uuid=>$uuid}); } return VirtualMachineConfigSpec->new( name => $node, @@ -1951,15 +1976,16 @@ sub create_storage_devs { } $storeloc =~ s/\/$//; (my $method,my $location) = split /:\/\//,$storeloc,2; - (my $server,my $path) = split/\//,$location,2; - $server =~ s/:$//; #tolerate habitual colons - my $servern = inet_aton($server); - unless ($servern) { - sendmsg([1,"could not resolve '$server' to an address from vm.storage"]); - return; - } - $server = inet_ntoa($servern); - my $uri = "nfs://$server/$path"; + my $uri = getURI($method, $location); + #(my $server,my $path) = split/\//,$location,2; + #$server =~ s/:$//; #tolerate habitual colons + #my $servern = inet_aton($server); + #unless ($servern) { + # sendmsg([1,"could not resolve '$server' to an address from vm.storage"]); + # return; + #} + #$server = inet_ntoa($servern); + #my $uri = "nfs://$server/$path"; $backingif = VirtualDiskFlatVer2BackingInfo->new(diskMode => 'persistent', fileName => "[".$sdmap->{$uri}."]"); if ($disktype eq 'ide' and $idecontrollerkey eq 1 and $ideunitnum eq 0) { #reserve a spot for CD @@ -2392,6 +2418,8 @@ sub validate_datastore_prereqs { my $node; my $method; my $location; + # get all of the datastores that are currently available on this node. + # and put them into a hash if (defined $hostview->{datastore}) { # only iterate if it exists foreach (@{$hostview->datastore}) { my $dsv = $hypconn->get_view(mo_ref=>$_); @@ -2407,10 +2435,18 @@ sub validate_datastore_prereqs { $hyphash{$hyp}->{datastoremap}->{"nfs://".$mnthost.$dsv->info->nas->remotePath}=$dsv->info->name; $hyphash{$hyp}->{datastorerefmap}->{"nfs://".$mnthost.$dsv->info->nas->remotePath}=$_; } #TODO: care about SMB - } #TODO: care about VMFS + }elsif(defined $dsv->info->{vmfs}){ + my $name = $dsv->info->vmfs->name; + $hyphash{$hyp}->{datastoremap}->{"vmfs://".$name} = $dsv->info->name; + $hyphash{$hyp}->{datasotrerefmap}->{"vmfs://".$name} = $_; + } } } my $refresh_names=0; + # now go through the nodes and make sure that we have matching datastores. + # E.g.: if its NFS, then mount it (if not mounted) + # E.g.: if its VMFS, then create it if not created already. Note: VMFS will persist on + # machine reboots, unless its destroyed by being overwritten. foreach $node (@$nodes) { my @storage = split /,/,$tablecfg{vm}->{$node}->[0]->{storage}; if ($tablecfg{vm}->{$node}->[0]->{cfgstore}) { @@ -2421,29 +2457,41 @@ sub validate_datastore_prereqs { s/\/$//; #Strip trailing slash if specified, to align to VMware semantics if (/:\/\//) { ($method,$location) = split /:\/\//,$_,2; - (my $server, my $path) = split /\//,$location,2; - $server =~ s/:$//; #remove a : if someone put it in out of nfs mount habit - my $servern = inet_aton($server); - unless ($servern) { - sendmsg([1,": Unable to resolve '$server' to an address, check vm.cfgstore/vm.storage"]); - return 0; - } - $server = inet_ntoa($servern); - my $uri = "nfs://$server/$path"; - unless ($method =~ /nfs/) { + if($method =~ /nfs/){ + # go through and see if NFS is mounted, if not, then mount it. + (my $server, my $path) = split /\//,$location,2; + $server =~ s/:$//; #remove a : if someone put it in out of nfs mount habit + my $servern = inet_aton($server); + unless ($servern) { + sendmsg([1,": Unable to resolve '$server' to an address, check vm.cfgstore/vm.storage"]); + return 0; + } + $server = inet_ntoa($servern); + my $uri = "nfs://$server/$path"; + unless ($hyphash{$hyp}->{datastoremap}->{$uri}) { #If not already there, must mount it + $refresh_names=1; + ($hyphash{$hyp}->{datastoremap}->{$uri},$hyphash{$hyp}->{datastorerefmap}->{$uri})=mount_nfs_datastore($hostview,$location); + } + }elsif($method =~ /vmfs/){ + (my $name, undef) = split /\//,$location,2; + $name =~ s/:$//; #remove a : if someone put it in for some reason. + my $uri = "vmfs://$name"; + # check and see if this vmfs is on the node. + unless ($hyphash{$hyp}->{datastoremap}->{$uri}) { #If not already there, try creating it. + ($hyphash{$hyp}->{datastoremap}->{$uri},$hyphash{$hyp}->{datastorerefmap}->{$uri})=create_vmfs_datastore($hostview,$name); + } + }else{ sendmsg([1,": $method is unsupported at this time (nfs would be)"],$node); return 0; } - unless ($hyphash{$hyp}->{datastoremap}->{$uri}) { #If not already there, must mount it - $refresh_names=1; - ($hyphash{$hyp}->{datastoremap}->{$uri},$hyphash{$hyp}->{datastorerefmap}->{$uri})=mount_nfs_datastore($hostview,$location); - } } else { - sendmsg([1,": $_ not supported storage specification for ESX plugin, 'nfs:///' only currently supported vm.storage supported for ESX at the moment"],$node); + sendmsg([1,": $_ not supported storage specification for ESX plugin,\n\t'nfs:///'\n\t\tor\n\t'vmfs://'\n only currently supported vm.storage supported for ESX at the moment"],$node); return 0; } #TODO: raw device mapping, VMFS via iSCSI, VMFS via FC? } } + # newdatastores are for migrations or changing vms. + # TODO: make this work for VMFS. Right now only NFS. if (ref $newdatastores) { foreach (keys %$newdatastores) { s/\/$//; #Strip trailing slash if specified, to align to VMware semantics @@ -2552,6 +2600,29 @@ sub mount_nfs_datastore { return ($location,$dsref); } +# create a VMFS data store on a node so that VMs can live locally instead of NFS +sub create_vmfs_datastore { + my $hostview = shift; # VM object + my $name = shift; # name of storage we wish to create. + # call some VMware API here to create + my $hdss = $hostview->{vim}->get_view(mo_ref=>$hostview->configManager->datastoreSystem); + my $diskList = $hdss->QueryAvailableDisksForVmfs(); + my $count = scalar(@$diskList); # get the number of disks available for formatting. + unless($count >0){ + die "No disks are available to create VMFS volume for $name"; + } + foreach my $disk(@$diskList){ + my $options = $hdss->QueryVmfsDatastoreCreateOptions(devicePath => $disk->devicePath); + @$options[0]->spec->vmfs->volumeName($name); + my $newDatastore = $hdss->CreateVmfsDatastore(spec => @$options[0]->spec ); + #return $newDatastore; + # create it on the first disk we see. + return ($name, $newDatastore); + } + return 0; +} + + sub build_more_info{ die("TODO: fix this function if called");