diff --git a/xCAT-server/lib/xcat/plugins/rhevm.pm b/xCAT-server/lib/xcat/plugins/rhevm.pm
index 8c8f23a88..6c0447a4d 100644
--- a/xCAT-server/lib/xcat/plugins/rhevm.pm
+++ b/xCAT-server/lib/xcat/plugins/rhevm.pm
@@ -225,7 +225,7 @@ sub preprocess_request {
# The dispatch depends on the rhevm. Since the operation is in serial, so no need to use the service node.
my @requests;
my @rhevms=keys(%rhevm_hash);
- my $sn = xCAT::ServiceNodeUtils->get_ServiceNode(\@rhevms, 'xcat', "MN");
+ my $sn = xCAT::Utils->get_ServiceNode(\@rhevms, 'xcat', "MN");
foreach my $snkey (keys %$sn){
my $reqcopy = {%$request};
$reqcopy->{'_xcatdest'} = $snkey;
@@ -340,6 +340,8 @@ sub process_request {
if($command eq 'mkinstall'){
mkinstall($request, $callback, \%rhevm_hash);
+ } elsif ($command eq "rsetboot") {
+ rsetboot($callback, \%rhevm_hash, $args);
} elsif ($command eq "addhost") {
addhost($callback, \%rhevm_hash);
} elsif ($command eq "cfghost") {
@@ -352,7 +354,9 @@ sub process_request {
rmhost();
} elsif ($command eq "lsvm") {
lsvm($callback, \%rhevm_hash, $args);
- } elsif ($command eq "mkvm") {
+ } elsif ($command eq "chvm") {
+ chvm($callback, \%rhevm_hash, $nodes, $args);
+ }elsif ($command eq "mkvm") {
mkvm($callback, \%rhevm_hash, $nodes, $args);
} elsif ($command eq "rmvm") {
rmvm($callback, \%rhevm_hash, $args);
@@ -835,6 +839,7 @@ my $display = {
'used' => ["used"],
'committed' => ["committed"],
'storage_format' => ["storage_format"],
+ 'status' => ["status/state"],
},
'networks' => {
'description' => ["description"],
@@ -922,6 +927,7 @@ sub displaysrc {
my $type = shift;
my $prelead = shift;
my $criteria = shift;
+ my $individual = shift;
my @output;
my @displayed;
@@ -932,7 +938,11 @@ sub displaysrc {
} elsif ($type eq "clusters") {
$prefix = "/clusters/cluster";
} elsif ($type eq "storagedomains") {
- $prefix = "/storage_domains/storage_domain";
+ if ($individual) {
+ $prefix = "/storage_domain";
+ } else {
+ $prefix = "/storage_domains/storage_domain";
+ }
} elsif ($type eq "networks") {
$prefix = "/networks/network";
} elsif ($type eq "hosts") {
@@ -1071,7 +1081,8 @@ sub lsve {
unless ($rc) {
displaysrc($callback, $ref_rhevm, $response, "clusters", " ");
}
- ($rc, $id, $stat, $response) = search_src($ref_rhevm, "storagedomains", "datacenter%3D$obj");
+ #($rc, $id, $stat, $response) = search_src($ref_rhevm, "storagedomains", "datacenter%3D$obj");
+ ($rc, $id, $stat, $response) = search_src($ref_rhevm, "datacenters/$dcid/storagedomains:storagedomains");
unless ($rc) {
displaysrc($callback, $ref_rhevm, $response, "storagedomains", " ");
}
@@ -1136,7 +1147,7 @@ sub cfgve {
my $args = shift;
my $nodes = shift;
- my ($type, $objlist, $mgr, $datacenter, $create, $update, $remove, $activate, $deactivate, $attach, $detach);
+ my ($type, $objlist, $mgr, $datacenter, $create, $update, $remove, $activate, $deactivate, $attach, $detach, $force);
if ($args) {
@ARGV=@{$args};
GetOptions('t=s' => \$type,
@@ -1149,7 +1160,8 @@ sub cfgve {
's' => \$deactivate,
'a' => \$attach,
'b' => \$detach,
- 'r' => \$remove);
+ 'r' => \$remove,
+ 'f' => \$force);
}
my $rhevm = (keys %{$rhevm_hash})[0];
@@ -1170,7 +1182,7 @@ sub cfgve {
xCAT::MsgUtils->message("I", $rsp, $callback);
return;
}
- } elsif ($activate || $deactivate || $attach || $detach) {
+ } elsif ($activate || $deactivate || $attach || $detach || $remove) {
# get the name of datacenter
my $vsdtab = xCAT::Table->new('virtsd',-create=>0);
my $vsdent = $vsdtab->getAttribs({'node'=>$obj}, ['datacenter']);
@@ -1211,8 +1223,23 @@ sub cfgve {
push @{$rsp->{data}}, "$obj: succeeded.";
xCAT::MsgUtils->message("I", $rsp, $callback);
}
+ } elsif ($remove) {
+ if ($force) {
+ # deactivate the storage domain
+ activate($callback, $ref_rhevm,"/api/datacenters/$dcid/storagedomains/$sdid", $obj, 1);
+
+ # detach the storage domain to the datacenter
+ attach($callback, $ref_rhevm,"/api/datacenters/$dcid/storagedomains", "storage_domain", $sdid, 1);
+ }
+
+ if (!deleteSD($callback, $ref_rhevm, "/api/storagedomains/$sdid", $obj)) {
+ my $rsp;
+ push @{$rsp->{data}}, "$obj: delete storage domain succeeded.";
+ xCAT::MsgUtils->message("I", $rsp, $callback);
+ return;
+ }
}
- }
+ }
} elsif ($type eq "tpl") {
if ($remove) {
my ($rc, $tplid, $stat, $response) = search_src($ref_rhevm, "templates", "$obj");
@@ -1255,6 +1282,15 @@ sub cfgve {
xCAT::MsgUtils->message("I", $rsp, $callback);
next;
}
+ } elsif ($remove) {
+ my ($rc, $nwid, $stat) = search_src($ref_rhevm, "networks", $obj);
+ if ($rc) {
+ my $rsp;
+ push @{$rsp->{data}}, "$obj: failed to get networks: $obj.";
+ xCAT::MsgUtils->message("E", $rsp, $callback);
+ next;
+ }
+ generalaction($callback, $ref_rhevm, "/api/networks/$nwid", "DELETE", 1);
}
} else {
my $rsp;
@@ -2121,6 +2157,177 @@ sub rmvm {
# Change virtual machine
sub chvm {
+ my $callback = shift;
+ my $rhevm_hash = shift;
+ my $nodes = shift;
+
+ # Get the mac address for the nodes from the mac table
+ my $mactab = new xCAT::Table('mac',-create=>1);
+
+ # Get the attributes for the nodes from the vm table
+ my $vmtab = xCAT::Table->new('vm',-create=>0);
+ my $vment = $vmtab->getNodesAttribs($nodes,['template', 'host', 'cluster', 'virtflags', 'storage', 'storagemodel', 'memory', 'cpus', 'nics', 'nicmodel', 'bootorder', 'vidproto']);
+
+ foreach my $rhevm (keys %{$rhevm_hash}) {
+ my %node_hyp;
+ my %hostid;
+ my $success = 0;
+ # generate the hash of rhevm which will be used for the action functions
+ my $ref_rhevm = {'name' => $rhevm,
+ 'user' => $rhevm_hash->{$rhevm}->{user},
+ 'pw' => $rhevm_hash->{$rhevm}->{pw}};
+
+ # generate the node that will be handled
+ if (defined $rhevm_hash->{$rhevm}->{host}) {
+ foreach my $rhevh (keys %{$rhevm_hash->{$rhevm}->{host}}) {
+ if (defined $rhevm_hash->{$rhevm}->{host}->{$rhevh}->{node}) {
+ foreach (@{$rhevm_hash->{$rhevm}->{host}->{$rhevh}->{node}}) {
+ $node_hyp{$_}{hyp} = $rhevh;
+ $hostid{$rhevh} = 1;
+ }
+ }
+ }
+ } elsif (defined $rhevm_hash->{$rhevm}->{node}) {
+ foreach (@{$rhevm_hash->{$rhevm}->{node}}) {
+ $node_hyp{$_}{hyp} = "";
+ }
+ }
+
+ # get the host id
+ # this is used for the case that needs locate vm to a spcific host
+ foreach my $host (keys %hostid) {
+ my ($rc, $id, $stat) = search_src($ref_rhevm, "hosts", $host);
+ if ($rc) {
+ my $rsp;
+ push @{$rsp->{data}}, "Cannot find $host in the rhevm.";
+ xCAT::MsgUtils->message("E", $rsp, $callback);
+ return;
+ }
+ $hostid{$host} = $id;
+ }
+ my @nodes = (keys %node_hyp);
+ my $macmac = $mactab->getNodesAttribs(\@nodes, ['mac']);
+
+ foreach my $node (@nodes) {
+ my $myvment = $vment->{$node}->[0];
+ unless ($myvment) {
+ my $rsp;
+ push @{$rsp->{data}}, "$node: has NOT entry in vm table.";
+ xCAT::MsgUtils->message("E", $rsp, $callback);
+ next;
+ }
+
+ # Check the existence of the node
+ my ($rc, $vmid, $stat) = search_src($ref_rhevm, "vms", $node);
+ if ($rc) {
+ my $rsp;
+ push @{$rsp->{data}}, "$node: virtual machine was not created.";
+ xCAT::MsgUtils->message("I", $rsp, $callback);
+ next;
+ }
+
+ # generate the content
+ my $tplele;
+ if ($myvment->{template}) {
+ $tplele = "$myvment->{template}";
+ }
+
+ # configure memory
+ my $memele;
+ if ($myvment->{memory}) {
+ my $memsize = $myvment->{memory};
+ $memsize =~ s/g/000000000/i;
+ $memsize =~ s/m/000000/i;
+ $memele = "$memsize";
+ }
+
+ # set the cpu
+ my $cpuele;
+ if ($myvment->{cpus}) {
+ my ($socketnum, $corenum) = split(':', $myvment->{cpus});
+ unless ($corenum) {$corenum = 1;}
+ $cpuele = "";
+ }
+
+ # configure bootorder
+ # there's a bug that sequence is not correct to set two order, so currently just set one
+ my $boele;
+ if ($myvment->{bootorder}) {
+ my ($firstbr, $secbr) = split (',', $myvment->{bootorder});
+ if ($secbr) {
+ $boele = "";
+ } else {
+ $boele = "";
+ }
+ }
+
+ my $disele;
+ if ($myvment->{vidproto}) {
+ $disele = "$myvment->{vidproto}";
+ }
+
+ my $affinity;
+ if ($myvment->{virtflags}) {
+ # parse the specific parameters from vm.virtflags
+ my @pairs = split (':', $myvment->{virtflags});
+ foreach my $pair (@pairs) {
+ my ($name, $value) = split('=', $pair);
+ if ($name eq "placement_affinity") {
+ # set the affinity for placement_policy
+ $affinity = "$value"
+ }
+ }
+ }
+
+ my $hostele;
+ if ($myvment->{host}) {
+ $hostele = "{host}}\"/>";
+ }
+
+ my $placement_policy;
+ if ($affinity) {
+ $placement_policy = "$hostele$affinity";
+ } elsif ($hostele) {
+ $affinity = "migratable";
+ $placement_policy = "$hostele$affinity";
+ }
+
+ # set the cluster for the vm
+ my $clusterele;
+ if ($myvment->{cluster}) {
+ $clusterele = "$myvment->{cluster}";
+ }
+
+ my $api = "/api/vms/$vmid";
+ my $method = "PUT";
+
+ my $content = "server$node$clusterele$tplele$memele$cpuele$boele$placement_policy$disele";
+ my $request = genreq($ref_rhevm, $method, $api, $content);
+ my $response;
+ ($rc, $response) = send_req($ref_rhevm, $request->as_string());
+ if ($rc) {
+ my $rsp;
+ push @{$rsp->{data}}, "$node: $response";
+ xCAT::MsgUtils->message("E", $rsp, $callback);
+ next;
+ } else {
+ my $parser = XML::LibXML->new();
+ my $doc = $parser->parse_string($response);
+ my $state;
+ if ($node eq getAttr($doc, "/vm/name")) {
+ my $rsp;
+ push @{$rsp->{data}}, "$node: change vm completed.";
+ xCAT::MsgUtils->message("I", $rsp, $callback);
+ next;
+ } else {
+ my $rsp;
+ push @{$rsp->{data}}, "$node: change vm failed.";
+ xCAT::MsgUtils->message("E", $rsp, $callback);
+ next;
+ }
+ }
+ }
+ }
}
# Clone the virtual machine
@@ -2204,6 +2411,103 @@ sub clonevm {
}
+# Set the boot sequence for the vm
+sub rsetboot {
+ my $callback = shift;
+ my $rhevm_hash = shift;
+ my $args = shift;
+
+ my ($showstat, $bootdev);
+ if ($args) {
+ my $arg = $args->[0];
+ if ($arg =~ /^stat/) {
+ $showstat = 1;
+ } else {
+ $bootdev = $arg;
+ }
+ } else {
+ $showstat = 1;
+ }
+
+ my ($firstbr, $secbr);
+ if ($bootdev) {
+ ($firstbr, $secbr) = split (',', $bootdev);
+ if (($firstbr && $firstbr !~ /^(network|hd)$/) || ($secbr && $secbr !~ /^(network|hd)$/)) {
+ my $rsp;
+ push @{$rsp->{data}}, "Supported boot device: network, hd";
+ xCAT::MsgUtils->message("E", $rsp, $callback);
+ return 1;
+ }
+ }
+
+ foreach my $rhevm (keys %{$rhevm_hash}) {
+ my @nodes;
+ # generate the hash of rhevm which will be used for the action functions
+ my $ref_rhevm = {'name' => $rhevm,
+ 'user' => $rhevm_hash->{$rhevm}->{user},
+ 'pw' => $rhevm_hash->{$rhevm}->{pw}};
+
+ # generate the node that will be handled
+ if (defined $rhevm_hash->{$rhevm}->{host}) {
+ foreach my $rhevh (keys %{$rhevm_hash->{$rhevm}->{host}}) {
+ if (defined $rhevm_hash->{$rhevm}->{host}->{$rhevh}->{node}) {
+ push @nodes, @{$rhevm_hash->{$rhevm}->{host}->{$rhevh}->{node}};
+ }
+ }
+ } elsif (defined $rhevm_hash->{$rhevm}->{node}) {
+ push @nodes, @{$rhevm_hash->{$rhevm}->{node}};
+ }
+
+ foreach my $node (@nodes) {
+ # Get the ID of vm
+ my ($rc, $vmid, $state, $response) = search_src($ref_rhevm, "vms", $node);
+ if ($rc) {
+ my $rsp;
+ push @{$rsp->{data}}, "$node: node was not defined in the rhevm.";
+ xCAT::MsgUtils->message("E", $rsp, $callback);
+ next;
+ }
+
+ if ($showstat) {
+ my $parser = XML::LibXML->new();
+ my $doc = $parser->parse_string($response);
+ my @bootdevs = getAttr($doc, "/vms/vm/os/boot", "dev");
+ my $bootlist = join(',', @bootdevs);
+ my $rsp;
+ push @{$rsp->{data}}, "$node: $bootlist";
+ xCAT::MsgUtils->message("I", $rsp, $callback);
+ next;
+ }
+
+ # configure bootorder
+ my $boele;
+ if ($secbr) {
+ $boele = "";
+ } else {
+ $boele = "";
+ }
+
+ my $api = "/api/vms/$vmid";
+ my $method = "PUT";
+
+ my $content = "$boele";
+ my $request = genreq($ref_rhevm, $method, $api, $content);
+ ($rc, $response) = send_req($ref_rhevm, $request->as_string());
+ if ($rc) {
+ my $rsp;
+ push @{$rsp->{data}}, "$node: $response";
+ xCAT::MsgUtils->message("E", $rsp, $callback);
+ next;
+ } else {
+ my $rsp;
+ push @{$rsp->{data}}, "$node: set boot order completed.";
+ xCAT::MsgUtils->message("I", $rsp, $callback);
+ next;
+ }
+ }
+ }
+}
+
#Migrate the virtual machine
sub rmigrate {
my $callback = shift;
@@ -2350,9 +2654,15 @@ sub power {
if ($state eq "up" || $state eq "powering_up") {
my ($rc, $msg) = power_action($ref_rhevm, $id, 'stop');
if (!$rc) {
+ if (waitforcomplete($ref_rhevm, "/api/vms/$id", "/vm/status/state=down", 30)) {
+ my $rsp;
+ push @{$rsp->{data}}, "$node: failed to waiting the vm gets to \"down\" state.";
+ xCAT::MsgUtils->message("E", $rsp, $callback);
+ next;
+ }
($rc, $msg) = power_action($ref_rhevm, $id, 'start');
if (!$rc) {
- $output = "$node: reset";
+ $output = "$node: $args->[0]";
} else {
$output = "$node: $msg";
}
@@ -2362,7 +2672,7 @@ sub power {
} else {
my ($rc, $msg) = power_action($ref_rhevm, $id, 'start');
if (!$rc) {
- $output = "$node: reset";
+ $output = "$node: $args->[0]";
} else {
$output = "$node: $msg";
}
@@ -2378,13 +2688,24 @@ sub power {
$output = "$node: $msg";
}
}
+ } elsif ($args->[0] eq 'suspend') {
+ if ($state eq "suspended") {
+ $output = "$node: suspended";
+ } else {
+ my ($rc, $msg) = power_action($ref_rhevm, $id, 'suspend');
+ if (!$rc) {
+ $output = "$node: suspended";
+ } else {
+ $output = "$node: $msg";
+ }
+ }
} elsif ($args->[0] =~ /^stat/) {
- if ($state eq "down" || $state eq "powering_down" || $state eq "powered_down") {
+ if ($state eq "down") {
$output = "$node: off";
- } elsif ($state eq "up" || $state eq "powering_up") {
+ } elsif ($state eq "up") {
$output = "$node: on";
} else {
- $output = "$node: unknow";
+ $output = "$node: $state";
}
}
my $rsp;
@@ -2911,27 +3232,19 @@ sub mkSD {
xCAT::MsgUtils->message("E", $rsp, $callback);
return 0;
}
- $api = "/api/datacenters/$dcid/storagedomains";
- $method = "POST";
- my $content = "";
- $request = genreq($ref_rhevm, $method, $api, $content);
- ($rc, $response) = send_req($ref_rhevm, $request->as_string());
- if ($rc) {
+
+ # attach the storage domain to the datacenter
+ if (attach($callback, $ref_rhevm,"/api/datacenters/$dcid/storagedomains", "storage_domain", $sdid)) {
my $rsp;
- push @{$rsp->{data}}, "$sd: $response";
+ push @{$rsp->{data}}, "$sd: failed to attach to datacenter:$dc.";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 0;
}
# active the storage domain
- $api = "/api/datacenters/$dcid/storagedomains/$sdid/activate";
- $method = "POST";
- $content = "";
- $request = genreq($ref_rhevm, $method, $api, $content);
- ($rc, $response) = send_req($ref_rhevm, $request->as_string());
- if ($rc) {
+ if (activate($callback, $ref_rhevm,"/api/datacenters/$dcid/storagedomains/$sdid", $sd)) {
my $rsp;
- push @{$rsp->{data}}, "$sd: $response";
+ push @{$rsp->{data}}, "$sd: failed to activate the storage domain.";
xCAT::MsgUtils->message("E", $rsp, $callback);
return 0;
}
@@ -3001,11 +3314,18 @@ sub attach {
my $id = shift;
my $detach = shift;
+ my $method = "POST";
my $api;
my $content;
if ($type eq "storage_domain") {
- $api = $path;
- $content = "<$type id=\"$id\"/>";
+ if ($detach) {
+ $api = "$path/$id";
+ $method = "DELETE";
+ $content = "";
+ } else {
+ $api = $path;
+ $content = "<$type id=\"$id\"/>";
+ }
} else {
if ($detach) {
$api = $path."/detach";
@@ -3015,33 +3335,35 @@ sub attach {
$content = "<$type id=\"$id\"/>";
}
- my $method = "POST";
+
my $request = genreq($ref_rhevm, $method, $api, $content);
my ($rc, $response) = send_req($ref_rhevm, $request->as_string());
if ($rc) {
- my $rsp;
- push @{$rsp->{data}}, "$response";
- xCAT::MsgUtils->message("E", $rsp, $callback);
- return 1;
+ # no output for detaching sd from datacenter
+ if ($rc == 2 && $type eq "storage_domain" && $detach) {
+ return 0;
+ }
+ my $rsp;
+ push @{$rsp->{data}}, "$response:$rc";
+ xCAT::MsgUtils->message("E", $rsp, $callback);
+ return 1;
} else {
my $parser = XML::LibXML->new();
my $doc = $parser->parse_string($response);
if ($doc ) {
my $attr;
- if ($attr = getAttr($doc, "/action/status/state")) {
- if ($type eq "storage_domain") {
- if ($attr eq "inactive") {
+ if ($type eq "storage_domain") {
+ if ("inactive" eq getAttr($doc, "/storage_domain/status/state")) {
+ return 0;
+ } else {
+ return 1;
+ }
+ } else {
+ if ("complete" eq getAttr($doc, "/action/status/state")) {
return 0;
- } else {
+ } else {
return 1;
- }
- } else {
- if ($attr eq "complete") {
- return 0;
- } else {
- return 1;
- }
}
}
}
@@ -3071,10 +3393,66 @@ sub generalaction {
}
if ($rc) {
- my $rsp;
- push @{$rsp->{data}}, "$response";
- xCAT::MsgUtils->message("E", $rsp, $callback);
- return 1;
+ my $rsp;
+ push @{$rsp->{data}}, "$response";
+ xCAT::MsgUtils->message("E", $rsp, $callback);
+ return 1;
+ }
+}
+
+# delete storage domain
+sub deleteSD {
+ my $callback = shift;
+ my $ref_rhevm = shift;
+ my $path = shift;
+ my $sd = shift;
+
+ # get the attributes for the SD
+ my $vsdtab = xCAT::Table->new('virtsd',-create=>0);
+ my $vsdent = $vsdtab->getAttribs({'node'=>$sd}, ['host']);
+ unless ($vsdent) {
+ my $rsp;
+ push @{$rsp->{data}}, "$sd: cannot find the definition for $sd in the virtsd table.";
+ xCAT::MsgUtils->message("E", $rsp, $callback);
+ return 1;
+ }
+
+ unless ($vsdent->{host}) {
+ my $rsp;
+ push @{$rsp->{data}}, "$sd: a SPM host needs to be specified.";
+ xCAT::MsgUtils->message("E", $rsp, $callback);
+ return 1;
+ }
+
+ # get the id of host
+ my ($rc, $hostid, $stat) = search_src($ref_rhevm, "hosts", $vsdent->{host});
+ if ($rc) {
+ my $rsp;
+ push @{$rsp->{data}}, "$sd: Cannot find the host: $vsdent->{host} for the storag domain.";
+ xCAT::MsgUtils->message("E", $rsp, $callback);
+ return 1;
+ }
+
+ my $method = "DELETE";
+ my $api = $path;
+ my $content;
+
+ $content = "true";
+
+ my $request = genreq($ref_rhevm, $method, $api, $content);
+ my $response;
+ ($rc, $response) = send_req($ref_rhevm, $request->as_string());
+
+ # no need to handle response for DELETE
+ if ($rc) {
+ # no output for detaching sd from datacenter
+ if ($rc == 2) {
+ return 0;
+ }
+ my $rsp;
+ push @{$rsp->{data}}, "$response";
+ xCAT::MsgUtils->message("E", $rsp, $callback);
+ return 1;
}
}