Skip to content

Commit 9717669

Browse files
Pearl1594Pearl Dsilva
andauthored
server: Fix issue with volume resize on VMWare (deploy as-is templates) (#4829)
This PR fixes the issue pertaining to volume resize on VMWare for deploy as-is templates. VMware deploy as-is templates are those that are deployed as per the specification in the imported OVF. Hence override root disk size will not be adhered to for such templates. Moreover, when we deploy VMs in stopped state and resize the volume, the root disk doesn't get resized but the volume size is merely updated in the DB. This PR also includes the following (for deploy as-is templates): - Disables overriding root disk size during VM deployment on the UI - Disables selection of compute offerings with root disk size specified, at the time of deployment - Provided users with the option to deploy VM is stopped state via UI (so as to give an option to users to resize the volumes before starting the VM) Co-authored-by: Pearl Dsilva <pearl.dsilva@shapeblue.com>
1 parent 918c3bd commit 9717669

8 files changed

Lines changed: 91 additions & 6 deletions

File tree

plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2071,7 +2071,13 @@ protected StartAnswer execute(StartCommand cmd) {
20712071
// Setup ROOT/DATA disk devices
20722072
//
20732073
for (DiskTO vol : sortedDisks) {
2074-
if (vol.getType() == Volume.Type.ISO || deployAsIs && vol.getType() == Volume.Type.ROOT) {
2074+
if (vol.getType() == Volume.Type.ISO) {
2075+
continue;
2076+
}
2077+
2078+
if (deployAsIs && vol.getType() == Volume.Type.ROOT) {
2079+
rootDiskTO = vol;
2080+
resizeRootDiskOnVMStart(vmMo, rootDiskTO, hyperHost, context);
20752081
continue;
20762082
}
20772083

plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
import org.apache.cloudstack.api.BaseCmd;
3232
import org.apache.cloudstack.api.command.user.firewall.CreateFirewallRuleCmd;
3333
import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
34+
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
3435
import org.apache.commons.codec.binary.Base64;
3536
import org.apache.commons.collections.CollectionUtils;
3637
import org.apache.log4j.Level;
@@ -70,6 +71,10 @@
7071
import com.cloud.network.rules.dao.PortForwardingRulesDao;
7172
import com.cloud.offering.ServiceOffering;
7273
import com.cloud.resource.ResourceManager;
74+
import com.cloud.storage.Volume;
75+
import com.cloud.storage.VolumeApiService;
76+
import com.cloud.storage.VolumeVO;
77+
import com.cloud.storage.dao.VolumeDao;
7378
import com.cloud.user.Account;
7479
import com.cloud.user.SSHKeyPairVO;
7580
import com.cloud.uservm.UserVm;
@@ -118,6 +123,10 @@ public class KubernetesClusterResourceModifierActionWorker extends KubernetesClu
118123
protected VMInstanceDao vmInstanceDao;
119124
@Inject
120125
protected UserVmManager userVmManager;
126+
@Inject
127+
protected VolumeApiService volumeService;
128+
@Inject
129+
protected VolumeDao volumeDao;
121130

122131
protected String kubernetesClusterNodeNamePrefix;
123132

@@ -268,13 +277,37 @@ protected DeployDestination plan() throws InsufficientServerCapacityException {
268277
return plan(kubernetesCluster.getTotalNodeCount(), zone, offering);
269278
}
270279

280+
protected void resizeNodeVolume(final UserVm vm) throws ManagementServerException {
281+
try {
282+
if (vm.getHypervisorType() == Hypervisor.HypervisorType.VMware && templateDao.findById(vm.getTemplateId()).isDeployAsIs()) {
283+
List<VolumeVO> vmVols = volumeDao.findByInstance(vm.getId());
284+
for (VolumeVO volumeVO : vmVols) {
285+
if (volumeVO.getVolumeType() == Volume.Type.ROOT) {
286+
ResizeVolumeCmd resizeVolumeCmd = new ResizeVolumeCmd();
287+
resizeVolumeCmd = ComponentContext.inject(resizeVolumeCmd);
288+
Field f = resizeVolumeCmd.getClass().getDeclaredField("size");
289+
Field f1 = resizeVolumeCmd.getClass().getDeclaredField("id");
290+
f.setAccessible(true);
291+
f1.setAccessible(true);
292+
f1.set(resizeVolumeCmd, volumeVO.getId());
293+
f.set(resizeVolumeCmd, kubernetesCluster.getNodeRootDiskSize());
294+
volumeService.resizeVolume(resizeVolumeCmd);
295+
}
296+
}
297+
}
298+
} catch (IllegalAccessException | NoSuchFieldException e) {
299+
throw new ManagementServerException(String.format("Failed to resize volume of VM in the Kubernetes cluster : %s", kubernetesCluster.getName()), e);
300+
}
301+
}
302+
271303
protected void startKubernetesVM(final UserVm vm) throws ManagementServerException {
272304
try {
273305
StartVMCmd startVm = new StartVMCmd();
274306
startVm = ComponentContext.inject(startVm);
275307
Field f = startVm.getClass().getDeclaredField("id");
276308
f.setAccessible(true);
277309
f.set(startVm, vm.getId());
310+
resizeNodeVolume(vm);
278311
userVmService.startVirtualMachine(startVm);
279312
if (LOGGER.isInfoEnabled()) {
280313
LOGGER.info(String.format("Started VM : %s in the Kubernetes cluster : %s", vm.getDisplayName(), kubernetesCluster.getName()));
@@ -296,6 +329,7 @@ protected List<UserVm> provisionKubernetesClusterNodeVms(final long nodeCount, f
296329
for (int i = offset + 1; i <= nodeCount; i++) {
297330
UserVm vm = createKubernetesNode(publicIpAddress, i);
298331
addKubernetesClusterVm(kubernetesCluster.getId(), vm.getId());
332+
resizeNodeVolume(vm);
299333
startKubernetesVM(vm);
300334
vm = userVmDao.findById(vm.getId());
301335
if (vm == null) {

plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,7 @@ private UserVm provisionKubernetesClusterMasterVm(final Network network, final S
277277
UserVm k8sMasterVM = null;
278278
k8sMasterVM = createKubernetesMaster(network, publicIpAddress);
279279
addKubernetesClusterVm(kubernetesCluster.getId(), k8sMasterVM.getId());
280+
resizeNodeVolume(k8sMasterVM);
280281
startKubernetesVM(k8sMasterVM);
281282
k8sMasterVM = userVmDao.findById(k8sMasterVM.getId());
282283
if (k8sMasterVM == null) {
@@ -296,6 +297,7 @@ private List<UserVm> provisionKubernetesClusterAdditionalMasterVms(final String
296297
UserVm vm = null;
297298
vm = createKubernetesAdditionalMaster(publicIpAddress, i);
298299
addKubernetesClusterVm(kubernetesCluster.getId(), vm.getId());
300+
resizeNodeVolume(vm);
299301
startKubernetesVM(vm);
300302
vm = userVmDao.findById(vm.getId());
301303
if (vm == null) {

server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -916,8 +916,15 @@ public VolumeVO resizeVolume(ResizeVolumeCmd cmd) throws ResourceAllocationExcep
916916
}
917917

918918
// if we are to use the existing disk offering
919+
ImageFormat format = null;
919920
if (newDiskOffering == null) {
920-
if (volume.getVolumeType().equals(Volume.Type.ROOT) && diskOffering.getDiskSize() > 0) {
921+
Long templateId = volume.getTemplateId();
922+
if (templateId != null) {
923+
VMTemplateVO template = _templateDao.findById(templateId);
924+
format = template.getFormat();
925+
}
926+
927+
if (volume.getVolumeType().equals(Volume.Type.ROOT) && diskOffering.getDiskSize() > 0 && format != null && format != ImageFormat.ISO) {
921928
throw new InvalidParameterValueException(
922929
"Failed to resize Root volume. The service offering of this Volume has been configured with a root disk size; "
923930
+ "on such case a Root Volume can only be resized when changing to another Service Offering with a Root disk size. "

server/src/main/java/com/cloud/vm/UserVmManagerImpl.java

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
import javax.xml.parsers.ParserConfigurationException;
5050

5151
import com.cloud.agent.api.to.deployasis.OVFPropertyTO;
52+
import com.cloud.api.query.dao.ServiceOfferingJoinDao;
53+
import com.cloud.api.query.vo.ServiceOfferingJoinVO;
5254
import com.cloud.deployasis.UserVmDeployAsIsDetailVO;
5355
import com.cloud.deployasis.dao.UserVmDeployAsIsDetailsDao;
5456
import com.cloud.exception.UnsupportedServiceException;
@@ -514,6 +516,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
514516
private UserVmDeployAsIsDetailsDao userVmDeployAsIsDetailsDao;
515517
@Inject
516518
private StorageManager storageMgr;
519+
@Inject
520+
private ServiceOfferingJoinDao serviceOfferingJoinDao;
517521

518522
private ScheduledExecutorService _executor = null;
519523
private ScheduledExecutorService _vmIpFetchExecutor = null;
@@ -5266,9 +5270,21 @@ public UserVm createVirtualMachine(DeployVMCmd cmd) throws InsufficientCapacityE
52665270
throw new InvalidParameterValueException("Unable to use template " + templateId);
52675271
}
52685272

5269-
// Bootmode and boottype are not supported on VMWare dpeloy-as-is templates (since 4.15)
5270-
if (template.isDeployAsIs() && (cmd.getBootMode() != null || cmd.getBootType() != null)) {
5271-
throw new InvalidParameterValueException("Boot type and boot mode are not supported on VMware, as we honour what is defined in the template.");
5273+
ServiceOfferingJoinVO svcOffering = serviceOfferingJoinDao.findById(serviceOfferingId);
5274+
5275+
if (template.isDeployAsIs()) {
5276+
if (svcOffering != null && svcOffering.getRootDiskSize() != null && svcOffering.getRootDiskSize() > 0) {
5277+
throw new InvalidParameterValueException("Failed to deploy Virtual Machine as a service offering with root disk size specified cannot be used with a deploy as-is template");
5278+
}
5279+
5280+
if (cmd.getDetails().get("rootdisksize") != null) {
5281+
throw new InvalidParameterValueException("Overriding root disk size isn't supported for VMs deployed from defploy as-is templates");
5282+
}
5283+
5284+
// Bootmode and boottype are not supported on VMWare dpeloy-as-is templates (since 4.15)
5285+
if ((cmd.getBootMode() != null || cmd.getBootType() != null)) {
5286+
throw new InvalidParameterValueException("Boot type and boot mode are not supported on VMware, as we honour what is defined in the template.");
5287+
}
52725288
}
52735289

52745290
Long diskOfferingId = cmd.getDiskOfferingId();

ui/public/locales/en.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2682,6 +2682,7 @@
26822682
"message.delete.vpn.customer.gateway": "Please confirm that you want to delete this VPN Customer Gateway",
26832683
"message.delete.vpn.gateway": "Please confirm that you want to delete this VPN Gateway",
26842684
"message.deleting.vm": "Deleting VM",
2685+
"message.deployasis": "Selected template is Deploy As-Is i.e., the VM is deployed by importing an OVA with vApps directly into vCenter. Root disk(s) resize is allowed only on stopped VMs for such templates.",
26852686
"message.desc.add.new.lb.sticky.rule": "Add new LB sticky rule",
26862687
"message.desc.advanced.zone": "For more sophisticated network topologies. This network model provides the most flexibility in defining guest networks and providing custom network offerings such as firewall, VPN, or load balancer support.",
26872688
"message.desc.basic.zone": "Provide a single network where each VM instance is assigned an IP directly from the network. Guest isolation can be provided through layer-3 means such as security groups (IP address source filtering).",

ui/src/views/compute/DeployVM.vue

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -105,7 +105,8 @@
105105
@update-template-iso="updateFieldValue" />
106106
<span>
107107
{{ $t('label.override.rootdisk.size') }}
108-
<a-switch @change="val => { this.showRootDiskSizeChanger = val }" style="margin-left: 10px;"/>
108+
<a-switch :disabled="template.deployasis" @change="val => { this.showRootDiskSizeChanger = val }" style="margin-left: 10px;"/>
109+
<div v-if="template.deployasis"> {{ this.$t('message.deployasis') }} </div>
109110
</span>
110111
<disk-size-selection
111112
v-show="showRootDiskSizeChanger"
@@ -183,6 +184,7 @@
183184
</a-form-item>
184185
<compute-offering-selection
185186
:compute-items="options.serviceOfferings"
187+
:selected-template="template"
186188
:row-count="rowCount.serviceOfferings"
187189
:zoneId="zoneId"
188190
:value="serviceOffering ? serviceOffering.id : ''"
@@ -543,6 +545,9 @@
543545
:options="keyboardSelectOptions"
544546
></a-select>
545547
</a-form-item>
548+
<a-form-item :label="$t('label.action.start.instance')">
549+
<a-switch v-decorator="['startvm', { initialValue: true }]" :checked="this.startvm" @change="checked => { this.startvm = checked }" />
550+
</a-form-item>
546551
</div>
547552
</template>
548553
</a-step>
@@ -663,6 +668,7 @@ export default {
663668
podId: null,
664669
clusterId: null,
665670
zoneSelected: false,
671+
startvm: true,
666672
vm: {
667673
name: null,
668674
zoneid: null,
@@ -1419,6 +1425,9 @@ export default {
14191425
if (values.hypervisor && values.hypervisor.length > 0) {
14201426
deployVmData.hypervisor = values.hypervisor
14211427
}
1428+
1429+
deployVmData.startvm = values.startvm
1430+
14221431
// step 3: select service offering
14231432
deployVmData.serviceofferingid = values.computeofferingid
14241433
if (this.serviceOffering && this.serviceOffering.iscustomized) {

ui/src/views/compute/wizard/ComputeOfferingSelection.vue

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,10 @@ export default {
6363
type: Array,
6464
default: () => []
6565
},
66+
selectedTemplate: {
67+
type: Object,
68+
default: () => {}
69+
},
6670
rowCount: {
6771
type: Number,
6872
default: () => 0
@@ -161,6 +165,9 @@ export default {
161165
(item.iscustomized === true && maxMemory < this.minimumMemory))) {
162166
disabled = true
163167
}
168+
if (this.selectedTemplate && this.selectedTemplate.hypervisor === 'VMware' && this.selectedTemplate.deployasis && item.rootdisksize) {
169+
disabled = true
170+
}
164171
return {
165172
key: item.id,
166173
name: item.name,
@@ -238,6 +245,9 @@ export default {
238245
return {
239246
on: {
240247
click: () => {
248+
if (record.disabled) {
249+
return
250+
}
241251
this.selectedRowKeys = [record.key]
242252
this.$emit('select-compute-item', record.key)
243253
}

0 commit comments

Comments
 (0)