Skip to content

Commit be93681

Browse files
committed
rescontruct vmspec to unmanage Stopped VM
1 parent c9bfec1 commit be93681

File tree

4 files changed

+116
-14
lines changed

4 files changed

+116
-14
lines changed

core/src/main/java/com/cloud/agent/api/UnmanageInstanceCommand.java

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,11 +19,14 @@
1919

2020
package com.cloud.agent.api;
2121

22+
import com.cloud.agent.api.to.VirtualMachineTO;
23+
2224
/**
2325
*/
2426
public class UnmanageInstanceCommand extends Command {
2527
String instanceName;
2628
boolean executeInSequence = false;
29+
VirtualMachineTO vm;
2730

2831
@Override
2932
public boolean executeInSequence() {
@@ -34,12 +37,20 @@ public boolean executeInSequence() {
3437
return executeInSequence;
3538
}
3639

37-
public UnmanageInstanceCommand(String instanceName, boolean executeInSequence) {
40+
public UnmanageInstanceCommand(VirtualMachineTO vm) {
41+
this.vm = vm;
42+
this.instanceName = vm.getName();
43+
}
44+
45+
public UnmanageInstanceCommand(String instanceName) {
3846
this.instanceName = instanceName;
39-
this.executeInSequence = executeInSequence;
4047
}
4148

4249
public String getInstanceName() {
4350
return instanceName;
4451
}
52+
53+
public VirtualMachineTO getVm() {
54+
return vm;
55+
}
4556
}

engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreDriver;
7171
import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
7272
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeDataFactory;
73+
import org.apache.cloudstack.engine.subsystem.api.storage.VolumeInfo;
7374
import org.apache.cloudstack.framework.ca.Certificate;
7475
import org.apache.cloudstack.framework.config.ConfigKey;
7576
import org.apache.cloudstack.framework.config.Configurable;
@@ -156,6 +157,7 @@
156157
import com.cloud.agent.api.VmNetworkStatsEntry;
157158
import com.cloud.agent.api.VmStatsEntry;
158159
import com.cloud.agent.api.routing.NetworkElementCommand;
160+
import com.cloud.agent.api.to.DataTO;
159161
import com.cloud.agent.api.to.DiskTO;
160162
import com.cloud.agent.api.to.DpdkTO;
161163
import com.cloud.agent.api.to.GPUDeviceTO;
@@ -2020,9 +2022,16 @@ public boolean unmanage(String vmUuid) {
20202022
boolean isDomainXMLPreserved = true;
20212023
// persist domain for kvm host
20222024
if (HypervisorType.KVM.equals(vm.getHypervisorType())) {
2023-
final UnmanageInstanceCommand unmanageInstanceCommand = new UnmanageInstanceCommand(vm.getName(), false);
2025+
long hostId = vm.getHostId();
2026+
UnmanageInstanceCommand unmanageInstanceCommand;
2027+
if (State.Stopped.equals(vm.getState())) {
2028+
hostId = vm.getLastHostId();
2029+
unmanageInstanceCommand = new UnmanageInstanceCommand(prepareVmTO(vm.getId(), hostId)); // reconstruct vmSpec
2030+
} else {
2031+
unmanageInstanceCommand = new UnmanageInstanceCommand(vm.getName());
2032+
}
20242033
try {
2025-
Answer answer = _agentMgr.send(vm.getHostId(), unmanageInstanceCommand);
2034+
Answer answer = _agentMgr.send(hostId, unmanageInstanceCommand);
20262035
isDomainXMLPreserved = (answer instanceof UnmanageInstanceAnswer && answer.getResult());
20272036
} catch (Exception ex) {
20282037
isDomainXMLPreserved = false;
@@ -4021,6 +4030,39 @@ private void checkAndSetEnterSetupMode(VirtualMachineTO vmTo, Map<VirtualMachine
40214030
vmTo.setEnterHardwareSetup(enterSetup == null ? false : enterSetup);
40224031
}
40234032

4033+
protected VirtualMachineTO prepareVmTO(Long vmId, Long hostId) {
4034+
final VMInstanceVO vm = _vmDao.findById(vmId);
4035+
final Account owner = _entityMgr.findById(Account.class, vm.getAccountId());
4036+
final ServiceOfferingVO offering = _offeringDao.findById(vm.getId(), vm.getServiceOfferingId());
4037+
final VirtualMachineTemplate template = _entityMgr.findByIdIncludingRemoved(VirtualMachineTemplate.class, vm.getTemplateId());
4038+
Host host = _hostDao.findById(hostId);
4039+
VirtualMachineProfileImpl vmProfile = new VirtualMachineProfileImpl(vm, template, offering, owner, null);
4040+
updateOverCommitRatioForVmProfile(vmProfile, host.getClusterId());
4041+
final List<NicVO> nics = _nicsDao.listByVmId(vmProfile.getId());
4042+
Collections.sort(nics, (nic1, nic2) -> {
4043+
Long nicId1 = Long.valueOf(nic1.getDeviceId());
4044+
Long nicId2 = Long.valueOf(nic2.getDeviceId());
4045+
return nicId1.compareTo(nicId2);
4046+
});
4047+
4048+
for (final NicVO nic : nics) {
4049+
final Network network = _networkModel.getNetwork(nic.getNetworkId());
4050+
final NicProfile nicProfile =
4051+
new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), null, _networkModel.isSecurityGroupSupportedInNetwork(network),
4052+
_networkModel.getNetworkTag(vmProfile.getHypervisorType(), network));
4053+
vmProfile.addNic(nicProfile);
4054+
}
4055+
4056+
List<VolumeVO> volumes = _volsDao.findUsableVolumesForInstance(vmId);
4057+
for (VolumeVO vol: volumes) {
4058+
VolumeInfo volumeInfo = volumeDataFactory.getVolume(vol.getId());
4059+
DataTO volTO = volumeInfo.getTO();
4060+
DiskTO disk = storageMgr.getDiskWithThrottling(volTO, vol.getVolumeType(), vol.getDeviceId(), vol.getPath(), vm.getServiceOfferingId(), vol.getDiskOfferingId());
4061+
vmProfile.addDisk(disk);
4062+
}
4063+
return toVmTO(vmProfile);
4064+
}
4065+
40244066
protected VirtualMachineTO getVmTO(Long vmId) {
40254067
final VMInstanceVO vm = _vmDao.findById(vmId);
40264068
final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm);

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtUnmanageInstanceCommandWrapper.java

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,20 @@
1919

2020
package com.cloud.hypervisor.kvm.resource.wrapper;
2121

22+
import java.net.URISyntaxException;
23+
2224
import org.libvirt.Connect;
2325
import org.libvirt.Domain;
2426
import org.libvirt.LibvirtException;
2527

2628
import com.cloud.agent.api.Answer;
2729
import com.cloud.agent.api.UnmanageInstanceAnswer;
2830
import com.cloud.agent.api.UnmanageInstanceCommand;
31+
import com.cloud.agent.api.to.VirtualMachineTO;
32+
import com.cloud.exception.InternalErrorException;
2933
import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource;
34+
import com.cloud.hypervisor.kvm.resource.LibvirtKvmAgentHook;
35+
import com.cloud.hypervisor.kvm.resource.LibvirtVMDef;
3036
import com.cloud.resource.CommandWrapper;
3137
import com.cloud.resource.ResourceWrapper;
3238

@@ -37,18 +43,60 @@ public final class LibvirtUnmanageInstanceCommandWrapper extends CommandWrapper<
3743
@Override
3844
public Answer execute(final UnmanageInstanceCommand command, final LibvirtComputingResource libvirtComputingResource) {
3945
String instanceName = command.getInstanceName();
46+
VirtualMachineTO vmSpec = command.getVm();
4047
final LibvirtUtilitiesHelper libvirtUtilitiesHelper = libvirtComputingResource.getLibvirtUtilitiesHelper();
41-
logger.debug("Unmanaging KVM instance: {}", instanceName);
48+
logger.debug("Attempting to unmanage KVM instance: {}", instanceName);
49+
Domain dom = null;
50+
Connect conn = null;
4251
try {
43-
Connect conn = libvirtUtilitiesHelper.getConnectionByVmName(instanceName);
44-
Domain dom = conn.domainLookupByName(instanceName);
45-
String domainXML = dom.getXMLDesc(1);
46-
conn.domainDefineXML(domainXML);
52+
if (vmSpec == null) {
53+
conn = libvirtUtilitiesHelper.getConnectionByVmName(instanceName);
54+
dom = conn.domainLookupByName(instanceName);
55+
String domainXML = dom.getXMLDesc(1);
56+
conn.domainDefineXML(domainXML).free();
57+
} else {
58+
// define domain using reconstructed vmSpec
59+
logger.debug("Unmanaging Stopped KVM instance: {}", instanceName);
60+
LibvirtVMDef vm = libvirtComputingResource.createVMFromSpec(vmSpec);
61+
libvirtComputingResource.createVbd(conn, vmSpec, instanceName, vm);
62+
conn = libvirtUtilitiesHelper.getConnectionByType(vm.getHvsType());
63+
String vmInitialSpecification = vm.toString();
64+
String vmFinalSpecification = performXmlTransformHook(vmInitialSpecification, libvirtComputingResource);
65+
conn.domainDefineXML(vmFinalSpecification).free();
66+
}
4767
logger.debug("Successfully unmanaged KVM instance: {}", instanceName);
4868
return new UnmanageInstanceAnswer(command, true, "Successfully unmanaged");
49-
} catch (final LibvirtException ex) {
50-
logger.warn("LibvirtException occurred during unmanaging instance: {} ", instanceName, ex);
51-
return new UnmanageInstanceAnswer(command, false, ex.getMessage());
69+
} catch (final LibvirtException e) {
70+
logger.warn("LibvirtException occurred during unmanaging instance: {} ", instanceName, e);
71+
return new UnmanageInstanceAnswer(command, false, e.getMessage());
72+
} catch (final URISyntaxException | InternalErrorException e) {
73+
logger.warn("URISyntaxException ", e);
74+
return new UnmanageInstanceAnswer(command, false, e.getMessage());
75+
} finally {
76+
if (dom != null) {
77+
try {
78+
dom.free();
79+
} catch (LibvirtException e) {
80+
logger.error("Ignore libvirt error on free.", e);
81+
}
82+
}
83+
}
84+
}
85+
86+
private String performXmlTransformHook(String vmInitialSpecification, final LibvirtComputingResource libvirtComputingResource) {
87+
String vmFinalSpecification;
88+
try {
89+
// if transformer fails, everything must go as it's just skipped.
90+
LibvirtKvmAgentHook t = libvirtComputingResource.getTransformer();
91+
vmFinalSpecification = (String) t.handle(vmInitialSpecification);
92+
if (null == vmFinalSpecification) {
93+
logger.warn("Libvirt XML transformer returned NULL, will use XML specification unchanged.");
94+
vmFinalSpecification = vmInitialSpecification;
95+
}
96+
} catch(Exception e) {
97+
logger.warn("Exception occurred when handling LibVirt XML transformer hook: {}", e);
98+
vmFinalSpecification = vmInitialSpecification;
5299
}
100+
return vmFinalSpecification;
53101
}
54102
}

server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2287,10 +2287,11 @@ public boolean unmanageVMInstance(long vmId) {
22872287

22882288
performUnmanageVMInstancePrechecks(vmVO);
22892289

2290-
Long hostId = findSuitableHostId(vmVO);
2290+
boolean isVMStopped = VirtualMachine.State.Stopped.equals(vmVO.getState());
2291+
Long hostId = isVMStopped ? vmVO.getLastHostId() : findSuitableHostId(vmVO);
22912292
String instanceName = vmVO.getInstanceName();
22922293

2293-
if (!existsVMToUnmanage(instanceName, hostId)) {
2294+
if (!isVMStopped && !existsVMToUnmanage(instanceName, hostId)) {
22942295
throw new CloudRuntimeException(String.format("VM %s is not found in the hypervisor", vmVO));
22952296
}
22962297

0 commit comments

Comments
 (0)