Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,12 @@ public class MigrateVirtualMachineWithVolumeCmd extends BaseAsyncCmd {
"<1b331390-59f2-4796-9993-bf11c6e76225>&migrateto[2].pool=<41fdb564-9d3b-447d-88ed-7628f7640cbc>")
private Map migrateVolumeTo;

@Parameter(name = ApiConstants.AUTO_SELECT,
since = "4.19.0",
type = CommandType.BOOLEAN,
description = "Automatically select a destination host for a running instance, if hostId is not specified. false by default")
private Boolean autoSelect;

/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
Expand Down Expand Up @@ -151,23 +157,26 @@ public void execute() {
}

VirtualMachine virtualMachine = _userVmService.getVm(getVirtualMachineId());
if (!VirtualMachine.State.Running.equals(virtualMachine.getState()) && hostId != null) {
if (!VirtualMachine.State.Running.equals(virtualMachine.getState()) && (hostId != null || Boolean.TRUE.equals(autoSelect))) {
throw new InvalidParameterValueException(String.format("%s is not in the Running state to migrate it to the new host.", virtualMachine));
}

if (!VirtualMachine.State.Stopped.equals(virtualMachine.getState()) && hostId == null) {
throw new InvalidParameterValueException(String.format("%s is not in the Stopped state to migrate, use the %s parameter to migrate it to a new host.",
virtualMachine, ApiConstants.HOST_ID));
if (!VirtualMachine.State.Stopped.equals(virtualMachine.getState()) && hostId == null && Boolean.FALSE.equals(autoSelect)) {
throw new InvalidParameterValueException(String.format("%s is not in the Stopped state to migrate, use the %s or %s parameter to migrate it to a new host.",
virtualMachine, ApiConstants.HOST_ID,ApiConstants.AUTO_SELECT));
}

try {
VirtualMachine migratedVm = null;
if (hostId != null) {
Host destinationHost = _resourceService.getHost(getHostId());
// OfflineVmwareMigration: destination host would have to not be a required parameter for stopped VMs
if (destinationHost == null) {
s_logger.error(String.format("Unable to find the host with ID [%s].", getHostId()));
throw new InvalidParameterValueException("Unable to find the specified host to migrate the VM.");
if (getHostId() != null || Boolean.TRUE.equals(autoSelect)) {
Host destinationHost = null;
if (!Boolean.TRUE.equals(autoSelect)) {
destinationHost = _resourceService.getHost(getHostId());
// OfflineVmwareMigration: destination host would have to not be a required parameter for stopped VMs
if (destinationHost == null) {
s_logger.error(String.format("Unable to find the host with ID [%s].", getHostId()));
throw new InvalidParameterValueException("Unable to find the specified host to migrate the VM.");
}
}
migratedVm = _userVmService.migrateVirtualMachineWithVolume(getVirtualMachineId(), destinationHost, getVolumeToPool());
} else if (MapUtils.isNotEmpty(migrateVolumeTo)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,10 @@
// under the License.
package org.apache.cloudstack.api.command.admin.vm;

import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ManagementServerException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.VirtualMachineMigrationException;
import com.cloud.host.Host;
import com.cloud.resource.ResourceService;
import com.cloud.uservm.UserVm;
import com.cloud.utils.db.UUIDManager;
import com.cloud.vm.UserVmService;
import com.cloud.vm.VirtualMachine;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ResponseGenerator;
import org.apache.cloudstack.api.ResponseObject;
Expand All @@ -40,13 +34,21 @@
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.powermock.modules.junit4.PowerMockRunner;
import org.mockito.junit.MockitoJUnitRunner;
import org.springframework.test.util.ReflectionTestUtils;

import java.util.List;
import java.util.Map;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ManagementServerException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.exception.VirtualMachineMigrationException;
import com.cloud.host.Host;
import com.cloud.resource.ResourceService;
import com.cloud.uservm.UserVm;
import com.cloud.utils.db.UUIDManager;
import com.cloud.vm.UserVmService;
import com.cloud.vm.VirtualMachine;

@RunWith(PowerMockRunner.class)
@RunWith(MockitoJUnitRunner.class)
public class MigrateVirtualMachineWithVolumeCmdTest {
@Mock
UserVmService userVmServiceMock;
Expand All @@ -68,24 +70,25 @@ public class MigrateVirtualMachineWithVolumeCmdTest {

@Spy
@InjectMocks
MigrateVirtualMachineWithVolumeCmd cmdSpy = new MigrateVirtualMachineWithVolumeCmd();
MigrateVirtualMachineWithVolumeCmd cmdSpy;

private Long hostId = 1L;
private Long virtualMachineUuid = 1L;
private Long virtualMachineId = 1L;
private String virtualMachineName = "VM-name";
private Map<String, String> migrateVolumeTo = Map.of("key","value");
private Map<String, String> migrateVolumeTo = null;
private SystemVmResponse systemVmResponse = new SystemVmResponse();
private UserVmResponse userVmResponse = new UserVmResponse();

@Before
public void setup() {
Mockito.when(cmdSpy.getVirtualMachineId()).thenReturn(virtualMachineUuid);
Mockito.when(cmdSpy.getHostId()).thenReturn(hostId);
Mockito.when(cmdSpy.getVolumeToPool()).thenReturn(migrateVolumeTo);
public void setUp() throws Exception {
ReflectionTestUtils.setField(cmdSpy, "virtualMachineId", virtualMachineId);
migrateVolumeTo = new HashMap<>();
migrateVolumeTo.put("volume", "abc");
migrateVolumeTo.put("pool", "xyz");
}

@Test
public void executeTestHostIdIsNullAndMigrateVolumeToIsNullThrowsInvalidParameterValueException(){
public void executeTestHostIdIsNullAndMigrateVolumeToIsNullThrowsInvalidParameterValueException() {
ReflectionTestUtils.setField(cmdSpy, "hostId", null);
ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", null);

Expand All @@ -99,13 +102,13 @@ public void executeTestHostIdIsNullAndMigrateVolumeToIsNullThrowsInvalidParamete
}

@Test
public void executeTestVMIsStoppedAndHostIdIsNotNullThrowsInvalidParameterValueException(){
public void executeTestVMIsStoppedAndHostIdIsNotNullThrowsInvalidParameterValueException() {
ReflectionTestUtils.setField(cmdSpy, "hostId", hostId);
ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", migrateVolumeTo);

Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(virtualMachineMock);
Mockito.when(virtualMachineMock.getState()).thenReturn(VirtualMachine.State.Stopped);
Mockito.when(virtualMachineMock.toString()).thenReturn(String.format("VM [uuid: %s, name: %s]", virtualMachineUuid, virtualMachineName));
Mockito.when(virtualMachineMock.toString()).thenReturn(String.format("VM [uuid: %s, name: %s]", virtualMachineId, virtualMachineName));

try {
cmdSpy.execute();
Expand All @@ -117,33 +120,35 @@ public void executeTestVMIsStoppedAndHostIdIsNotNullThrowsInvalidParameterValueE
}

@Test
public void executeTestVMIsRunningAndHostIdIsNullThrowsInvalidParameterValueException(){
public void executeTestVMIsRunningAndHostIdIsNullThrowsInvalidParameterValueException() {
ReflectionTestUtils.setField(cmdSpy, "hostId", null);
ReflectionTestUtils.setField(cmdSpy, "autoSelect", false);
ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", migrateVolumeTo);

Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(virtualMachineMock);
Mockito.when(virtualMachineMock.getState()).thenReturn(VirtualMachine.State.Running);
Mockito.when(virtualMachineMock.toString()).thenReturn(String.format("VM [uuid: %s, name: %s]", virtualMachineUuid, virtualMachineName));
Mockito.when(virtualMachineMock.toString()).thenReturn(String.format("VM [uuid: %s, name: %s]", virtualMachineId, virtualMachineName));

try {
cmdSpy.execute();
} catch (Exception e) {
Assert.assertEquals(InvalidParameterValueException.class, e.getClass());
String expected = String.format("%s is not in the Stopped state to migrate, use the %s parameter to migrate it to a new host.", virtualMachineMock,
ApiConstants.HOST_ID);
String expected = String.format("%s is not in the Stopped state to migrate, use the %s or %s parameter to migrate it to a new host.", virtualMachineMock,
ApiConstants.HOST_ID, ApiConstants.AUTO_SELECT);
Assert.assertEquals(expected , e.getMessage());
}
}

@Test
public void executeTestHostIdIsNullThrowsInvalidParameterValueException(){
public void executeTestHostIdIsNullThrowsInvalidParameterValueException() {
ReflectionTestUtils.setField(cmdSpy, "virtualMachineId", virtualMachineId);
ReflectionTestUtils.setField(cmdSpy, "hostId", hostId);
ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", migrateVolumeTo);
ReflectionTestUtils.setField(cmdSpy, "autoSelect", false);

Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(virtualMachineMock);
Mockito.when(virtualMachineMock.getState()).thenReturn(VirtualMachine.State.Running);
Mockito.when(resourceServiceMock.getHost(Mockito.anyLong())).thenReturn(null);
Mockito.when(uuidManagerMock.getUuid(Host.class, virtualMachineUuid)).thenReturn(virtualMachineUuid.toString());

try {
cmdSpy.execute();
Expand All @@ -154,15 +159,22 @@ public void executeTestHostIdIsNullThrowsInvalidParameterValueException(){
}
}

private Map getMockedMigrateVolumeToApiCmdParam() {
Map<String, String> migrateVolumeTo = new HashMap<>();
migrateVolumeTo.put("volume", "abc");
migrateVolumeTo.put("pool", "xyz");
return Map.of("", migrateVolumeTo);
}

@Test
public void executeTestHostIsNotNullMigratedVMIsNullThrowsServerApiException() throws ManagementServerException, ResourceUnavailableException, VirtualMachineMigrationException {
ReflectionTestUtils.setField(cmdSpy, "hostId", hostId);
ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", migrateVolumeTo);
ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", getMockedMigrateVolumeToApiCmdParam());

Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(virtualMachineMock);
Mockito.when(virtualMachineMock.getState()).thenReturn(VirtualMachine.State.Running);
Mockito.when(resourceServiceMock.getHost(Mockito.anyLong())).thenReturn(hostMock);
Mockito.when(userVmServiceMock.migrateVirtualMachineWithVolume(virtualMachineUuid, hostMock, migrateVolumeTo)).thenReturn(null);
Mockito.when(resourceServiceMock.getHost(hostId)).thenReturn(hostMock);
Mockito.when(userVmServiceMock.migrateVirtualMachineWithVolume(Mockito.anyLong(), Mockito.any(), Mockito.anyMap())).thenReturn(null);

try {
cmdSpy.execute();
Expand All @@ -176,11 +188,11 @@ public void executeTestHostIsNotNullMigratedVMIsNullThrowsServerApiException() t
@Test
public void executeTestHostIsNullMigratedVMIsNullThrowsServerApiException() {
ReflectionTestUtils.setField(cmdSpy, "hostId", null);
ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", migrateVolumeTo);
ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", getMockedMigrateVolumeToApiCmdParam());

Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(virtualMachineMock);
Mockito.when(virtualMachineMock.getState()).thenReturn(VirtualMachine.State.Stopped);
Mockito.when(userVmServiceMock.vmStorageMigration(virtualMachineUuid, migrateVolumeTo)).thenReturn(null);
Mockito.when(userVmServiceMock.vmStorageMigration(Mockito.anyLong(), Mockito.anyMap())).thenReturn(null);

try {
cmdSpy.execute();
Expand All @@ -194,11 +206,11 @@ public void executeTestHostIsNullMigratedVMIsNullThrowsServerApiException() {
@Test
public void executeTestSystemVMMigratedWithSuccess() {
ReflectionTestUtils.setField(cmdSpy, "hostId", null);
ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", migrateVolumeTo);
ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", getMockedMigrateVolumeToApiCmdParam());

Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(virtualMachineMock);
Mockito.when(virtualMachineMock.getState()).thenReturn(VirtualMachine.State.Stopped);
Mockito.when(userVmServiceMock.vmStorageMigration(virtualMachineUuid, migrateVolumeTo)).thenReturn(virtualMachineMock);
Mockito.when(userVmServiceMock.vmStorageMigration(Mockito.anyLong(), Mockito.anyMap())).thenReturn(virtualMachineMock);
Mockito.when(virtualMachineMock.getType()).thenReturn(VirtualMachine.Type.ConsoleProxy);
Mockito.when(responseGeneratorMock.createSystemVmResponse(virtualMachineMock)).thenReturn(systemVmResponse);

Expand All @@ -211,11 +223,11 @@ public void executeTestSystemVMMigratedWithSuccess() {
public void executeTestUserVMMigratedWithSuccess() {
UserVm userVmMock = Mockito.mock(UserVm.class);
ReflectionTestUtils.setField(cmdSpy, "hostId", null);
ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", migrateVolumeTo);
ReflectionTestUtils.setField(cmdSpy, "migrateVolumeTo", getMockedMigrateVolumeToApiCmdParam());

Mockito.when(userVmServiceMock.getVm(Mockito.anyLong())).thenReturn(userVmMock);
Mockito.when(userVmMock.getState()).thenReturn(VirtualMachine.State.Stopped);
Mockito.when(userVmServiceMock.vmStorageMigration(virtualMachineUuid, migrateVolumeTo)).thenReturn(userVmMock);
Mockito.when(userVmServiceMock.vmStorageMigration(Mockito.anyLong(), Mockito.anyMap())).thenReturn(userVmMock);
Mockito.when(userVmMock.getType()).thenReturn(VirtualMachine.Type.User);
Mockito.when(responseGeneratorMock.createUserVmResponse(ResponseObject.ResponseView.Full, "virtualmachine", userVmMock)).thenReturn(List.of(userVmResponse));

Expand Down
Loading