Skip to content

Commit 62da865

Browse files
authored
FR572 - KCPS2 migration improvements (#47)
Changes ported from 4.9.1.0-shapeblue8 Summarised changes from the 4.9.1.0-shapeblue8 release: Changes will be done to bypass secondary storage during the migration of a detached volume while using migrateVolume API. Instead, a worker VM is used, as the transport mechanism, to migrate a detached volume with vMotion (volume is attached to the worker VM, VM migrated, volume detached), while paying attention to the cluster in which the worker VM is created. Additionally, to improve the robustness of the CloudStack job queue framework for volumes. Change is made similar to the code change present in the upstream CloudStack repository pull request apache#2739
1 parent 5b8c32c commit 62da865

File tree

44 files changed

+2185
-706
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+2185
-706
lines changed

api/src/com/cloud/hypervisor/HypervisorGuru.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import java.util.List;
2020
import java.util.Map;
2121

22+
import com.cloud.storage.StoragePool;
2223
import org.apache.cloudstack.framework.config.ConfigKey;
2324

2425
import com.cloud.agent.api.Command;
@@ -84,4 +85,13 @@ public interface HypervisorGuru extends Adapter {
8485
List<Command> finalizeExpungeVolumes(VirtualMachine vm);
8586

8687
Map<String, String> getClusterSettings(long vmId);
88+
89+
/**
90+
* will generate commands to migrate a vm to a pool. For now this will ony work for stopped VMs on Vmware.
91+
*
92+
* @param vm the stopped vm to migrate
93+
* @param destination the primary storage pool to migrate to
94+
* @return a list of commands to perform for a successful migration
95+
*/
96+
List<Command> finalizeMigrate(VirtualMachine vm, StoragePool destination);
8797
}

api/src/com/cloud/storage/VolumeApiService.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,17 @@
2929
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
3030
import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
3131
import org.apache.cloudstack.api.response.GetUploadParamsResponse;
32+
import org.apache.cloudstack.framework.config.ConfigKey;
3233

3334
import com.cloud.exception.ResourceAllocationException;
3435
import com.cloud.user.Account;
3536

3637
public interface VolumeApiService {
38+
ConfigKey<Long> ConcurrentMigrationsThresholdPerDatastore = new ConfigKey<Long>("Advanced", Long.class,
39+
"concurrent.migrations.per.target.datastore", "0",
40+
"Limits number of migrations that can be handled per target datastore concurrently. Default is 0 - unlimited.",
41+
true, ConfigKey.Scope.Global);
42+
3743
/**
3844
* Creates the database object for a volume based on the given criteria
3945
*

api/src/org/apache/cloudstack/api/BaseAsyncCmd.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ public abstract class BaseAsyncCmd extends BaseCmd {
2727
public static final String ipAddressSyncObject = "ipaddress";
2828
public static final String networkSyncObject = "network";
2929
public static final String vpcSyncObject = "vpc";
30+
public static final String migrationSyncObject = "migration";
3031
public static final String snapshotHostSyncObject = "snapshothost";
3132
public static final String gslbSyncObject = "globalserverloadbalancer";
3233
private static final Logger s_logger = Logger.getLogger(BaseAsyncCmd.class.getName());

api/src/org/apache/cloudstack/api/command/admin/vm/MigrateVMCmd.java

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444

4545
@APICommand(name = "migrateVirtualMachine",
4646
description = "Attempts Migration of a VM to a different host or Root volume of the vm to a different storage pool",
47-
responseObject = UserVmResponse.class, entityType = {VirtualMachine.class},
47+
responseObject = UserVmResponse.class, entityType = {VirtualMachine.class},
4848
requestHasSensitiveInfo = false,
4949
responseHasSensitiveInfo = true)
5050
public class MigrateVMCmd extends BaseAsyncCmd {
@@ -149,6 +149,7 @@ public void execute() {
149149
CallContext.current().setEventDetails("VM Id: " + getVirtualMachineId() + " to host Id: " + getHostId());
150150
}
151151

152+
// OfflineMigration performed when this parameter is specified
152153
StoragePool destStoragePool = null;
153154
if (getStoragePoolId() != null) {
154155
destStoragePool = _storageService.getStoragePool(getStoragePoolId());
@@ -186,4 +187,25 @@ public void execute() {
186187
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
187188
}
188189
}
190+
191+
@Override
192+
public String getSyncObjType() {
193+
if (getSyncObjId() != null) {
194+
return BaseAsyncCmd.migrationSyncObject;
195+
}
196+
return null;
197+
}
198+
199+
@Override
200+
public Long getSyncObjId() {
201+
if (getStoragePoolId() != null) {
202+
return getStoragePoolId();
203+
}
204+
// OfflineVmwareMigrations: undocumented feature;
205+
// OfflineVmwareMigrations: on implementing a maximum queue size for per storage migrations it seems counter intuitive for the user to not enforce it for hosts as well.
206+
if (getHostId() != null) {
207+
return getHostId();
208+
}
209+
return null;
210+
}
189211
}

api/src/org/apache/cloudstack/api/command/admin/vm/MigrateVirtualMachineWithVolumeCmd.java

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@
4646

4747
@APICommand(name = "migrateVirtualMachineWithVolume",
4848
description = "Attempts Migration of a VM with its volumes to a different host",
49-
responseObject = UserVmResponse.class, entityType = {VirtualMachine.class},
49+
responseObject = UserVmResponse.class, entityType = {VirtualMachine.class},
5050
requestHasSensitiveInfo = false,
5151
responseHasSensitiveInfo = true)
5252
public class MigrateVirtualMachineWithVolumeCmd extends BaseAsyncCmd {
@@ -147,6 +147,7 @@ public void execute() {
147147
}
148148

149149
Host destinationHost = _resourceService.getHost(getHostId());
150+
// OfflineVmwareMigration: destination host would have to not be a required parameter for stopped VMs
150151
if (destinationHost == null) {
151152
throw new InvalidParameterValueException("Unable to find the host to migrate the VM, host id =" + getHostId());
152153
}
@@ -163,13 +164,7 @@ public void execute() {
163164
} catch (ResourceUnavailableException ex) {
164165
s_logger.warn("Exception: ", ex);
165166
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
166-
} catch (ConcurrentOperationException e) {
167-
s_logger.warn("Exception: ", e);
168-
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
169-
} catch (ManagementServerException e) {
170-
s_logger.warn("Exception: ", e);
171-
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
172-
} catch (VirtualMachineMigrationException e) {
167+
} catch (ConcurrentOperationException | ManagementServerException | VirtualMachineMigrationException e) {
173168
s_logger.warn("Exception: ", e);
174169
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
175170
}

api/src/org/apache/cloudstack/api/command/user/volume/MigrateVolumeCmd.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -119,4 +119,19 @@ public void execute() {
119119
}
120120
}
121121

122+
@Override
123+
public String getSyncObjType() {
124+
if (getSyncObjId() != null) {
125+
return BaseAsyncCmd.migrationSyncObject;
126+
}
127+
return null;
128+
}
129+
130+
@Override
131+
public Long getSyncObjId() {
132+
if (getStoragePoolId() != null) {
133+
return getStoragePoolId();
134+
}
135+
return null;
136+
}
122137
}
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//
2+
// Licensed to the Apache Software Foundation (ASF) under one
3+
// or more contributor license agreements. See the NOTICE file
4+
// distributed with this work for additional information
5+
// regarding copyright ownership. The ASF licenses this file
6+
// to you under the Apache License, Version 2.0 (the
7+
// "License"); you may not use this file except in compliance
8+
// with the License. You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing,
13+
// software distributed under the License is distributed on an
14+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
// KIND, either express or implied. See the License for the
16+
// specific language governing permissions and limitations
17+
// under the License.
18+
//
19+
20+
package com.cloud.agent.api;
21+
22+
import org.apache.cloudstack.storage.to.VolumeObjectTO;
23+
24+
import java.util.List;
25+
26+
public class MigrateVmToPoolAnswer extends Answer {
27+
28+
List<VolumeObjectTO> volumeTos;
29+
30+
public MigrateVmToPoolAnswer(MigrateVmToPoolCommand cmd, Exception ex) {
31+
super(cmd, ex);
32+
volumeTos = null;
33+
}
34+
35+
public MigrateVmToPoolAnswer(MigrateVmToPoolCommand cmd, List<VolumeObjectTO> volumeTos) {
36+
super(cmd, true, null);
37+
this.volumeTos = volumeTos;
38+
}
39+
40+
public List<VolumeObjectTO> getVolumeTos() {
41+
return volumeTos;
42+
}
43+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
//
2+
// Licensed to the Apache Software Foundation (ASF) under one
3+
// or more contributor license agreements. See the NOTICE file
4+
// distributed with this work for additional information
5+
// regarding copyright ownership. The ASF licenses this file
6+
// to you under the Apache License, Version 2.0 (the
7+
// "License"); you may not use this file except in compliance
8+
// with the License. You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing,
13+
// software distributed under the License is distributed on an
14+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
// KIND, either express or implied. See the License for the
16+
// specific language governing permissions and limitations
17+
// under the License.
18+
//
19+
package com.cloud.agent.api;
20+
21+
import com.cloud.agent.api.to.VolumeTO;
22+
23+
import java.util.Collection;
24+
25+
/**
26+
* used to tell the agent to migrate a vm to a different primary storage pool.
27+
* It is for now only implemented on Vmware and is supposed to work irrespective of whether the VM is started or not.
28+
*
29+
*/
30+
public class MigrateVmToPoolCommand extends Command {
31+
private Collection<VolumeTO> volumes;
32+
private String vmName;
33+
private String destinationPool;
34+
private boolean executeInSequence = false;
35+
36+
protected MigrateVmToPoolCommand() {
37+
}
38+
39+
/**
40+
*
41+
* @param vmName the name of the VM to migrate
42+
* @param volumes used to supply feedback on vmware generated names
43+
* @param destinationPool the primary storage pool to migrate the VM to
44+
* @param executeInSequence
45+
*/
46+
public MigrateVmToPoolCommand(String vmName, Collection<VolumeTO> volumes, String destinationPool, boolean executeInSequence) {
47+
this.vmName = vmName;
48+
this.volumes = volumes;
49+
this.destinationPool = destinationPool;
50+
this.executeInSequence = executeInSequence;
51+
}
52+
53+
public Collection<VolumeTO> getVolumes() {
54+
return volumes;
55+
}
56+
57+
public String getDestinationPool() {
58+
return destinationPool;
59+
}
60+
61+
public String getVmName() {
62+
return vmName;
63+
}
64+
65+
@Override
66+
public boolean executeInSequence() {
67+
return executeInSequence;
68+
}
69+
70+
}

core/src/com/cloud/agent/api/UnregisterVMCommand.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,14 +22,19 @@
2222
public class UnregisterVMCommand extends Command {
2323
String vmName;
2424
boolean cleanupVmFiles = false;
25+
boolean executeInSequence = false;
2526

2627
public UnregisterVMCommand(String vmName) {
28+
this(vmName, false);
29+
}
30+
public UnregisterVMCommand(String vmName, boolean executeInSequence) {
2731
this.vmName = vmName;
32+
this.executeInSequence = executeInSequence;
2833
}
2934

3035
@Override
3136
public boolean executeInSequence() {
32-
return false;
37+
return executeInSequence;
3338
}
3439

3540
public String getVmName() {

core/src/com/cloud/agent/api/storage/MigrateVolumeCommand.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ public class MigrateVolumeCommand extends Command {
3131
long volumeId;
3232
String volumePath;
3333
StorageFilerTO pool;
34+
StorageFilerTO sourcePool;
3435
String attachedVmName;
3536
Volume.Type volumeType;
3637

@@ -47,12 +48,14 @@ public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool pool,
4748
}
4849

4950
public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool pool, String attachedVmName, Volume.Type volumeType, int timeout) {
50-
this.volumeId = volumeId;
51-
this.volumePath = volumePath;
52-
this.pool = new StorageFilerTO(pool);
51+
this(volumeId,volumePath,pool,timeout);
5352
this.attachedVmName = attachedVmName;
5453
this.volumeType = volumeType;
55-
this.setWait(timeout);
54+
}
55+
56+
public MigrateVolumeCommand(long volumeId, String volumePath, StoragePool sourcePool, StoragePool targetPool) {
57+
this(volumeId,volumePath,targetPool, null, Volume.Type.UNKNOWN, -1);
58+
this.sourcePool = new StorageFilerTO(sourcePool);
5659
}
5760

5861
public MigrateVolumeCommand(DataTO srcData, DataTO destData, Map<String, String> srcDetails, Map<String, String> destDetails, int timeout) {
@@ -81,6 +84,14 @@ public StorageFilerTO getPool() {
8184
return pool;
8285
}
8386

87+
public StorageFilerTO getSourcePool() {
88+
return sourcePool;
89+
}
90+
91+
public StorageFilerTO getTargetPool() {
92+
return pool;
93+
}
94+
8495
public String getAttachedVmName() {
8596
return attachedVmName;
8697
}

0 commit comments

Comments
 (0)