From 97176690b85ff4c63ced2f37888252cd1322eef8 Mon Sep 17 00:00:00 2001 From: Pearl Dsilva Date: Mon, 29 Mar 2021 12:54:47 +0530 Subject: [PATCH 1/7] 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 --- .../vmware/resource/VmwareResource.java | 8 ++++- ...esClusterResourceModifierActionWorker.java | 34 +++++++++++++++++++ .../KubernetesClusterStartWorker.java | 2 ++ .../cloud/storage/VolumeApiServiceImpl.java | 9 ++++- .../java/com/cloud/vm/UserVmManagerImpl.java | 22 ++++++++++-- ui/public/locales/en.json | 1 + ui/src/views/compute/DeployVM.vue | 11 +++++- .../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 56d08a4e088..e59c7578b06 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 b715f09d7b8..c771cf34561 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 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 855c264d690..5855319ae67 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 0adeb836c7c..dc3bf04396d 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 d94c00c2391..737beb5274c 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 a00357755a1..476bd89e61a 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 b2a5fee8bcb..c4c20dee039 100644 --- a/ui/src/views/compute/DeployVM.vue +++ b/ui/src/views/compute/DeployVM.vue @@ -105,7 +105,8 @@ @update-template-iso="updateFieldValue" /> {{ $t('label.override.rootdisk.size') }} - + +
{{ this.$t('message.deployasis') }}
+ + + @@ -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 c372b821aef..f1a6128872e 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) } From 642878063d811853d707020b24901ff6721776ba Mon Sep 17 00:00:00 2001 From: Hoang Nguyen Date: Mon, 29 Mar 2021 17:49:26 +0700 Subject: [PATCH 2/7] ui: Auto-focus input, form (#4762) * autofocus into the first element (form/dialog) * add autofocus missing * add autofocus to missing elements --- ui/src/components/view/ListResourceTable.vue | 3 ++- ui/src/components/view/ResourceLimitTab.vue | 1 + ui/src/views/AutogenView.vue | 26 ++++++++++++++++--- ui/src/views/compute/AssignInstance.vue | 2 +- ui/src/views/compute/AttachIso.vue | 3 ++- ui/src/views/compute/ChangeAffinity.vue | 3 ++- .../views/compute/CreateKubernetesCluster.vue | 3 ++- ui/src/views/compute/CreateSSHKeyPair.vue | 3 ++- ui/src/views/compute/CreateSnapshotWizard.vue | 3 ++- ui/src/views/compute/DeployVM.vue | 2 ++ ui/src/views/compute/DestroyVM.vue | 3 ++- ui/src/views/compute/EditVM.vue | 3 ++- ui/src/views/compute/InstanceTab.vue | 10 ++++--- ui/src/views/compute/MigrateWizard.vue | 3 ++- .../views/compute/ScaleKubernetesCluster.vue | 3 ++- ui/src/views/compute/StartVirtualMachine.vue | 3 ++- .../compute/UpgradeKubernetesCluster.vue | 3 ++- ui/src/views/compute/backup/FormSchedule.vue | 3 ++- .../wizard/ComputeOfferingSelection.vue | 3 ++- .../views/compute/wizard/ComputeSelection.vue | 2 ++ .../compute/wizard/DiskSizeSelection.vue | 1 + .../compute/wizard/MultiDiskSelection.vue | 1 + .../compute/wizard/NetworkConfiguration.vue | 8 +++--- ui/src/views/iam/AddAccount.vue | 3 ++- ui/src/views/iam/AddLdapAccount.vue | 2 +- ui/src/views/iam/AddUser.vue | 3 ++- ui/src/views/iam/ChangeUserPassword.vue | 3 ++- ui/src/views/iam/ConfigureSamlSsoAuth.vue | 1 + ui/src/views/iam/CreateRole.vue | 3 ++- ui/src/views/iam/DomainActionForm.vue | 17 +++++++++++- ui/src/views/iam/EditUser.vue | 3 ++- ui/src/views/iam/ImportRole.vue | 3 ++- ui/src/views/iam/PermissionEditable.vue | 3 ++- .../image/AddKubernetesSupportedVersion.vue | 3 ++- ui/src/views/image/IsoZones.vue | 3 ++- ui/src/views/image/RegisterOrUploadIso.vue | 5 ++-- .../views/image/RegisterOrUploadTemplate.vue | 5 ++-- ui/src/views/image/TemplateZones.vue | 3 ++- .../UpdateKubernetesSupportedVersion.vue | 3 ++- .../image/UpdateTemplateIsoPermissions.vue | 6 ++++- ui/src/views/infra/AddPrimaryStorage.vue | 5 +++- ui/src/views/infra/AddSecondaryStorage.vue | 2 +- ui/src/views/infra/ClusterAdd.vue | 2 +- ui/src/views/infra/HostAdd.vue | 2 +- ui/src/views/infra/MigrateData.vue | 1 + ui/src/views/infra/PodAdd.vue | 3 ++- .../views/infra/network/DedicatedVLANTab.vue | 1 + .../views/infra/network/EditTrafficLabel.vue | 1 + .../infra/network/IpRangesTabManagement.vue | 1 + .../views/infra/network/IpRangesTabPublic.vue | 3 ++- .../infra/network/IpRangesTabStorage.vue | 1 + .../infra/network/ServiceProvidersTab.vue | 4 +++ .../network/providers/AddF5LoadBalancer.vue | 1 + .../providers/AddNetscalerLoadBalancer.vue | 1 + .../network/providers/AddNiciraNvpDevice.vue | 1 + .../network/providers/AddPaloAltoFirewall.vue | 1 + .../network/providers/AddSrxFirewall.vue | 1 + .../views/infra/routers/RouterHealthCheck.vue | 3 ++- .../infra/zone/AdvancedGuestTrafficForm.vue | 1 + .../views/infra/zone/IpAddressRangeForm.vue | 1 + ui/src/views/infra/zone/StaticInputsForm.vue | 4 +++ .../ZoneWizardPhysicalNetworkSetupStep.vue | 2 +- .../infra/zone/ZoneWizardZoneDetailsStep.vue | 1 + .../infra/zone/ZoneWizardZoneTypeStep.vue | 1 + ui/src/views/network/AclListRulesTab.vue | 6 +++-- .../network/CreateIsolatedNetworkForm.vue | 3 ++- ui/src/views/network/CreateL2NetworkForm.vue | 3 ++- .../views/network/CreateSharedNetworkForm.vue | 3 ++- ui/src/views/network/CreateVlanIpRange.vue | 1 + ui/src/views/network/CreateVpc.vue | 3 ++- .../network/CreateVpnCustomerGateway.vue | 3 ++- ui/src/views/network/EgressRulesTab.vue | 2 +- ui/src/views/network/EnableStaticNat.vue | 6 ++++- ui/src/views/network/FirewallRules.vue | 4 +-- .../network/IngressEgressRuleConfigure.vue | 10 +++++-- .../views/network/InternalLBAssignVmForm.vue | 6 ++++- ui/src/views/network/IpAddressesTab.vue | 2 ++ ui/src/views/network/LoadBalancing.vue | 12 ++++++--- ui/src/views/network/PortForwarding.vue | 5 +++- ui/src/views/network/StaticRoutesTab.vue | 6 +++-- ui/src/views/network/VpcTab.vue | 8 +++--- ui/src/views/network/VpcTiersTab.vue | 4 ++- ui/src/views/offering/AddComputeOffering.vue | 1 + ui/src/views/offering/AddDiskOffering.vue | 1 + ui/src/views/offering/AddNetworkOffering.vue | 1 + ui/src/views/offering/AddVpcOffering.vue | 1 + .../views/offering/ImportBackupOffering.vue | 1 + .../views/offering/UpdateOfferingAccess.vue | 2 ++ .../plugins/quota/EditTariffValueWizard.vue | 1 + .../project/AddAccountOrUserToProject.vue | 6 +++-- .../views/project/InvitationTokenTemplate.vue | 1 + ui/src/views/project/InvitationsTemplate.vue | 3 ++- ui/src/views/project/iam/ProjectRoleTab.vue | 8 +++--- ui/src/views/storage/AttachVolume.vue | 1 + .../storage/CreateSnapshotFromVMSnapshot.vue | 1 + ui/src/views/storage/CreateVolume.vue | 3 ++- ui/src/views/storage/FormSchedule.vue | 3 ++- ui/src/views/storage/MigrateVolume.vue | 5 +++- ui/src/views/storage/ResizeVolume.vue | 4 ++- .../storage/RestoreAttachBackupVolume.vue | 3 ++- ui/src/views/storage/TakeSnapshot.vue | 3 ++- ui/src/views/storage/UploadLocalVolume.vue | 3 ++- 102 files changed, 257 insertions(+), 90 deletions(-) diff --git a/ui/src/components/view/ListResourceTable.vue b/ui/src/components/view/ListResourceTable.vue index c498d16e583..dea774c63e5 100644 --- a/ui/src/components/view/ListResourceTable.vue +++ b/ui/src/components/view/ListResourceTable.vue @@ -22,7 +22,8 @@ style="width: 25vw;float: right;margin-bottom: 10px; z-index: 8" :placeholder="$t('label.search')" v-model="filter" - @search="handleSearch" /> + @search="handleSearch" + autoFocus />
diff --git a/ui/src/views/compute/CreateKubernetesCluster.vue b/ui/src/views/compute/CreateKubernetesCluster.vue index 9759a5d9055..660505f22b8 100644 --- a/ui/src/views/compute/CreateKubernetesCluster.vue +++ b/ui/src/views/compute/CreateKubernetesCluster.vue @@ -33,7 +33,8 @@ v-decorator="['name', { rules: [{ required: true, message: $t('message.error.kubecluster.name') }] }]" - :placeholder="apiParams.name.description"/> + :placeholder="apiParams.name.description" + autoFocus /> diff --git a/ui/src/views/compute/CreateSSHKeyPair.vue b/ui/src/views/compute/CreateSSHKeyPair.vue index ba58a0ee79d..62a2bdf475c 100644 --- a/ui/src/views/compute/CreateSSHKeyPair.vue +++ b/ui/src/views/compute/CreateSSHKeyPair.vue @@ -28,7 +28,8 @@ v-decorator="['name', { rules: [{ required: true, message: $t('message.error.name') }] }]" - :placeholder="apiParams.name.description"/> + :placeholder="apiParams.name.description" + autoFocus /> + :placeholder="apiParams.volumeid.description" + autoFocus> diff --git a/ui/src/views/compute/DeployVM.vue b/ui/src/views/compute/DeployVM.vue index c4c20dee039..ae8593a9ca3 100644 --- a/ui/src/views/compute/DeployVM.vue +++ b/ui/src/views/compute/DeployVM.vue @@ -41,6 +41,7 @@ :options="zoneSelectOptions" @change="onSelectZoneId" :loading="loading.zones" + autoFocus > diff --git a/ui/src/views/compute/DestroyVM.vue b/ui/src/views/compute/DestroyVM.vue index 638097d2947..f0dedee059d 100644 --- a/ui/src/views/compute/DestroyVM.vue +++ b/ui/src/views/compute/DestroyVM.vue @@ -44,7 +44,8 @@ v-decorator="['volumeids']" :placeholder="$t('label.delete.volumes')" mode="multiple" - :loading="loading"> + :loading="loading" + :autoFocus="$store.getters.userInfo.roletype !== 'Admin' && !$store.getters.features.allowuserexpungerecovervm"> {{ volume.name }} diff --git a/ui/src/views/compute/EditVM.vue b/ui/src/views/compute/EditVM.vue index ece9061f19e..c9f342ba392 100644 --- a/ui/src/views/compute/EditVM.vue +++ b/ui/src/views/compute/EditVM.vue @@ -30,7 +30,8 @@ + v-decorator="['name', { initialValue: resource.name || '' }]" + autoFocus /> diff --git a/ui/src/views/compute/InstanceTab.vue b/ui/src/views/compute/InstanceTab.vue index fd11d762c44..29a5cdedebd 100644 --- a/ui/src/views/compute/InstanceTab.vue +++ b/ui/src/views/compute/InstanceTab.vue @@ -165,7 +165,7 @@ {{ $t('message.network.addvm.desc') }} @@ -218,7 +220,7 @@ {{ $t('message.network.secondaryip') }}

- +
{{ $t('label.add.secondary.ip') }} {{ $t('label.close') }} diff --git a/ui/src/views/compute/MigrateWizard.vue b/ui/src/views/compute/MigrateWizard.vue index 9f050cda20f..f0afac93c3b 100644 --- a/ui/src/views/compute/MigrateWizard.vue +++ b/ui/src/views/compute/MigrateWizard.vue @@ -21,7 +21,8 @@ :placeholder="$t('label.search')" v-model="searchQuery" style="margin-bottom: 10px;" - @search="fetchData" /> + @search="fetchData" + autoFocus /> + :placeholder="apiParams.size.description" + autoFocus /> diff --git a/ui/src/views/compute/StartVirtualMachine.vue b/ui/src/views/compute/StartVirtualMachine.vue index 4fec9913cc9..5be132ac808 100644 --- a/ui/src/views/compute/StartVirtualMachine.vue +++ b/ui/src/views/compute/StartVirtualMachine.vue @@ -43,7 +43,8 @@ }" :loading="podsLoading" :placeholder="apiParams.podid.description" - @change="handlePodChange"> + @change="handlePodChange" + :autoFocus="this.$store.getters.userInfo.roletype === 'Admin'"> {{ pod.name }} diff --git a/ui/src/views/compute/UpgradeKubernetesCluster.vue b/ui/src/views/compute/UpgradeKubernetesCluster.vue index 18b51b21ca1..9d94e59919a 100644 --- a/ui/src/views/compute/UpgradeKubernetesCluster.vue +++ b/ui/src/views/compute/UpgradeKubernetesCluster.vue @@ -44,7 +44,8 @@ return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0 }" :loading="kubernetesVersionLoading" - :placeholder="apiParams.kubernetesversionid.description"> + :placeholder="apiParams.kubernetesversionid.description" + autoFocus > {{ opt.name || opt.description }} diff --git a/ui/src/views/compute/backup/FormSchedule.vue b/ui/src/views/compute/backup/FormSchedule.vue index c30b3e24158..e61efc8dfbb 100644 --- a/ui/src/views/compute/backup/FormSchedule.vue +++ b/ui/src/views/compute/backup/FormSchedule.vue @@ -61,7 +61,8 @@ rules: [{required: true, message: $t('message.error.required.input')}] }]" :min="1" - :max="59"/> + :max="59" + autoFocus /> diff --git a/ui/src/views/compute/wizard/ComputeOfferingSelection.vue b/ui/src/views/compute/wizard/ComputeOfferingSelection.vue index f1a6128872e..117a7c062cd 100644 --- a/ui/src/views/compute/wizard/ComputeOfferingSelection.vue +++ b/ui/src/views/compute/wizard/ComputeOfferingSelection.vue @@ -21,7 +21,8 @@ style="width: 25vw;float: right;margin-bottom: 10px; z-index: 8" :placeholder="$t('label.search')" v-model="filter" - @search="handleSearch" /> + @search="handleSearch" + autoFocus /> @@ -48,6 +49,7 @@ :validate-status="errors.cpuspeed.status" :help="errors.cpuspeed.message"> diff --git a/ui/src/views/compute/wizard/DiskSizeSelection.vue b/ui/src/views/compute/wizard/DiskSizeSelection.vue index dcea64026f2..57e8e89b7f4 100644 --- a/ui/src/views/compute/wizard/DiskSizeSelection.vue +++ b/ui/src/views/compute/wizard/DiskSizeSelection.vue @@ -23,6 +23,7 @@ diff --git a/ui/src/views/compute/wizard/MultiDiskSelection.vue b/ui/src/views/compute/wizard/MultiDiskSelection.vue index 998fdbe7d3b..630d3b4652b 100644 --- a/ui/src/views/compute/wizard/MultiDiskSelection.vue +++ b/ui/src/views/compute/wizard/MultiDiskSelection.vue @@ -28,6 +28,7 @@ diff --git a/ui/src/views/compute/wizard/NetworkConfiguration.vue b/ui/src/views/compute/wizard/NetworkConfiguration.vue index 7bd17f4b69b..5a9c7ed0d1d 100644 --- a/ui/src/views/compute/wizard/NetworkConfiguration.vue +++ b/ui/src/views/compute/wizard/NetworkConfiguration.vue @@ -30,9 +30,10 @@
{{ text }}
{{ $t('label.cidr') + ': ' + record.cidr }} -