diff --git a/api/src/main/java/com/cloud/vm/VmDetailConstants.java b/api/src/main/java/com/cloud/vm/VmDetailConstants.java index f24c4f587c40..1bf471bbd5cb 100644 --- a/api/src/main/java/com/cloud/vm/VmDetailConstants.java +++ b/api/src/main/java/com/cloud/vm/VmDetailConstants.java @@ -17,14 +17,41 @@ package com.cloud.vm; public interface VmDetailConstants { - public static final String KEYBOARD = "keyboard"; - public static final String NIC_ADAPTER = "nicAdapter"; - public static final String ROOT_DISK_CONTROLLER = "rootDiskController"; - public static final String NESTED_VIRTUALIZATION_FLAG = "nestedVirtualizationFlag"; - public static final String HYPERVISOR_TOOLS_VERSION = "hypervisortoolsversion"; - public static final String DATA_DISK_CONTROLLER = "dataDiskController"; - public static final String SVGA_VRAM_SIZE = "svga.vramSize"; - public static final String CPU_NUMBER = "cpuNumber"; - public static final String CPU_SPEED = "cpuSpeed"; - public static final String MEMORY = "memory"; + String KEYBOARD = "keyboard"; + String CPU_CORE_PER_SOCKET = "cpu.corespersocket"; + + // VMware specific + String NIC_ADAPTER = "nicAdapter"; + String ROOT_DISK_CONTROLLER = "rootDiskController"; + String DATA_DISK_CONTROLLER = "dataDiskController"; + String SVGA_VRAM_SIZE = "svga.vramSize"; + String NESTED_VIRTUALIZATION_FLAG = "nestedVirtualizationFlag"; + + // XenServer specific (internal) + String HYPERVISOR_TOOLS_VERSION = "hypervisortoolsversion"; + String PLATFORM = "platform"; + String TIME_OFFSET = "timeoffset"; + + // KVM specific (internal) + String KVM_VNC_PORT = "kvm.vnc.port"; + String KVM_VNC_ADDRESS = "kvm.vnc.address"; + + // Mac OSX guest specific (internal) + String SMC_PRESENT = "smc.present"; + String FIRMWARE = "firmware"; + + // VM deployment with custom compute offering params + String CPU_NUMBER = "cpuNumber"; + String CPU_SPEED = "cpuSpeed"; + String MEMORY = "memory"; + + // Misc details for internal usage (not to be set/changed by user or admin) + String CPU_OVER_COMMIT_RATIO = "cpuOvercommitRatio"; + String MEMORY_OVER_COMMIT_RATIO = "memoryOvercommitRatio"; + String MESSAGE_RESERVED_CAPACITY_FREED_FLAG = "Message.ReservedCapacityFreed.Flag"; + String DEPLOY_VM = "deployvm"; + String ROOT_DISK_SIZE = "rootdisksize"; + String SSH_PUBLIC_KEY = "SSH.PublicKey"; + String PASSWORD = "password"; + String ENCRYPTED_PASSWORD = "Encrypted.Password"; } diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/resource/ListDetailOptionsCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/resource/ListDetailOptionsCmd.java new file mode 100644 index 000000000000..54f041f1756f --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/resource/ListDetailOptionsCmd.java @@ -0,0 +1,89 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.command.user.resource; + +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.DetailOptionsResponse; +import org.apache.cloudstack.context.CallContext; + +import com.cloud.server.ResourceTag; +import com.google.common.base.Strings; + +@APICommand(name = ListDetailOptionsCmd.APINAME, + description = "Lists all possible details and their options for a resource type such as a VM or a template", + responseObject = DetailOptionsResponse.class, + since = "4.13", + requestHasSensitiveInfo = false, + responseHasSensitiveInfo = false) +public class ListDetailOptionsCmd extends BaseCmd { + public final static String APINAME = "listDetailOptions"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.RESOURCE_TYPE, type = CommandType.STRING, required = true, + description = "the resource type such as UserVm, Template etc.", + validations = {ApiArgValidator.NotNullOrEmpty} + ) + private String resourceType; + + @Parameter(name = ApiConstants.RESOURCE_ID, type = CommandType.STRING, + description = "the UUID of the resource (optional)") + private String resourceId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public ResourceTag.ResourceObjectType getResourceType() { + return _taggedResourceService.getResourceType(resourceType); + } + + public String getResourceId() { + if (!Strings.isNullOrEmpty(resourceId)) { + return _taggedResourceService.getUuid(resourceId, getResourceType()); + } + return null; + } + + ///////////////////////////////////////////////////// + /////////////////// Implementation ////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + @Override + public void execute() { + final DetailOptionsResponse response = _queryService.listDetailOptions(this); + response.setResponseName(getCommandName()); + response.setObjectName("detailoptions"); + setResponseObject(response); + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/response/DetailOptionsResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/DetailOptionsResponse.java new file mode 100644 index 000000000000..5f6bff395976 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/response/DetailOptionsResponse.java @@ -0,0 +1,44 @@ +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +package org.apache.cloudstack.api.response; + +import java.util.List; +import java.util.Map; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +public class DetailOptionsResponse extends BaseResponse { + @SerializedName(ApiConstants.DETAILS) + @Param(description = "Map of all possible details and their possible list of values") + private Map> details; + + public DetailOptionsResponse(Map> details) { + this.details = details; + } + + public void setDetails(Map> details) { + this.details = details; + } + + public Map> getDetails() { + return details; + } +} diff --git a/api/src/main/java/org/apache/cloudstack/query/QueryService.java b/api/src/main/java/org/apache/cloudstack/query/QueryService.java index ac29dff23a63..287efee2161c 100644 --- a/api/src/main/java/org/apache/cloudstack/query/QueryService.java +++ b/api/src/main/java/org/apache/cloudstack/query/QueryService.java @@ -20,8 +20,8 @@ import org.apache.cloudstack.affinity.AffinityGroupResponse; import org.apache.cloudstack.api.command.admin.domain.ListDomainsCmd; -import org.apache.cloudstack.api.command.admin.host.ListHostsCmd; import org.apache.cloudstack.api.command.admin.host.ListHostTagsCmd; +import org.apache.cloudstack.api.command.admin.host.ListHostsCmd; import org.apache.cloudstack.api.command.admin.internallb.ListInternalLBVMsCmd; import org.apache.cloudstack.api.command.admin.management.ListMgmtsCmd; import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd; @@ -40,6 +40,7 @@ import org.apache.cloudstack.api.command.user.offering.ListServiceOfferingsCmd; import org.apache.cloudstack.api.command.user.project.ListProjectInvitationsCmd; import org.apache.cloudstack.api.command.user.project.ListProjectsCmd; +import org.apache.cloudstack.api.command.user.resource.ListDetailOptionsCmd; import org.apache.cloudstack.api.command.user.securitygroup.ListSecurityGroupsCmd; import org.apache.cloudstack.api.command.user.tag.ListTagsCmd; import org.apache.cloudstack.api.command.user.template.ListTemplatesCmd; @@ -50,6 +51,7 @@ import org.apache.cloudstack.api.command.user.zone.ListZonesCmd; import org.apache.cloudstack.api.response.AccountResponse; import org.apache.cloudstack.api.response.AsyncJobResponse; +import org.apache.cloudstack.api.response.DetailOptionsResponse; import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.DomainRouterResponse; @@ -134,6 +136,8 @@ public interface QueryService { ListResponse listIsos(ListIsosCmd cmd); + DetailOptionsResponse listDetailOptions(ListDetailOptionsCmd cmd); + ListResponse searchForAffinityGroups(ListAffinityGroupsCmd cmd); List listResourceDetails(ListResourceDetailsCmd cmd); diff --git a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java index 7d218e226d50..86310150363a 100755 --- a/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java +++ b/engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java @@ -1071,16 +1071,16 @@ public void orchestrateStart(final String vmUuid, final Map 1f || Float.parseFloat(cluster_detail_ram.getValue()) > 1f)) { - userVmDetailsDao.addDetail(vm.getId(), "cpuOvercommitRatio", cluster_detail_cpu.getValue(), true); - userVmDetailsDao.addDetail(vm.getId(), "memoryOvercommitRatio", cluster_detail_ram.getValue(), true); - } else if (userVmDetailsDao.findDetail(vm.getId(), "cpuOvercommitRatio") != null) { - userVmDetailsDao.addDetail(vm.getId(), "cpuOvercommitRatio", cluster_detail_cpu.getValue(), true); - userVmDetailsDao.addDetail(vm.getId(), "memoryOvercommitRatio", cluster_detail_ram.getValue(), true); + userVmDetailsDao.addDetail(vm.getId(), VmDetailConstants.CPU_OVER_COMMIT_RATIO, cluster_detail_cpu.getValue(), true); + userVmDetailsDao.addDetail(vm.getId(), VmDetailConstants.MEMORY_OVER_COMMIT_RATIO, cluster_detail_ram.getValue(), true); + } else if (userVmDetailsDao.findDetail(vm.getId(), VmDetailConstants.CPU_OVER_COMMIT_RATIO) != null) { + userVmDetailsDao.addDetail(vm.getId(), VmDetailConstants.CPU_OVER_COMMIT_RATIO, cluster_detail_cpu.getValue(), true); + userVmDetailsDao.addDetail(vm.getId(), VmDetailConstants.MEMORY_OVER_COMMIT_RATIO, cluster_detail_ram.getValue(), true); } vmProfile.setCpuOvercommitRatio(Float.parseFloat(cluster_detail_cpu.getValue())); @@ -1162,8 +1162,8 @@ public void orchestrateStart(final String vmUuid, final Map vmMetadatum) { private void updateVmMetaData(Long vmId, String platform) { UserVmVO userVm = _userVmDao.findById(vmId); _userVmDao.loadDetails(userVm); - if ( userVm.details.containsKey("timeoffset")) { - userVm.details.remove("timeoffset"); + if ( userVm.details.containsKey(VmDetailConstants.TIME_OFFSET)) { + userVm.details.remove(VmDetailConstants.TIME_OFFSET); } - userVm.setDetail("platform", platform); + userVm.setDetail(VmDetailConstants.PLATFORM, platform); String pvdriver = "xenserver56"; if ( platform.contains("device_id")) { pvdriver = "xenserver61"; } - if (!userVm.details.containsKey("hypervisortoolsversion") || !userVm.details.get("hypervisortoolsversion").equals(pvdriver)) { - userVm.setDetail("hypervisortoolsversion", pvdriver); + if (!userVm.details.containsKey(VmDetailConstants.HYPERVISOR_TOOLS_VERSION) || !userVm.details.get(VmDetailConstants.HYPERVISOR_TOOLS_VERSION).equals(pvdriver)) { + userVm.setDetail(VmDetailConstants.HYPERVISOR_TOOLS_VERSION, pvdriver); } _userVmDao.saveDetails(userVm); } 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 37d27c855bc4..1897f19e02cf 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 @@ -1876,7 +1876,7 @@ protected StartAnswer execute(StartCommand cmd) { // Check for multi-cores per socket settings int numCoresPerSocket = 1; - String coresPerSocket = vmSpec.getDetails().get("cpu.corespersocket"); + String coresPerSocket = vmSpec.getDetails().get(VmDetailConstants.CPU_CORE_PER_SOCKET); if (coresPerSocket != null) { String apiVersion = HypervisorHostHelper.getVcenterApiVersion(vmMo.getContext()); // Property 'numCoresPerSocket' is supported since vSphere API 5.0 diff --git a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java index e1066b755e3b..3d4fb552d852 100644 --- a/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java +++ b/plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java @@ -134,6 +134,7 @@ import com.cloud.utils.ssh.SshHelper; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.PowerState; +import com.cloud.vm.VmDetailConstants; import com.trilead.ssh2.SCPClient; import com.xensource.xenapi.Bond; import com.xensource.xenapi.Connection; @@ -1870,18 +1871,18 @@ protected void finalizeVmMetaData(final VM vm, final Connection conn, final Virt final Map details = vmSpec.getDetails(); if (details != null) { - final String platformstring = details.get("platform"); + final String platformstring = details.get(VmDetailConstants.PLATFORM); if (platformstring != null && !platformstring.isEmpty()) { final Map platform = StringUtils.stringToMap(platformstring); vm.setPlatform(conn, platform); } else { - final String timeoffset = details.get("timeoffset"); + final String timeoffset = details.get(VmDetailConstants.TIME_OFFSET); if (timeoffset != null) { final Map platform = vm.getPlatform(conn); - platform.put("timeoffset", timeoffset); + platform.put(VmDetailConstants.TIME_OFFSET, timeoffset); vm.setPlatform(conn, platform); } - final String coresPerSocket = details.get("cpu.corespersocket"); + final String coresPerSocket = details.get(VmDetailConstants.CPU_CORE_PER_SOCKET); if (coresPerSocket != null) { final Map platform = vm.getPlatform(conn); platform.put("cores-per-socket", coresPerSocket); @@ -1889,7 +1890,7 @@ protected void finalizeVmMetaData(final VM vm, final Connection conn, final Virt } } if (!BootloaderType.CD.equals(vmSpec.getBootloader())) { - final String xenservertoolsversion = details.get("hypervisortoolsversion"); + final String xenservertoolsversion = details.get(VmDetailConstants.HYPERVISOR_TOOLS_VERSION); if ((xenservertoolsversion == null || !xenservertoolsversion.equalsIgnoreCase("xenserver61")) && vmSpec.getGpuDevice() == null) { final Map platform = vm.getPlatform(conn); platform.remove("device_id"); diff --git a/server/src/main/java/com/cloud/api/ApiDBUtils.java b/server/src/main/java/com/cloud/api/ApiDBUtils.java index 22ed2437d4de..40ff827a9cd5 100644 --- a/server/src/main/java/com/cloud/api/ApiDBUtils.java +++ b/server/src/main/java/com/cloud/api/ApiDBUtils.java @@ -302,6 +302,7 @@ import com.cloud.vm.UserVmVO; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VmDetailConstants; import com.cloud.vm.VmStats; import com.cloud.vm.dao.ConsoleProxyDao; import com.cloud.vm.dao.DomainRouterDao; @@ -1454,7 +1455,7 @@ public static String getKeyPairName(String sshPublicKey) { } public static UserVmDetailVO findPublicKeyByVmId(long vmId) { - return s_userVmDetailsDao.findDetail(vmId, "SSH.PublicKey"); + return s_userVmDetailsDao.findDetail(vmId, VmDetailConstants.SSH_PUBLIC_KEY); } public static void getAutoScaleVmGroupPolicies(long vmGroupId, List scaleUpPolicies, List scaleDownPolicies) { diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java index 91e0466d9dbb..ef16bab98bd5 100644 --- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java @@ -17,7 +17,10 @@ package com.cloud.api.query; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; import java.util.Date; +import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; @@ -25,8 +28,6 @@ import javax.inject.Inject; -import com.cloud.cluster.ManagementServerHostVO; -import com.cloud.cluster.dao.ManagementServerHostDao; import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.affinity.AffinityGroupDomainMapVO; import org.apache.cloudstack.affinity.AffinityGroupResponse; @@ -64,6 +65,7 @@ import org.apache.cloudstack.api.command.user.offering.ListServiceOfferingsCmd; import org.apache.cloudstack.api.command.user.project.ListProjectInvitationsCmd; import org.apache.cloudstack.api.command.user.project.ListProjectsCmd; +import org.apache.cloudstack.api.command.user.resource.ListDetailOptionsCmd; import org.apache.cloudstack.api.command.user.securitygroup.ListSecurityGroupsCmd; import org.apache.cloudstack.api.command.user.tag.ListTagsCmd; import org.apache.cloudstack.api.command.user.template.ListTemplatesCmd; @@ -74,6 +76,7 @@ import org.apache.cloudstack.api.command.user.zone.ListZonesCmd; import org.apache.cloudstack.api.response.AccountResponse; import org.apache.cloudstack.api.response.AsyncJobResponse; +import org.apache.cloudstack.api.response.DetailOptionsResponse; import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.cloudstack.api.response.DomainResponse; import org.apache.cloudstack.api.response.DomainRouterResponse; @@ -156,6 +159,8 @@ import com.cloud.api.query.vo.UserAccountJoinVO; import com.cloud.api.query.vo.UserVmJoinVO; import com.cloud.api.query.vo.VolumeJoinVO; +import com.cloud.cluster.ManagementServerHostVO; +import com.cloud.cluster.dao.ManagementServerHostDao; import com.cloud.dc.DedicatedResourceVO; import com.cloud.dc.dao.DedicatedResourceDao; import com.cloud.domain.Domain; @@ -215,14 +220,17 @@ import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Func; import com.cloud.utils.db.SearchCriteria.Op; +import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.DomainRouterVO; import com.cloud.vm.UserVmVO; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VmDetailConstants; import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.VMInstanceDao; +import com.google.common.base.Strings; @Component public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements QueryService, Configurable { @@ -3399,6 +3407,50 @@ private Pair, Integer> searchForIsosInternal(ListIsosCmd cm hypervisorType, true, cmd.listInReadyState(), permittedAccounts, caller, listProjectResourcesCriteria, tags, showRemovedISO, null, null); } + @Override + public DetailOptionsResponse listDetailOptions(final ListDetailOptionsCmd cmd) { + final ResourceObjectType type = cmd.getResourceType(); + final String resourceUuid = cmd.getResourceId(); + final Map> options = new HashMap<>(); + switch (type) { + case Template: + case UserVm: + HypervisorType hypervisorType = HypervisorType.None; + if (!Strings.isNullOrEmpty(resourceUuid) && ResourceObjectType.Template.equals(type)) { + hypervisorType = _templateDao.findByUuid(resourceUuid).getHypervisorType(); + } + if (!Strings.isNullOrEmpty(resourceUuid) && ResourceObjectType.UserVm.equals(type)) { + hypervisorType = _vmInstanceDao.findByUuid(resourceUuid).getHypervisorType(); + } + fillVMOrTemplateDetailOptions(options, hypervisorType); + break; + default: + throw new CloudRuntimeException("Resource type not supported."); + } + return new DetailOptionsResponse(options); + } + + private void fillVMOrTemplateDetailOptions(final Map> options, final HypervisorType hypervisorType) { + if (options == null) { + throw new CloudRuntimeException("Invalid/null detail-options response object passed"); + } + + options.put(VmDetailConstants.KEYBOARD, Arrays.asList("uk", "us", "jp", "fr")); + options.put(VmDetailConstants.CPU_CORE_PER_SOCKET, Collections.emptyList()); + + if (HypervisorType.KVM.equals(hypervisorType)) { + options.put(VmDetailConstants.ROOT_DISK_CONTROLLER, Arrays.asList("ide", "scsi", "virtio")); + } + + if (HypervisorType.VMware.equals(hypervisorType)) { + options.put(VmDetailConstants.NIC_ADAPTER, Arrays.asList("E1000", "PCNet32", "Vmxnet2", "Vmxnet3")); + options.put(VmDetailConstants.ROOT_DISK_CONTROLLER, Arrays.asList("osdefault", "ide", "scsi", "lsilogic", "lsisas1068", "buslogic", "pvscsi")); + options.put(VmDetailConstants.DATA_DISK_CONTROLLER, Arrays.asList("osdefault", "ide", "scsi", "lsilogic", "lsisas1068", "buslogic", "pvscsi")); + options.put(VmDetailConstants.NESTED_VIRTUALIZATION_FLAG, Arrays.asList("true", "false")); + options.put(VmDetailConstants.SVGA_VRAM_SIZE, Collections.emptyList()); + } + } + @Override public ListResponse searchForAffinityGroups(ListAffinityGroupsCmd cmd) { Pair, Integer> result = searchForAffinityGroupsInternal(cmd); @@ -3705,7 +3757,7 @@ public ListResponse listManagementServers(ListMgmtsCmd } response.setResponses(result); return response; - } + } @Override public String getConfigComponentName() { diff --git a/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java b/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java index cc2d7a56b601..4731a7d18229 100644 --- a/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java +++ b/server/src/main/java/com/cloud/capacity/CapacityManagerImpl.java @@ -89,6 +89,7 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Event; import com.cloud.vm.VirtualMachine.State; +import com.cloud.vm.VmDetailConstants; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDetailsDao; import com.cloud.vm.dao.VMInstanceDao; @@ -138,8 +139,6 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager, @Inject MessageBus _messageBus; - private static final String MESSAGE_RESERVED_CAPACITY_FREED_FLAG = "Message.ReservedCapacityFreed.Flag"; - @Override public boolean configure(String name, Map params) throws ConfigurationException { _vmCapacityReleaseInterval = NumbersUtil.parseInt(_configDao.getValue(Config.CapacitySkipcountingHours.key()), 3600); @@ -632,8 +631,8 @@ public void updateCapacityForHost(final Host host) { Float ramOvercommitRatio = 1.0f; long secondsSinceLastUpdate = (DateUtil.currentGMTTime().getTime() - vm.getUpdateTime().getTime()) / 1000; if (secondsSinceLastUpdate < _vmCapacityReleaseInterval) { - UserVmDetailVO vmDetailCpu = _userVmDetailsDao.findDetail(vm.getId(), "cpuOvercommitRatio"); - UserVmDetailVO vmDetailRam = _userVmDetailsDao.findDetail(vm.getId(), "memoryOvercommitRatio"); + UserVmDetailVO vmDetailCpu = _userVmDetailsDao.findDetail(vm.getId(), VmDetailConstants.CPU_OVER_COMMIT_RATIO); + UserVmDetailVO vmDetailRam = _userVmDetailsDao.findDetail(vm.getId(), VmDetailConstants.MEMORY_OVER_COMMIT_RATIO); if (vmDetailCpu != null) { //if vmDetail_cpu is not null it means it is running in a overcommited cluster. cpuOvercommitRatio = Float.parseFloat(vmDetailCpu.getValue()); @@ -657,14 +656,14 @@ public void updateCapacityForHost(final Host host) { } else { // signal if not done already, that the VM has been stopped for skip.counting.hours, // hence capacity will not be reserved anymore. - UserVmDetailVO messageSentFlag = _userVmDetailsDao.findDetail(vm.getId(), MESSAGE_RESERVED_CAPACITY_FREED_FLAG); + UserVmDetailVO messageSentFlag = _userVmDetailsDao.findDetail(vm.getId(), VmDetailConstants.MESSAGE_RESERVED_CAPACITY_FREED_FLAG); if (messageSentFlag == null || !Boolean.valueOf(messageSentFlag.getValue())) { _messageBus.publish(_name, "VM_ReservedCapacity_Free", PublishScope.LOCAL, vm); if (vm.getType() == VirtualMachine.Type.User) { UserVmVO userVM = _userVMDao.findById(vm.getId()); _userVMDao.loadDetails(userVM); - userVM.setDetail(MESSAGE_RESERVED_CAPACITY_FREED_FLAG, "true"); + userVM.setDetail(VmDetailConstants.MESSAGE_RESERVED_CAPACITY_FREED_FLAG, "true"); _userVMDao.saveDetails(userVM); } } @@ -891,7 +890,7 @@ public boolean postStateTransitionEvent(StateMachine2.Transition t UserVmVO userVM = _userVMDao.findById(vm.getId()); _userVMDao.loadDetails(userVM); // free the message sent flag if it exists - userVM.setDetail(MESSAGE_RESERVED_CAPACITY_FREED_FLAG, "false"); + userVM.setDetail(VmDetailConstants.MESSAGE_RESERVED_CAPACITY_FREED_FLAG, "false"); _userVMDao.saveDetails(userVM); } diff --git a/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java b/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java index 4d2452d45ce5..76e4fc03ce7b 100644 --- a/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java +++ b/server/src/main/java/com/cloud/network/element/ConfigDriveNetworkElement.java @@ -77,6 +77,7 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineManager; import com.cloud.vm.VirtualMachineProfile; +import com.cloud.vm.VmDetailConstants; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.UserVmDetailsDao; @@ -195,7 +196,7 @@ public boolean canEnableIndividualServices() { } private String getSshKey(VirtualMachineProfile profile) { - final UserVmDetailVO vmDetailSshKey = _userVmDetailsDao.findDetail(profile.getId(), "SSH.PublicKey"); + final UserVmDetailVO vmDetailSshKey = _userVmDetailsDao.findDetail(profile.getId(), VmDetailConstants.SSH_PUBLIC_KEY); return (vmDetailSshKey!=null ? vmDetailSshKey.getValue() : null); } @@ -262,7 +263,7 @@ private void storePasswordInVmDetails(VirtualMachineProfile vm) { final String password_encrypted = DBEncryptionUtil.encrypt(password); final UserVmVO userVmVO = _userVmDao.findById(vm.getId()); - _userVmDetailsDao.addDetail(vm.getId(), "password", password_encrypted, false); + _userVmDetailsDao.addDetail(vm.getId(), VmDetailConstants.PASSWORD, password_encrypted, false); userVmVO.setUpdateParameters(true); _userVmDao.update(userVmVO.getId(), userVmVO); diff --git a/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java b/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java index 862ccfe69e63..850f0e1e51bb 100644 --- a/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/main/java/com/cloud/network/element/VirtualRouterElement.java @@ -31,6 +31,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; +import com.cloud.vm.VmDetailConstants; import com.google.gson.Gson; import org.apache.cloudstack.api.command.admin.router.ConfigureOvsElementCmd; @@ -718,7 +719,7 @@ public boolean savePassword(final Network network, final NicProfile nic, final V final UserVmVO userVmVO = _userVmDao.findById(vm.getId()); _userVmDao.loadDetails(userVmVO); - userVmVO.setDetail("password", password_encrypted); + userVmVO.setDetail(VmDetailConstants.PASSWORD, password_encrypted); _userVmDao.saveDetails(userVmVO); userVmVO.setUpdateParameters(true); diff --git a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java index 8bc97cbea2a4..b3983bdf4692 100755 --- a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java +++ b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java @@ -31,6 +31,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.vm.VmDetailConstants; import com.cloud.vm.dao.UserVmDetailsDao; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.commons.lang.ObjectUtils; @@ -1313,8 +1314,8 @@ protected void setKVMVncAccess(long hostId, List vms) { for (VMInstanceVO vm : vms) { GetVncPortAnswer vmVncPortAnswer = (GetVncPortAnswer) _agentMgr.easySend(hostId, new GetVncPortCommand(vm.getId(), vm.getInstanceName())); if (vmVncPortAnswer != null) { - userVmDetailsDao.addDetail(vm.getId(), "kvm.vnc.address", vmVncPortAnswer.getAddress(), true); - userVmDetailsDao.addDetail(vm.getId(), "kvm.vnc.port", String.valueOf(vmVncPortAnswer.getPort()), true); + userVmDetailsDao.addDetail(vm.getId(), VmDetailConstants.KVM_VNC_ADDRESS, vmVncPortAnswer.getAddress(), true); + userVmDetailsDao.addDetail(vm.getId(), VmDetailConstants.KVM_VNC_PORT, String.valueOf(vmVncPortAnswer.getPort()), true); } } } diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index b211cab27a23..8f1a798167b2 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -37,7 +37,6 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.storage.ScopeType; import org.apache.cloudstack.acl.ControlledEntity; import org.apache.cloudstack.affinity.AffinityGroupProcessor; import org.apache.cloudstack.affinity.dao.AffinityGroupVMMapDao; @@ -217,10 +216,10 @@ import org.apache.cloudstack.api.command.admin.usage.DeleteTrafficMonitorCmd; import org.apache.cloudstack.api.command.admin.usage.DeleteTrafficTypeCmd; import org.apache.cloudstack.api.command.admin.usage.GenerateUsageRecordsCmd; -import org.apache.cloudstack.api.command.admin.usage.ListUsageRecordsCmd; import org.apache.cloudstack.api.command.admin.usage.ListTrafficMonitorsCmd; import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypeImplementorsCmd; import org.apache.cloudstack.api.command.admin.usage.ListTrafficTypesCmd; +import org.apache.cloudstack.api.command.admin.usage.ListUsageRecordsCmd; import org.apache.cloudstack.api.command.admin.usage.ListUsageTypesCmd; import org.apache.cloudstack.api.command.admin.usage.RemoveRawUsageRecordsCmd; import org.apache.cloudstack.api.command.admin.usage.UpdateTrafficTypeCmd; @@ -409,6 +408,7 @@ import org.apache.cloudstack.api.command.user.region.ha.gslb.RemoveFromGlobalLoadBalancerRuleCmd; import org.apache.cloudstack.api.command.user.region.ha.gslb.UpdateGlobalLoadBalancerRuleCmd; import org.apache.cloudstack.api.command.user.resource.GetCloudIdentifierCmd; +import org.apache.cloudstack.api.command.user.resource.ListDetailOptionsCmd; import org.apache.cloudstack.api.command.user.resource.ListHypervisorsCmd; import org.apache.cloudstack.api.command.user.resource.ListResourceLimitsCmd; import org.apache.cloudstack.api.command.user.resource.UpdateResourceCountCmd; @@ -634,6 +634,7 @@ import com.cloud.storage.GuestOSHypervisorVO; import com.cloud.storage.GuestOSVO; import com.cloud.storage.GuestOsCategory; +import com.cloud.storage.ScopeType; import com.cloud.storage.StorageManager; import com.cloud.storage.StoragePool; import com.cloud.storage.Volume; @@ -2871,6 +2872,7 @@ public List> getCommands() { cmdList.add(ExtractTemplateCmd.class); cmdList.add(ListTemplatePermissionsCmd.class); cmdList.add(ListTemplatesCmd.class); + cmdList.add(ListDetailOptionsCmd.class); cmdList.add(RegisterTemplateCmd.class); cmdList.add(UpdateTemplateCmd.class); cmdList.add(UpdateTemplatePermissionsCmd.class); diff --git a/server/src/main/java/com/cloud/servlet/ConsoleProxyServlet.java b/server/src/main/java/com/cloud/servlet/ConsoleProxyServlet.java index 8cfaa9fd69b2..5a6c84f14795 100644 --- a/server/src/main/java/com/cloud/servlet/ConsoleProxyServlet.java +++ b/server/src/main/java/com/cloud/servlet/ConsoleProxyServlet.java @@ -41,6 +41,7 @@ import org.springframework.stereotype.Component; import org.springframework.web.context.support.SpringBeanAutowiringSupport; +import com.cloud.vm.VmDetailConstants; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -421,8 +422,8 @@ private String composeConsoleAccessUrl(String rootUrl, VirtualMachine vm, HostVO Pair portInfo; if (hostVo.getResourceState().equals(ResourceState.ErrorInMaintenance)) { - UserVmDetailVO detailAddress = _userVmDetailsDao.findDetail(vm.getId(), "kvm.vnc.address"); - UserVmDetailVO detailPort = _userVmDetailsDao.findDetail(vm.getId(), "kvm.vnc.port"); + UserVmDetailVO detailAddress = _userVmDetailsDao.findDetail(vm.getId(), VmDetailConstants.KVM_VNC_ADDRESS); + UserVmDetailVO detailPort = _userVmDetailsDao.findDetail(vm.getId(), VmDetailConstants.KVM_VNC_PORT); portInfo = new Pair<>(detailAddress.getValue(), Integer.valueOf(detailPort.getValue())); } else { portInfo = _ms.getVncPort(vm); @@ -441,7 +442,7 @@ private String composeConsoleAccessUrl(String rootUrl, VirtualMachine vm, HostVO } String sid = vm.getVncPassword(); - UserVmDetailVO details = _userVmDetailsDao.findDetail(vm.getId(), "keyboard"); + UserVmDetailVO details = _userVmDetailsDao.findDetail(vm.getId(), VmDetailConstants.KEYBOARD); String tag = vm.getUuid(); diff --git a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java index df3b59b5ff73..19050c7e9143 100755 --- a/server/src/main/java/com/cloud/template/TemplateManagerImpl.java +++ b/server/src/main/java/com/cloud/template/TemplateManagerImpl.java @@ -39,6 +39,7 @@ import com.cloud.utils.DateUtil; import com.cloud.utils.Pair; import com.cloud.utils.EnumUtils; +import com.cloud.vm.VmDetailConstants; import com.google.common.base.Joiner; import com.google.gson.Gson; import com.google.gson.GsonBuilder; @@ -1895,7 +1896,7 @@ public VMTemplateVO createPrivateTemplateRecord(CreateTemplateCmd cmd, Account t } } if (cmd.getDetails() != null) { - details.remove("Encrypted.Password"); // new password will be generated during vm deployment from password enabled template + details.remove(VmDetailConstants.ENCRYPTED_PASSWORD); // new password will be generated during vm deployment from password enabled template details.putAll(cmd.getDetails()); } if (!details.isEmpty()) { diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 68b45e1af7c3..523d96616804 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -844,7 +844,7 @@ private boolean resetVMSSHKeyInternal(Long vmId, String sshPublicKey, String pas } else { final UserVmVO userVm = _vmDao.findById(vmId); _vmDao.loadDetails(userVm); - userVm.setDetail("SSH.PublicKey", sshPublicKey); + userVm.setDetail(VmDetailConstants.SSH_PUBLIC_KEY, sshPublicKey); if (template.isEnablePassword()) { userVm.setPassword(password); //update the encrypted password in vm_details table too @@ -3354,13 +3354,13 @@ private UserVm createVirtualMachine(DataCenter zone, ServiceOffering serviceOffe boolean isIso = Storage.ImageFormat.ISO == template.getFormat(); long size = 0; // custom root disk size, resizes base template to larger size - if (customParameters.containsKey("rootdisksize")) { + if (customParameters.containsKey(VmDetailConstants.ROOT_DISK_SIZE)) { // only KVM, XenServer and VMware supports rootdisksize override if (!(hypervisorType == HypervisorType.KVM || hypervisorType == HypervisorType.XenServer || hypervisorType == HypervisorType.VMware || hypervisorType == HypervisorType.Simulator)) { throw new InvalidParameterValueException("Hypervisor " + hypervisorType + " does not support rootdisksize override"); } - Long rootDiskSize = NumbersUtil.parseLong(customParameters.get("rootdisksize"), -1); + Long rootDiskSize = NumbersUtil.parseLong(customParameters.get(VmDetailConstants.ROOT_DISK_SIZE), -1); if (rootDiskSize <= 0) { throw new InvalidParameterValueException("Root disk size should be a positive number."); } @@ -3743,7 +3743,7 @@ public UserVmVO doInTransaction(TransactionStatus status) throws InsufficientCap } if (sshPublicKey != null) { - vm.setDetail("SSH.PublicKey", sshPublicKey); + vm.setDetail(VmDetailConstants.SSH_PUBLIC_KEY, sshPublicKey); } if (keyboard != null && !keyboard.isEmpty()) { @@ -3755,9 +3755,9 @@ public UserVmVO doInTransaction(TransactionStatus status) throws InsufficientCap } Long rootDiskSize = null; // custom root disk size, resizes base template to larger size - if (customParameters.containsKey("rootdisksize")) { + if (customParameters.containsKey(VmDetailConstants.ROOT_DISK_SIZE)) { // already verified for positive number - rootDiskSize = Long.parseLong(customParameters.get("rootdisksize")); + rootDiskSize = Long.parseLong(customParameters.get(VmDetailConstants.ROOT_DISK_SIZE)); VMTemplateVO templateVO = _templateDao.findById(template.getId()); if (templateVO == null) { @@ -3781,10 +3781,10 @@ public UserVmVO doInTransaction(TransactionStatus status) throws InsufficientCap // If hypervisor is vSphere and OS is OS X, set special settings. if (hypervisorType.equals(HypervisorType.VMware)) { if (guestOS.getDisplayName().toLowerCase().contains("apple mac os")) { - vm.setDetail("smc.present", "TRUE"); + vm.setDetail(VmDetailConstants.SMC_PRESENT, "TRUE"); vm.setDetail(VmDetailConstants.ROOT_DISK_CONTROLLER, "scsi"); vm.setDetail(VmDetailConstants.DATA_DISK_CONTROLLER, "scsi"); - vm.setDetail("firmware", "efi"); + vm.setDetail(VmDetailConstants.FIRMWARE, "efi"); s_logger.info("guestOS is OSX : overwrite root disk controller to scsi, use smc and efi"); } else { String controllerSetting = _configDao.getValue("vmware.root.disk.controller"); @@ -3813,7 +3813,7 @@ public UserVmVO doInTransaction(TransactionStatus status) throws InsufficientCap vm.setDetail(key, customParameters.get(key)); } } - vm.setDetail("deployvm", "true"); + vm.setDetail(VmDetailConstants.DEPLOY_VM, "true"); _vmDao.saveDetails(vm); s_logger.debug("Allocating in the DB for vm"); @@ -3863,10 +3863,10 @@ public void validateRootDiskResize(final HypervisorType hypervisorType, Long roo s_logger.error(error); throw new InvalidParameterValueException(error); } else if ((rootDiskSize << 30) > templateVO.getSize()) { - if (hypervisorType == HypervisorType.VMware && (vm.getDetails() == null || vm.getDetails().get("rootDiskController") == null)) { + if (hypervisorType == HypervisorType.VMware && (vm.getDetails() == null || vm.getDetails().get(VmDetailConstants.ROOT_DISK_CONTROLLER) == null)) { s_logger.warn("If Root disk controller parameter is not overridden, then Root disk resize may fail because current Root disk controller value is NULL."); - } else if (hypervisorType == HypervisorType.VMware && !vm.getDetails().get("rootDiskController").toLowerCase().contains("scsi")) { - String error = "Found unsupported root disk controller: " + vm.getDetails().get("rootDiskController"); + } else if (hypervisorType == HypervisorType.VMware && !vm.getDetails().get(VmDetailConstants.ROOT_DISK_CONTROLLER).toLowerCase().contains("scsi")) { + String error = "Found unsupported root disk controller: " + vm.getDetails().get(VmDetailConstants.ROOT_DISK_CONTROLLER); s_logger.error(error); throw new InvalidParameterValueException(error); } else { @@ -3874,7 +3874,7 @@ public void validateRootDiskResize(final HypervisorType hypervisorType, Long roo } } else { s_logger.debug("Root disk size specified is " + (rootDiskSize << 30) + "B and Template root disk size is " + templateVO.getSize() + "B. Both are equal so no need to override"); - customParameters.remove("rootdisksize"); + customParameters.remove(VmDetailConstants.ROOT_DISK_SIZE); } } @@ -4157,7 +4157,7 @@ public boolean finalizeVirtualMachineProfile(VirtualMachineProfile profile, Depl boolean isWindows = _guestOSCategoryDao.findById(_guestOSDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows"); List vmData = _networkModel.generateVmData(vm.getUserData(), serviceOffering, vm.getDataCenterId(), vm.getInstanceName(), vm.getHostName(), vm.getId(), - vm.getUuid(), defaultNic.getIPv4Address(), vm.getDetail("SSH.PublicKey"), (String) profile.getParameter(VirtualMachineProfile.Param.VmPassword), isWindows); + vm.getUuid(), defaultNic.getIPv4Address(), vm.getDetail(VmDetailConstants.SSH_PUBLIC_KEY), (String) profile.getParameter(VirtualMachineProfile.Param.VmPassword), isWindows); String vmName = vm.getInstanceName(); String configDriveIsoRootFolder = "/tmp"; String isoFile = configDriveIsoRootFolder + "/" + vmName + "/configDrive/" + vmName + ".iso"; @@ -4543,8 +4543,8 @@ public Pair> startVirtualMach // this value is not being sent to the backend; need only for api // display purposes if (template.isEnablePassword()) { - if (vm.getDetail("password") != null) { - userVmDetailsDao.removeDetail(vm.getId(), "password"); + if (vm.getDetail(VmDetailConstants.PASSWORD) != null) { + userVmDetailsDao.removeDetail(vm.getId(), VmDetailConstants.PASSWORD); } vm.setUpdateParameters(false); _vmDao.update(vm.getId(), vm); @@ -6299,7 +6299,7 @@ public UserVm restoreVMInternal(Account caller, UserVmVO vm, Long newTemplateId) if (needRestart) { try { - if (vm.getDetail("password") != null) { + if (vm.getDetail(VmDetailConstants.PASSWORD) != null) { params = new HashMap(); params.put(VirtualMachineProfile.Param.VmPassword, password); } @@ -6312,8 +6312,8 @@ public UserVm restoreVMInternal(Account caller, UserVmVO vm, Long newTemplateId) if (vm.isUpdateParameters()) { vm.setUpdateParameters(false); _vmDao.loadDetails(vm); - if (vm.getDetail("password") != null) { - userVmDetailsDao.removeDetail(vm.getId(), "password"); + if (vm.getDetail(VmDetailConstants.PASSWORD) != null) { + userVmDetailsDao.removeDetail(vm.getId(), VmDetailConstants.PASSWORD); } _vmDao.update(vm.getId(), vm); } @@ -6491,7 +6491,7 @@ public void prepareStop(VirtualMachineProfile profile) { } private void encryptAndStorePassword(UserVmVO vm, String password) { - String sshPublicKey = vm.getDetail("SSH.PublicKey"); + String sshPublicKey = vm.getDetail(VmDetailConstants.SSH_PUBLIC_KEY); if (sshPublicKey != null && !sshPublicKey.equals("") && password != null && !password.equals("saved_password")) { if (!sshPublicKey.startsWith("ssh-rsa")) { s_logger.warn("Only RSA public keys can be used to encrypt a vm password."); @@ -6502,7 +6502,7 @@ private void encryptAndStorePassword(UserVmVO vm, String password) { throw new CloudRuntimeException("Error encrypting password"); } - vm.setDetail("Encrypted.Password", encryptedPasswd); + vm.setDetail(VmDetailConstants.ENCRYPTED_PASSWORD, encryptedPasswd); _vmDao.saveDetails(vm); } } @@ -6534,7 +6534,7 @@ public ConfigKey[] getConfigKeys() { public String getVmUserData(long vmId) { UserVmVO vm = _vmDao.findById(vmId); if (vm == null) { - throw new InvalidParameterValueException("Unable to find virual machine with id " + vmId); + throw new InvalidParameterValueException("Unable to find virtual machine with id " + vmId); } _accountMgr.checkAccess(CallContext.current().getCallingAccount(), null, true, vm); diff --git a/ui/css/cloudstack3.css b/ui/css/cloudstack3.css index 5294f5658802..dab2d88eec55 100644 --- a/ui/css/cloudstack3.css +++ b/ui/css/cloudstack3.css @@ -13393,9 +13393,25 @@ div.gpugroups div.list-view { ul.ui-autocomplete.ui-menu { width: 250px; - background: #ddd; - font-size: 13px; + max-height: 100px; + background: #eee; padding: 5px; + text-align: left; + overflow-y: auto; + overflow-x: hidden; + z-index: 100; +} + +.ui-menu .ui-menu-item { + cursor: pointer; +} + +.ui-menu .ui-menu-item .ui-state-active { + background: #CBDDF3; +} + +.ui-helper-hidden-accessible { + display: none; } .multi-edit-add-list .ui-button.migrateok, @@ -13470,4 +13486,4 @@ div.button.export a { background-size: 15.5px; text-decoration: none; color: black; -} \ No newline at end of file +} diff --git a/ui/scripts/globalSettings.js b/ui/scripts/globalSettings.js index ab03978c22a4..3e926ea678fc 100644 --- a/ui/scripts/globalSettings.js +++ b/ui/scripts/globalSettings.js @@ -168,7 +168,6 @@ }], dataProvider: function(args) { var items = []; - console.log(args); $.ajax({ url: createURL("listLdapConfigurations&hostname=" + args.context.ldapConfiguration[0].hostname), dataType: "json", diff --git a/ui/scripts/instances.js b/ui/scripts/instances.js index b00644793d6a..3e3a09e42065 100644 --- a/ui/scripts/instances.js +++ b/ui/scripts/instances.js @@ -3212,6 +3212,7 @@ settings: { title: 'label.settings', custom: cloudStack.uiCustom.granularDetails({ + resourceType: 'UserVm', dataProvider: function(args) { $.ajax({ url: createURL('listVirtualMachines&id=' + args.context.instances[0].id), @@ -3240,7 +3241,6 @@ async:false, success: function(json) { var details = json.listvirtualmachinesresponse.virtualmachine[0].details; - console.log(details); existingDetails = details; }, @@ -3248,7 +3248,6 @@ args.response.error(parseXMLHttpResponse(json)); } }); - console.log(existingDetails); var newDetails = ''; for (d in existingDetails) { if (d != data.name) { diff --git a/ui/scripts/roles.js b/ui/scripts/roles.js index 01700dfc9a5d..ff89dc56a19b 100644 --- a/ui/scripts/roles.js +++ b/ui/scripts/roles.js @@ -327,28 +327,24 @@ }); } }); - var setupAutocompletion = function() { - $($.find('input[name="rule"]')).autocomplete("destroy"); - $($.find('input[name="rule"]')).autocomplete({ - source: apiList, - autoFocus:true - }); - }; - if (apiList.length == 0) { - $.ajax({ - url: createURL("listApis"), - dataType: "json", - success: function(json) { - var response = json.listapisresponse.api; - $.each(response, function(idx, api) { - apiList.push(api.name); - }); - setupAutocompletion(); - } - }); - } else { - setupAutocompletion(); - } + $.ajax({ + url: createURL("listApis"), + dataType: "json", + success: function(json) { + var apis = []; + var response = json.listapisresponse.api; + $.each(response, function(idx, api) { + apis.push(api.name); + }); + $($.find('input[name="rule"]')).autocomplete({ + minLength: 0, + delay: 0, + source: apis.sort() + }).focus(function() { + $(this).data("uiAutocomplete").search($(this).val()); + }); + } + }); } }); } diff --git a/ui/scripts/templates.js b/ui/scripts/templates.js index 96660fac6804..e0ae8b90a4ed 100755 --- a/ui/scripts/templates.js +++ b/ui/scripts/templates.js @@ -1954,6 +1954,7 @@ settings: { title: 'label.settings', custom: cloudStack.uiCustom.granularDetails({ + resourceType: 'Template', dataProvider: function(args) { $.ajax({ url: createURL('listTemplates'), diff --git a/ui/scripts/ui-custom/granularSettings.js b/ui/scripts/ui-custom/granularSettings.js index 5312394127e6..0d49445924a1 100644 --- a/ui/scripts/ui-custom/granularSettings.js +++ b/ui/scripts/ui-custom/granularSettings.js @@ -54,9 +54,10 @@ return $listView; } }; - cloudStack.uiCustom.granularDetails = function(args) { + cloudStack.uiCustom.granularDetails = function(args) { var dataProvider = args.dataProvider; var actions = args.actions; + var resourceType = args.resourceType; return function(args) { var context = args.context; @@ -77,57 +78,140 @@ label: 'label.change.value', action: actions.edit }, - remove: { - label: 'Remove Setting', - messages: { - confirm: function(args) { - return 'Delete Setting'; - }, - notification: function(args) { - return 'Setting deleted'; - } - }, - action: actions.remove, - notification: { - poll: function(args) { - args.complete(); - } - } - }, - add : { - label: 'Add Setting', - messages: { - confirm: function(args) { - return 'Add Setting'; - }, - notification: function(args) { - return 'Setting added'; - } - }, - preFilter: function(args) { - return true; - }, - createForm: { - title: 'Add New Setting', - fields: { - name: { - label: 'label.name', - validation: { - required: true - } - }, - value: { - label: 'label.value', - validation: { - required: true - } - } - } - }, - action: actions.add - } + remove: { + label: 'Remove Setting', + messages: { + confirm: function(args) { + return 'Delete Setting'; + }, + notification: function(args) { + return 'Setting deleted'; + } + }, + action: actions.remove, + notification: { + poll: function(args) { + args.complete(); + } + } + }, + add : { + label: 'Add Setting', + messages: { + confirm: function(args) { + return 'Add Setting'; + }, + notification: function(args) { + return 'Setting added'; + } + }, + preFilter: function(args) { + return true; + }, + createForm: { + title: 'Add New Setting', + preFilter: function(args) { + var data = { + resourcetype: resourceType + }; + if (resourceType === 'UserVm') { + data.resourceid = args.context.instances[0].id; + } + if (resourceType === 'Template') { + data.resourceid = args.context.templates[0].id; + } + + $.ajax({ + url: createURL("listDetailOptions"), + data: data, + dataType: "json", + success: function(json) { + var details = json.listdetailoptionsresponse.detailoptions.details; + var keys = []; + Object.keys(details).forEach(function(key,index) { + keys.push(key); + }); + $(args.$form.find('input[name="name"]')).blur(); + $(args.$form.find('input[name="name"]')).autocomplete({ + minLength: 0, + delay: 0, + source: keys.sort(), + select: function(event, ui) { + const key = ui.item.value; + const options = details[key]; + $(args.$form.find('input[name="value"]')).autocomplete({ + minLength: 0, + delay: 0, + autoFocus: true, + source: options.sort() + }).focus(function() { + $(this).data("uiAutocomplete").search($(this).val()); + }); + } + }).focus(function() { + $(this).data("uiAutocomplete").search($(this).val()); + }); + } + }); + + return true; + }, + fields: { + name: { + label: 'label.name', + validation: { + required: true + } + }, + value: { + label: 'label.value', + validation: { + required: true + } + } + } + }, + action: actions.add + } }, - dataProvider: dataProvider + dataProvider: function(args) { + dataProvider(args); + var data = { + resourcetype: resourceType + }; + if (resourceType === 'UserVm') { + data.resourceid = args.context.instances[0].id; + } + if (resourceType === 'Template') { + data.resourceid = args.context.templates[0].id; + } + $.ajax({ + url: createURL("listDetailOptions"), + data: data, + dataType: "json", + success: function(json) { + var details = json.listdetailoptionsresponse.detailoptions.details; + var tbody = $.find('#details-tab-settings .data-table tbody'); + $(tbody).on('DOMNodeInserted', "tr", function() { + $.each($.find('#details-tab-settings .data-table tbody tr'), function(idx, row) { + const key = $(row).find('td.name').attr('title'); + const options = details[key]; + if (options) { + $($(row).find('input.edit')).autocomplete({ + minLength: 0, + delay: 0, + autoFocus: true, + source: options.sort() + }).focus(function() { + $(this).data("uiAutocomplete").search($(this).val()); + }); + $(row).find('input.edit').blur(); + } + }); + }); + } + }); + } }; var $listView = $('
').listView({ @@ -138,4 +222,4 @@ return $listView; } }; -}(jQuery, cloudStack)); \ No newline at end of file +}(jQuery, cloudStack));