This is an automated email from the ASF dual-hosted git repository.
rohit pushed a commit to branch 4.15
in repository https://gitbox.apache.org/repos/asf/cloudstack.git
The following commit(s) were added to refs/heads/4.15 by this push:
new 9717669 server: Fix issue with volume resize on VMWare (deploy as-is
templates) (#4829)
9717669 is described below
commit 97176690b85ff4c63ced2f37888252cd1322eef8
Author: Pearl Dsilva <[email protected]>
AuthorDate: Mon Mar 29 12:54:47 2021 +0530
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 <[email protected]>
---
.../hypervisor/vmware/resource/VmwareResource.java | 8 ++++-
...ernetesClusterResourceModifierActionWorker.java | 34 ++++++++++++++++++++++
.../KubernetesClusterStartWorker.java | 2 ++
.../com/cloud/storage/VolumeApiServiceImpl.java | 9 +++++-
.../main/java/com/cloud/vm/UserVmManagerImpl.java | 22 ++++++++++++--
ui/public/locales/en.json | 1 +
ui/src/views/compute/DeployVM.vue | 11 ++++++-
.../compute/wizard/ComputeOfferingSelection.vue | 10 +++++++
8 files changed, 91 insertions(+), 6 deletions(-)
diff --git
a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
index 56d08a4..e59c757 100644
---
a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
+++
b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java
@@ -2071,7 +2071,13 @@ public class VmwareResource implements
StoragePoolResource, ServerResource, Vmwa
// Setup ROOT/DATA disk devices
//
for (DiskTO vol : sortedDisks) {
- if (vol.getType() == Volume.Type.ISO || deployAsIs &&
vol.getType() == Volume.Type.ROOT) {
+ if (vol.getType() == Volume.Type.ISO) {
+ continue;
+ }
+
+ if (deployAsIs && vol.getType() == Volume.Type.ROOT) {
+ rootDiskTO = vol;
+ resizeRootDiskOnVMStart(vmMo, rootDiskTO, hyperHost,
context);
continue;
}
diff --git
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java
index b715f09..c771cf3 100644
---
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java
+++
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterResourceModifierActionWorker.java
@@ -31,6 +31,7 @@ import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.command.user.firewall.CreateFirewallRuleCmd;
import org.apache.cloudstack.api.command.user.vm.StartVMCmd;
+import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Level;
@@ -70,6 +71,10 @@ import com.cloud.network.rules.RulesService;
import com.cloud.network.rules.dao.PortForwardingRulesDao;
import com.cloud.offering.ServiceOffering;
import com.cloud.resource.ResourceManager;
+import com.cloud.storage.Volume;
+import com.cloud.storage.VolumeApiService;
+import com.cloud.storage.VolumeVO;
+import com.cloud.storage.dao.VolumeDao;
import com.cloud.user.Account;
import com.cloud.user.SSHKeyPairVO;
import com.cloud.uservm.UserVm;
@@ -118,6 +123,10 @@ public class KubernetesClusterResourceModifierActionWorker
extends KubernetesClu
protected VMInstanceDao vmInstanceDao;
@Inject
protected UserVmManager userVmManager;
+ @Inject
+ protected VolumeApiService volumeService;
+ @Inject
+ protected VolumeDao volumeDao;
protected String kubernetesClusterNodeNamePrefix;
@@ -268,6 +277,29 @@ public class KubernetesClusterResourceModifierActionWorker
extends KubernetesClu
return plan(kubernetesCluster.getTotalNodeCount(), zone, offering);
}
+ protected void resizeNodeVolume(final UserVm vm) throws
ManagementServerException {
+ try {
+ if (vm.getHypervisorType() == Hypervisor.HypervisorType.VMware &&
templateDao.findById(vm.getTemplateId()).isDeployAsIs()) {
+ List<VolumeVO> vmVols = volumeDao.findByInstance(vm.getId());
+ for (VolumeVO volumeVO : vmVols) {
+ if (volumeVO.getVolumeType() == Volume.Type.ROOT) {
+ ResizeVolumeCmd resizeVolumeCmd = new
ResizeVolumeCmd();
+ resizeVolumeCmd =
ComponentContext.inject(resizeVolumeCmd);
+ Field f =
resizeVolumeCmd.getClass().getDeclaredField("size");
+ Field f1 =
resizeVolumeCmd.getClass().getDeclaredField("id");
+ f.setAccessible(true);
+ f1.setAccessible(true);
+ f1.set(resizeVolumeCmd, volumeVO.getId());
+ f.set(resizeVolumeCmd,
kubernetesCluster.getNodeRootDiskSize());
+ volumeService.resizeVolume(resizeVolumeCmd);
+ }
+ }
+ }
+ } catch (IllegalAccessException | NoSuchFieldException e) {
+ throw new ManagementServerException(String.format("Failed to
resize volume of VM in the Kubernetes cluster : %s",
kubernetesCluster.getName()), e);
+ }
+ }
+
protected void startKubernetesVM(final UserVm vm) throws
ManagementServerException {
try {
StartVMCmd startVm = new StartVMCmd();
@@ -275,6 +307,7 @@ public class KubernetesClusterResourceModifierActionWorker
extends KubernetesClu
Field f = startVm.getClass().getDeclaredField("id");
f.setAccessible(true);
f.set(startVm, vm.getId());
+ resizeNodeVolume(vm);
userVmService.startVirtualMachine(startVm);
if (LOGGER.isInfoEnabled()) {
LOGGER.info(String.format("Started VM : %s in the Kubernetes
cluster : %s", vm.getDisplayName(), kubernetesCluster.getName()));
@@ -296,6 +329,7 @@ public class KubernetesClusterResourceModifierActionWorker
extends KubernetesClu
for (int i = offset + 1; i <= nodeCount; i++) {
UserVm vm = createKubernetesNode(publicIpAddress, i);
addKubernetesClusterVm(kubernetesCluster.getId(), vm.getId());
+ resizeNodeVolume(vm);
startKubernetesVM(vm);
vm = userVmDao.findById(vm.getId());
if (vm == null) {
diff --git
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java
index 855c264..5855319 100644
---
a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java
+++
b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/cluster/actionworkers/KubernetesClusterStartWorker.java
@@ -277,6 +277,7 @@ public class KubernetesClusterStartWorker extends
KubernetesClusterResourceModif
UserVm k8sMasterVM = null;
k8sMasterVM = createKubernetesMaster(network, publicIpAddress);
addKubernetesClusterVm(kubernetesCluster.getId(), k8sMasterVM.getId());
+ resizeNodeVolume(k8sMasterVM);
startKubernetesVM(k8sMasterVM);
k8sMasterVM = userVmDao.findById(k8sMasterVM.getId());
if (k8sMasterVM == null) {
@@ -296,6 +297,7 @@ public class KubernetesClusterStartWorker extends
KubernetesClusterResourceModif
UserVm vm = null;
vm = createKubernetesAdditionalMaster(publicIpAddress, i);
addKubernetesClusterVm(kubernetesCluster.getId(), vm.getId());
+ resizeNodeVolume(vm);
startKubernetesVM(vm);
vm = userVmDao.findById(vm.getId());
if (vm == null) {
diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
index 0adeb83..dc3bf04 100644
--- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
@@ -916,8 +916,15 @@ public class VolumeApiServiceImpl extends ManagerBase
implements VolumeApiServic
}
// if we are to use the existing disk offering
+ ImageFormat format = null;
if (newDiskOffering == null) {
- if (volume.getVolumeType().equals(Volume.Type.ROOT) &&
diskOffering.getDiskSize() > 0) {
+ Long templateId = volume.getTemplateId();
+ if (templateId != null) {
+ VMTemplateVO template = _templateDao.findById(templateId);
+ format = template.getFormat();
+ }
+
+ if (volume.getVolumeType().equals(Volume.Type.ROOT) &&
diskOffering.getDiskSize() > 0 && format != null && format != ImageFormat.ISO) {
throw new InvalidParameterValueException(
"Failed to resize Root volume. The service offering of
this Volume has been configured with a root disk size; "
+ "on such case a Root Volume can only be
resized when changing to another Service Offering with a Root disk size. "
diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
index d94c00c..737beb5 100644
--- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
@@ -49,6 +49,8 @@ import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import com.cloud.agent.api.to.deployasis.OVFPropertyTO;
+import com.cloud.api.query.dao.ServiceOfferingJoinDao;
+import com.cloud.api.query.vo.ServiceOfferingJoinVO;
import com.cloud.deployasis.UserVmDeployAsIsDetailVO;
import com.cloud.deployasis.dao.UserVmDeployAsIsDetailsDao;
import com.cloud.exception.UnsupportedServiceException;
@@ -514,6 +516,8 @@ public class UserVmManagerImpl extends ManagerBase
implements UserVmManager, Vir
private UserVmDeployAsIsDetailsDao userVmDeployAsIsDetailsDao;
@Inject
private StorageManager storageMgr;
+ @Inject
+ private ServiceOfferingJoinDao serviceOfferingJoinDao;
private ScheduledExecutorService _executor = null;
private ScheduledExecutorService _vmIpFetchExecutor = null;
@@ -5266,9 +5270,21 @@ public class UserVmManagerImpl extends ManagerBase
implements UserVmManager, Vir
throw new InvalidParameterValueException("Unable to use template "
+ templateId);
}
- // Bootmode and boottype are not supported on VMWare dpeloy-as-is
templates (since 4.15)
- if (template.isDeployAsIs() && (cmd.getBootMode() != null ||
cmd.getBootType() != null)) {
- throw new InvalidParameterValueException("Boot type and boot mode
are not supported on VMware, as we honour what is defined in the template.");
+ ServiceOfferingJoinVO svcOffering =
serviceOfferingJoinDao.findById(serviceOfferingId);
+
+ if (template.isDeployAsIs()) {
+ if (svcOffering != null && svcOffering.getRootDiskSize() != null
&& svcOffering.getRootDiskSize() > 0) {
+ 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");
+ }
+
+ if (cmd.getDetails().get("rootdisksize") != null) {
+ throw new InvalidParameterValueException("Overriding root disk
size isn't supported for VMs deployed from defploy as-is templates");
+ }
+
+ // Bootmode and boottype are not supported on VMWare dpeloy-as-is
templates (since 4.15)
+ if ((cmd.getBootMode() != null || cmd.getBootType() != null)) {
+ throw new InvalidParameterValueException("Boot type and boot
mode are not supported on VMware, as we honour what is defined in the
template.");
+ }
}
Long diskOfferingId = cmd.getDiskOfferingId();
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index a003577..476bd89e 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -2682,6 +2682,7 @@
"message.delete.vpn.customer.gateway": "Please confirm that you want to delete
this VPN Customer Gateway",
"message.delete.vpn.gateway": "Please confirm that you want to delete this VPN
Gateway",
"message.deleting.vm": "Deleting VM",
+"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.",
"message.desc.add.new.lb.sticky.rule": "Add new LB sticky rule",
"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.",
"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).",
diff --git a/ui/src/views/compute/DeployVM.vue
b/ui/src/views/compute/DeployVM.vue
index b2a5fee..c4c20de 100644
--- a/ui/src/views/compute/DeployVM.vue
+++ b/ui/src/views/compute/DeployVM.vue
@@ -105,7 +105,8 @@
@update-template-iso="updateFieldValue" />
<span>
{{ $t('label.override.rootdisk.size') }}
- <a-switch @change="val => {
this.showRootDiskSizeChanger = val }" style="margin-left: 10px;"/>
+ <a-switch :disabled="template.deployasis"
@change="val => { this.showRootDiskSizeChanger = val }" style="margin-left:
10px;"/>
+ <div v-if="template.deployasis"> {{
this.$t('message.deployasis') }} </div>
</span>
<disk-size-selection
v-show="showRootDiskSizeChanger"
@@ -183,6 +184,7 @@
</a-form-item>
<compute-offering-selection
:compute-items="options.serviceOfferings"
+ :selected-template="template"
:row-count="rowCount.serviceOfferings"
:zoneId="zoneId"
:value="serviceOffering ? serviceOffering.id : ''"
@@ -543,6 +545,9 @@
:options="keyboardSelectOptions"
></a-select>
</a-form-item>
+ <a-form-item :label="$t('label.action.start.instance')">
+ <a-switch v-decorator="['startvm', { initialValue: true
}]" :checked="this.startvm" @change="checked => { this.startvm = checked }" />
+ </a-form-item>
</div>
</template>
</a-step>
@@ -663,6 +668,7 @@ export default {
podId: null,
clusterId: null,
zoneSelected: false,
+ startvm: true,
vm: {
name: null,
zoneid: null,
@@ -1419,6 +1425,9 @@ export default {
if (values.hypervisor && values.hypervisor.length > 0) {
deployVmData.hypervisor = values.hypervisor
}
+
+ deployVmData.startvm = values.startvm
+
// step 3: select service offering
deployVmData.serviceofferingid = values.computeofferingid
if (this.serviceOffering && this.serviceOffering.iscustomized) {
diff --git a/ui/src/views/compute/wizard/ComputeOfferingSelection.vue
b/ui/src/views/compute/wizard/ComputeOfferingSelection.vue
index c372b82..f1a6128 100644
--- a/ui/src/views/compute/wizard/ComputeOfferingSelection.vue
+++ b/ui/src/views/compute/wizard/ComputeOfferingSelection.vue
@@ -63,6 +63,10 @@ export default {
type: Array,
default: () => []
},
+ selectedTemplate: {
+ type: Object,
+ default: () => {}
+ },
rowCount: {
type: Number,
default: () => 0
@@ -161,6 +165,9 @@ export default {
(item.iscustomized === true && maxMemory < this.minimumMemory))) {
disabled = true
}
+ if (this.selectedTemplate && this.selectedTemplate.hypervisor ===
'VMware' && this.selectedTemplate.deployasis && item.rootdisksize) {
+ disabled = true
+ }
return {
key: item.id,
name: item.name,
@@ -238,6 +245,9 @@ export default {
return {
on: {
click: () => {
+ if (record.disabled) {
+ return
+ }
this.selectedRowKeys = [record.key]
this.$emit('select-compute-item', record.key)
}