diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiServerService.java b/api/src/main/java/org/apache/cloudstack/api/ApiServerService.java
index 1f6d3d50375..54fda7e36b8 100644
--- a/api/src/main/java/org/apache/cloudstack/api/ApiServerService.java
+++ b/api/src/main/java/org/apache/cloudstack/api/ApiServerService.java
@@ -42,6 +42,4 @@ public interface ApiServerService {
public String handleRequest(Map params, String responseType, StringBuilder auditTrailSb) throws ServerApiException;
public Class> getCmdClass(String cmdName);
-
- public boolean isValidApiName(String apiName);
}
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/ImportRoleCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/ImportRoleCmd.java
index 3afac9fbea0..c5d9c3f99e6 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/ImportRoleCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/acl/ImportRoleCmd.java
@@ -94,9 +94,6 @@ public class ImportRoleCmd extends RoleCmd {
if (Strings.isNullOrEmpty(rule)) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Empty rule provided in rules param");
}
- if (!rule.contains("*") && !_apiServer.isValidApiName(rule)) {
- throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Invalid api name: " + rule + " provided in rules param");
- }
ruleDetails.put(ApiConstants.RULE, new Rule(rule));
String permission = detail.get(ApiConstants.PERMISSION);
diff --git a/engine/storage/src/main/java/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java b/engine/storage/src/main/java/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java
index ac2c93567c3..08a3a3924d7 100644
--- a/engine/storage/src/main/java/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java
+++ b/engine/storage/src/main/java/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java
@@ -173,6 +173,7 @@ public class PrimaryDataStoreHelper {
public DataStore attachZone(DataStore store) {
StoragePoolVO pool = this.dataStoreDao.findById(store.getId());
+ storageMgr.createCapacityEntry(pool.getId());
pool.setScope(ScopeType.ZONE);
pool.setStatus(StoragePoolStatus.Up);
this.dataStoreDao.update(pool.getId(), pool);
@@ -181,6 +182,7 @@ public class PrimaryDataStoreHelper {
public DataStore attachZone(DataStore store, HypervisorType hypervisor) {
StoragePoolVO pool = this.dataStoreDao.findById(store.getId());
+ storageMgr.createCapacityEntry(pool.getId());
pool.setScope(ScopeType.ZONE);
pool.setHypervisor(hypervisor);
pool.setStatus(StoragePoolStatus.Up);
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 fb2af6f57a5..42a1d30e9c3 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
@@ -2072,7 +2072,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/api/ApiServer.java b/server/src/main/java/com/cloud/api/ApiServer.java
index 586d80b4745..cf0891fb606 100644
--- a/server/src/main/java/com/cloud/api/ApiServer.java
+++ b/server/src/main/java/com/cloud/api/ApiServer.java
@@ -1208,17 +1208,6 @@ public class ApiServer extends ManagerBase implements HttpRequestHandler, ApiSer
}
}
- @Override
- public boolean isValidApiName(String apiName) {
- if (apiName == null || apiName.isEmpty())
- return false;
-
- if (!s_apiNameCmdClassMap.containsKey(apiName))
- return false;
-
- return true;
- }
-
// FIXME: rather than isError, we might was to pass in the status code to give more flexibility
private void writeResponse(final HttpResponse resp, final String responseText, final int statusCode, final String responseType, final String reasonPhrase) {
try {
diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
index 6f362a7720f..a7be48f074e 100644
--- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
@@ -962,8 +962,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 a3f818ad626..09b15bf5a81 100644
--- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
+++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java
@@ -145,6 +145,8 @@ import com.cloud.agent.api.to.deployasis.OVFPropertyTO;
import com.cloud.agent.manager.Commands;
import com.cloud.alert.AlertManager;
import com.cloud.api.ApiDBUtils;
+import com.cloud.api.query.dao.ServiceOfferingJoinDao;
+import com.cloud.api.query.vo.ServiceOfferingJoinVO;
import com.cloud.capacity.Capacity;
import com.cloud.capacity.CapacityManager;
import com.cloud.configuration.Config;
@@ -512,7 +514,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
@Inject
private UserVmDeployAsIsDetailsDao userVmDeployAsIsDetailsDao;
@Inject
- private StorageManager _storageManager;
+ private StorageManager storageManager;
+ @Inject
+ private ServiceOfferingJoinDao serviceOfferingJoinDao;
private ScheduledExecutorService _executor = null;
private ScheduledExecutorService _vmIpFetchExecutor = null;
@@ -2051,7 +2055,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
if (poolType == StoragePoolType.PowerFlex) {
// Get volume stats from the pool directly instead of sending cmd to host
// Added support for ScaleIO/PowerFlex pool only
- answer = _storageManager.getVolumeStats(storagePool, cmd);
+ answer = storageManager.getVolumeStats(storagePool, cmd);
} else {
if (timeout > 0) {
cmd.setWait(timeout/1000);
@@ -5313,9 +5317,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();
@@ -6349,7 +6365,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
HypervisorType hypervisorType = _volsDao.getHypervisorType(volume.getId());
if (hypervisorType.equals(HypervisorType.VMware)) {
try {
- boolean isStoragePoolStoragepolicyComplaince = _storageManager.isStoragePoolComplaintWithStoragePolicy(Arrays.asList(volume), pool);
+ boolean isStoragePoolStoragepolicyComplaince = storageManager.isStoragePoolComplaintWithStoragePolicy(Arrays.asList(volume), pool);
if (!isStoragePoolStoragepolicyComplaince) {
throw new CloudRuntimeException(String.format("Storage pool %s is not storage policy compliance with the volume %s", pool.getUuid(), volume.getUuid()));
}
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index 80c3319f12d..28e99b0c141 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -2692,6 +2692,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/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 />
-
- {{ $t('label.submit') }}
-
+
+
+ {{ $t('label.cancel') }}
+
+
+ {{ $t('label.submit') }}
+
+
@@ -183,6 +188,9 @@ export default {
this.selectedAccount = null
this.fetchNetworks()
},
+ closeAction () {
+ this.$emit('close-action')
+ },
submitData () {
let variableKey = ''
let variableValue = ''
@@ -255,6 +263,10 @@ export default {
.submit-btn {
margin-top: 10px;
align-self: flex-end;
+
+ button {
+ margin-left: 10px;
+ }
}
.required {
diff --git a/ui/src/views/compute/AttachIso.vue b/ui/src/views/compute/AttachIso.vue
index 947201171df..3c62c4cea21 100644
--- a/ui/src/views/compute/AttachIso.vue
+++ b/ui/src/views/compute/AttachIso.vue
@@ -26,7 +26,8 @@
v-decorator="['id', {
initialValue: this.selectedIso,
rules: [{ required: true, message: `${this.$t('label.required')}`}]
- }]" >
+ }]"
+ autoFocus>
{{ iso.displaytext || iso.name }}
diff --git a/ui/src/views/compute/ChangeAffinity.vue b/ui/src/views/compute/ChangeAffinity.vue
index 9482ccf15a7..d6bdc1b9cd1 100644
--- a/ui/src/views/compute/ChangeAffinity.vue
+++ b/ui/src/views/compute/ChangeAffinity.vue
@@ -29,7 +29,8 @@
style="margin-bottom: 10px;"
:placeholder="$t('label.search')"
v-model="filter"
- @search="handleSearch" />
+ @search="handleSearch"
+ autoFocus />
@@ -663,6 +670,7 @@ export default {
podId: null,
clusterId: null,
zoneSelected: false,
+ startvm: true,
vm: {
name: null,
zoneid: null,
@@ -1419,6 +1427,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/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 f34a778fe1c..3b28972ae5c 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 c372b821aef..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 />
[]
},
+ selectedTemplate: {
+ type: Object,
+ default: () => {}
+ },
rowCount: {
type: Number,
default: () => 0
@@ -161,6 +166,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 +246,9 @@ export default {
return {
on: {
click: () => {
+ if (record.disabled) {
+ return
+ }
this.selectedRowKeys = [record.key]
this.$emit('select-compute-item', record.key)
}
diff --git a/ui/src/views/compute/wizard/ComputeSelection.vue b/ui/src/views/compute/wizard/ComputeSelection.vue
index 46a9f73dd9c..df178a8922d 100644
--- a/ui/src/views/compute/wizard/ComputeSelection.vue
+++ b/ui/src/views/compute/wizard/ComputeSelection.vue
@@ -35,6 +35,7 @@
updateComputeCpuNumber($event)"
/>
@@ -48,6 +49,7 @@
:validate-status="errors.cpuspeed.status"
:help="errors.cpuspeed.message">
updateComputeCpuSpeed($event)"
/>
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 @@
updateDiskSize($event)"
/>
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 }}
-
-
+
+
+
+ :placeholder="apiParams.roleid.description"
+ autoFocus>
{{ role.name + ' (' + role.type + ')' }}
diff --git a/ui/src/views/iam/AddLdapAccount.vue b/ui/src/views/iam/AddLdapAccount.vue
index 50806d18f10..4152ebcb489 100644
--- a/ui/src/views/iam/AddLdapAccount.vue
+++ b/ui/src/views/iam/AddLdapAccount.vue
@@ -50,7 +50,7 @@
@submit="handleSubmit"
layout="vertical" >
-
+
{{ opt.name }}
diff --git a/ui/src/views/iam/AddUser.vue b/ui/src/views/iam/AddUser.vue
index d7121ea9cbb..edffb4fb424 100644
--- a/ui/src/views/iam/AddUser.vue
+++ b/ui/src/views/iam/AddUser.vue
@@ -30,7 +30,8 @@
v-decorator="['username', {
rules: [{ required: true, message: $t('message.error.required.input') }]
}]"
- :placeholder="apiParams.username.description" />
+ :placeholder="apiParams.username.description"
+ autoFocus/>
diff --git a/ui/src/views/iam/ChangeUserPassword.vue b/ui/src/views/iam/ChangeUserPassword.vue
index 698d2fb5f45..27fc269bf38 100644
--- a/ui/src/views/iam/ChangeUserPassword.vue
+++ b/ui/src/views/iam/ChangeUserPassword.vue
@@ -33,7 +33,8 @@
v-decorator="['currentpassword', {
rules: [{ required: true, message: $t('message.error.current.password') }]
}]"
- :placeholder="$t('message.error.current.password')"/>
+ :placeholder="$t('message.error.current.password')"
+ autoFocus />
diff --git a/ui/src/views/iam/ConfigureSamlSsoAuth.vue b/ui/src/views/iam/ConfigureSamlSsoAuth.vue
index 1e21a0d17a9..79b0f8814d6 100644
--- a/ui/src/views/iam/ConfigureSamlSsoAuth.vue
+++ b/ui/src/views/iam/ConfigureSamlSsoAuth.vue
@@ -25,6 +25,7 @@
}]"
:checked="isSamlEnabled"
@change="val => { isSamlEnabled = val }"
+ autoFocus
/>
diff --git a/ui/src/views/iam/CreateRole.vue b/ui/src/views/iam/CreateRole.vue
index 6e4bb35f83c..fc034cbe696 100644
--- a/ui/src/views/iam/CreateRole.vue
+++ b/ui/src/views/iam/CreateRole.vue
@@ -33,7 +33,8 @@
v-decorator="['name', {
rules: [{ required: true, message: $t('message.error.required.input') }]
}]"
- :placeholder="createRoleApiParams.name.description" />
+ :placeholder="createRoleApiParams.name.description"
+ autoFocus />
diff --git a/ui/src/views/iam/DomainActionForm.vue b/ui/src/views/iam/DomainActionForm.vue
index 0f01f5945c1..54604992fe9 100644
--- a/ui/src/views/iam/DomainActionForm.vue
+++ b/ui/src/views/iam/DomainActionForm.vue
@@ -68,6 +68,7 @@
rules: [{ required: field.required, message: $t('message.error.select') }]
}]"
:placeholder="field.description"
+ :autoFocus="fieldIndex === firstIndex"
>
{{ opt }}
@@ -87,6 +88,7 @@
:filterOption="(input, option) => {
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
}"
+ :autoFocus="fieldIndex === firstIndex"
>
{{ opt.name || opt.description || opt.traffictype || opt.publicip }}
@@ -101,6 +103,7 @@
rules: [{ required: field.required, message: $t('message.error.select') }]
}]"
:placeholder="field.description"
+ :autoFocus="fieldIndex === firstIndex"
>
{{ opt.name && opt.type ? opt.name + ' (' + opt.type + ')' : opt.name || opt.description }}
@@ -113,6 +116,7 @@
rules: [{ required: field.required, message: `${$t('message.validate.number')}` }]
}]"
:placeholder="field.description"
+ :autoFocus="fieldIndex === firstIndex"
/>
@@ -120,7 +124,8 @@
v-decorator="[field.name, {
rules: [{ required: field.required, message: $t('message.error.required.input') }]
}]"
- :placeholder="field.description" />
+ :placeholder="field.description"
+ :autoFocus="fieldIndex === firstIndex" />
@@ -151,6 +156,16 @@ export default {
beforeCreate () {
this.form = this.$form.createForm(this)
},
+ created () {
+ this.firstIndex = 0
+ for (let fieldIndex = 0; fieldIndex < this.action.paramFields.length; fieldIndex++) {
+ const field = this.action.paramFields[fieldIndex]
+ if (!(this.action.mapping && field.name in this.action.mapping && this.action.mapping[field.name].value)) {
+ this.firstIndex = fieldIndex
+ break
+ }
+ }
+ },
mounted () {
if (this.action.dataView && this.action.icon === 'edit') {
this.fillEditFormFieldValues()
diff --git a/ui/src/views/iam/EditUser.vue b/ui/src/views/iam/EditUser.vue
index e1ae0b58580..43c1b90d5f4 100644
--- a/ui/src/views/iam/EditUser.vue
+++ b/ui/src/views/iam/EditUser.vue
@@ -30,7 +30,8 @@
v-decorator="['username', {
rules: [{ required: true, message: $t('message.error.required.input') }]
}]"
- :placeholder="apiParams.username.description" />
+ :placeholder="apiParams.username.description"
+ autoFocus />
diff --git a/ui/src/views/iam/ImportRole.vue b/ui/src/views/iam/ImportRole.vue
index 4fad432ef27..278f8dae863 100644
--- a/ui/src/views/iam/ImportRole.vue
+++ b/ui/src/views/iam/ImportRole.vue
@@ -62,7 +62,8 @@
v-decorator="['name', {
rules: [{ required: true, message: $t('message.error.required.input') }]
}]"
- :placeholder="importRoleApiParams.name.description" />
+ :placeholder="importRoleApiParams.name.description"
+ autoFocus />
diff --git a/ui/src/views/iam/PermissionEditable.vue b/ui/src/views/iam/PermissionEditable.vue
index df70749e183..f7905d53f6d 100644
--- a/ui/src/views/iam/PermissionEditable.vue
+++ b/ui/src/views/iam/PermissionEditable.vue
@@ -18,7 +18,8 @@
+ @change="handleChange"
+ autoFocus>
{{ $t('label.allow') }}
{{ $t('label.deny') }}
diff --git a/ui/src/views/image/AddKubernetesSupportedVersion.vue b/ui/src/views/image/AddKubernetesSupportedVersion.vue
index 30fb4804876..58cf77fcb31 100644
--- a/ui/src/views/image/AddKubernetesSupportedVersion.vue
+++ b/ui/src/views/image/AddKubernetesSupportedVersion.vue
@@ -33,7 +33,8 @@
v-decorator="['semanticversion', {
rules: [{ required: true, message: $t('message.error.kuberversion') }]
}]"
- :placeholder="apiParams.semanticversion.description"/>
+ :placeholder="apiParams.semanticversion.description"
+ autoFocus />
diff --git a/ui/src/views/image/IsoZones.vue b/ui/src/views/image/IsoZones.vue
index 6808724bd8f..d95a9a73e2c 100644
--- a/ui/src/views/image/IsoZones.vue
+++ b/ui/src/views/image/IsoZones.vue
@@ -108,7 +108,8 @@
:filterOption="(input, option) => {
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
}"
- :loading="zoneLoading">
+ :loading="zoneLoading"
+ autoFocus>
{{ zone.name }}
diff --git a/ui/src/views/image/RegisterOrUploadIso.vue b/ui/src/views/image/RegisterOrUploadIso.vue
index a5b2a6afd2d..b2284df3e4e 100644
--- a/ui/src/views/image/RegisterOrUploadIso.vue
+++ b/ui/src/views/image/RegisterOrUploadIso.vue
@@ -29,7 +29,7 @@
layout="vertical">
+ :placeholder="apiParams.name.description"
+ :autoFocus="currentForm !== 'Create'" />
diff --git a/ui/src/views/image/RegisterOrUploadTemplate.vue b/ui/src/views/image/RegisterOrUploadTemplate.vue
index c55410ff0bc..cb60116893f 100644
--- a/ui/src/views/image/RegisterOrUploadTemplate.vue
+++ b/ui/src/views/image/RegisterOrUploadTemplate.vue
@@ -31,7 +31,7 @@
+ :placeholder="apiParams.name.description"
+ :autoFocus="currentForm !== 'Create'"/>
diff --git a/ui/src/views/image/TemplateZones.vue b/ui/src/views/image/TemplateZones.vue
index 047d39f23b1..e0abd029a84 100644
--- a/ui/src/views/image/TemplateZones.vue
+++ b/ui/src/views/image/TemplateZones.vue
@@ -100,7 +100,8 @@
:filterOption="(input, option) => {
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
}"
- :loading="zoneLoading">
+ :loading="zoneLoading"
+ autoFocus>
{{ zone.name }}
diff --git a/ui/src/views/image/UpdateKubernetesSupportedVersion.vue b/ui/src/views/image/UpdateKubernetesSupportedVersion.vue
index 6d8475f07fd..77d5a1892c9 100644
--- a/ui/src/views/image/UpdateKubernetesSupportedVersion.vue
+++ b/ui/src/views/image/UpdateKubernetesSupportedVersion.vue
@@ -34,7 +34,8 @@
return option.componentOptions.children[0].text.toLowerCase().indexOf(input.toLowerCase()) >= 0
}"
:loading="stateLoading"
- :placeholder="apiParams.state.description">
+ :placeholder="apiParams.state.description"
+ autoFocus >
{{ opt.name || opt.description }}
diff --git a/ui/src/views/image/UpdateTemplateIsoPermissions.vue b/ui/src/views/image/UpdateTemplateIsoPermissions.vue
index 808567e795c..4b98e42b27f 100644
--- a/ui/src/views/image/UpdateTemplateIsoPermissions.vue
+++ b/ui/src/views/image/UpdateTemplateIsoPermissions.vue
@@ -23,7 +23,11 @@