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)
           }

Reply via email to