Skip to content

Commit 8cfabb9

Browse files
committed
api: instance and template details are free text
Problem: Users don't know what keys/values to enter for template and VM details. Root Cause: The feature does not exist that can list possible details and options. Solution: Based on the possible VM and template details handled by the codebase, those details were refactored and a list API is introduced that can return users those details along with possible values. When users add details now, they will be presented with a list of key details and their possible options if any. Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
1 parent 671a70a commit 8cfabb9

23 files changed

Lines changed: 478 additions & 159 deletions

File tree

api/src/main/java/com/cloud/vm/VmDetailConstants.java

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,14 +17,41 @@
1717
package com.cloud.vm;
1818

1919
public interface VmDetailConstants {
20-
public static final String KEYBOARD = "keyboard";
21-
public static final String NIC_ADAPTER = "nicAdapter";
22-
public static final String ROOT_DISK_CONTROLLER = "rootDiskController";
23-
public static final String NESTED_VIRTUALIZATION_FLAG = "nestedVirtualizationFlag";
24-
public static final String HYPERVISOR_TOOLS_VERSION = "hypervisortoolsversion";
25-
public static final String DATA_DISK_CONTROLLER = "dataDiskController";
26-
public static final String SVGA_VRAM_SIZE = "svga.vramSize";
27-
public static final String CPU_NUMBER = "cpuNumber";
28-
public static final String CPU_SPEED = "cpuSpeed";
29-
public static final String MEMORY = "memory";
20+
String KEYBOARD = "keyboard";
21+
String CPU_CORE_PER_SOCKET = "cpu.corespersocket";
22+
23+
// VMware specific
24+
String NIC_ADAPTER = "nicAdapter";
25+
String ROOT_DISK_CONTROLLER = "rootDiskController";
26+
String DATA_DISK_CONTROLLER = "dataDiskController";
27+
String SVGA_VRAM_SIZE = "svga.vramSize";
28+
String NESTED_VIRTUALIZATION_FLAG = "nestedVirtualizationFlag";
29+
30+
// XenServer specific (internal)
31+
String HYPERVISOR_TOOLS_VERSION = "hypervisortoolsversion";
32+
String PLATFORM = "platform";
33+
String TIME_OFFSET = "timeoffset";
34+
35+
// KVM specific (internal)
36+
String KVM_VNC_PORT = "kvm.vnc.port";
37+
String KVM_VNC_ADDRESS = "kvm.vnc.address";
38+
39+
// Mac OSX guest specific (internal)
40+
String SMC_PRESENT = "smc.present";
41+
String FIRMWARE = "firmware";
42+
43+
// VM deployment with custom compute offering params
44+
String CPU_NUMBER = "cpuNumber";
45+
String CPU_SPEED = "cpuSpeed";
46+
String MEMORY = "memory";
47+
48+
// Misc details for internal usage (not to be set/changed by user or admin)
49+
String CPU_OVER_COMMIT_RATIO = "cpuOvercommitRatio";
50+
String MEMORY_OVER_COMMIT_RATIO = "memoryOvercommitRatio";
51+
String MESSAGE_RESERVED_CAPACITY_FREED_FLAG = "Message.ReservedCapacityFreed.Flag";
52+
String DEPLOY_VM = "deployvm";
53+
String ROOT_DISK_SIZE = "rootdisksize";
54+
String SSH_PUBLIC_KEY = "SSH.PublicKey";
55+
String PASSWORD = "password";
56+
String ENCRYPTED_PASSWORD = "Encrypted.Password";
3057
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.api.command.user.resource;
18+
19+
import org.apache.cloudstack.api.APICommand;
20+
import org.apache.cloudstack.api.ApiArgValidator;
21+
import org.apache.cloudstack.api.ApiConstants;
22+
import org.apache.cloudstack.api.BaseCmd;
23+
import org.apache.cloudstack.api.Parameter;
24+
import org.apache.cloudstack.api.response.DetailOptionsResponse;
25+
import org.apache.cloudstack.context.CallContext;
26+
27+
import com.cloud.server.ResourceTag;
28+
import com.google.common.base.Strings;
29+
30+
@APICommand(name = ListDetailOptionsCmd.APINAME,
31+
description = "Lists all possible details and their options for a resource type such as a VM or a template",
32+
responseObject = DetailOptionsResponse.class,
33+
since = "4.13",
34+
requestHasSensitiveInfo = false,
35+
responseHasSensitiveInfo = false)
36+
public class ListDetailOptionsCmd extends BaseCmd {
37+
public final static String APINAME = "listDetailOptions";
38+
39+
/////////////////////////////////////////////////////
40+
//////////////// API parameters /////////////////////
41+
/////////////////////////////////////////////////////
42+
43+
@Parameter(name = ApiConstants.RESOURCE_TYPE, type = CommandType.STRING, required = true,
44+
description = "the resource type such as UserVm, Template etc.",
45+
validations = {ApiArgValidator.NotNullOrEmpty}
46+
)
47+
private String resourceType;
48+
49+
@Parameter(name = ApiConstants.RESOURCE_ID, type = CommandType.STRING,
50+
description = "the UUID of the resource (optional)")
51+
private String resourceId;
52+
53+
/////////////////////////////////////////////////////
54+
/////////////////// Accessors ///////////////////////
55+
/////////////////////////////////////////////////////
56+
57+
public ResourceTag.ResourceObjectType getResourceType() {
58+
return _taggedResourceService.getResourceType(resourceType);
59+
}
60+
61+
public String getResourceId() {
62+
if (!Strings.isNullOrEmpty(resourceId)) {
63+
return _taggedResourceService.getUuid(resourceId, getResourceType());
64+
}
65+
return null;
66+
}
67+
68+
/////////////////////////////////////////////////////
69+
/////////////////// Implementation //////////////////
70+
/////////////////////////////////////////////////////
71+
72+
@Override
73+
public String getCommandName() {
74+
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
75+
}
76+
77+
@Override
78+
public long getEntityOwnerId() {
79+
return CallContext.current().getCallingAccountId();
80+
}
81+
82+
@Override
83+
public void execute() {
84+
final DetailOptionsResponse response = _queryService.listDetailOptions(this);
85+
response.setResponseName(getCommandName());
86+
response.setObjectName("detailoptions");
87+
setResponseObject(response);
88+
}
89+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.api.response;
18+
19+
import java.util.List;
20+
import java.util.Map;
21+
22+
import org.apache.cloudstack.api.ApiConstants;
23+
import org.apache.cloudstack.api.BaseResponse;
24+
25+
import com.cloud.serializer.Param;
26+
import com.google.gson.annotations.SerializedName;
27+
28+
public class DetailOptionsResponse extends BaseResponse {
29+
@SerializedName(ApiConstants.DETAILS)
30+
@Param(description = "Map of all possible details and their possible list of values")
31+
private Map<String, List<String>> details;
32+
33+
public DetailOptionsResponse(Map<String, List<String>> details) {
34+
this.details = details;
35+
}
36+
37+
public void setDetails(Map<String, List<String>> details) {
38+
this.details = details;
39+
}
40+
41+
public Map<String, List<String>> getDetails() {
42+
return details;
43+
}
44+
}

api/src/main/java/org/apache/cloudstack/query/QueryService.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@
2020

2121
import org.apache.cloudstack.affinity.AffinityGroupResponse;
2222
import org.apache.cloudstack.api.command.admin.domain.ListDomainsCmd;
23-
import org.apache.cloudstack.api.command.admin.host.ListHostsCmd;
2423
import org.apache.cloudstack.api.command.admin.host.ListHostTagsCmd;
24+
import org.apache.cloudstack.api.command.admin.host.ListHostsCmd;
2525
import org.apache.cloudstack.api.command.admin.internallb.ListInternalLBVMsCmd;
2626
import org.apache.cloudstack.api.command.admin.management.ListMgmtsCmd;
2727
import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd;
@@ -40,6 +40,7 @@
4040
import org.apache.cloudstack.api.command.user.offering.ListServiceOfferingsCmd;
4141
import org.apache.cloudstack.api.command.user.project.ListProjectInvitationsCmd;
4242
import org.apache.cloudstack.api.command.user.project.ListProjectsCmd;
43+
import org.apache.cloudstack.api.command.user.resource.ListDetailOptionsCmd;
4344
import org.apache.cloudstack.api.command.user.securitygroup.ListSecurityGroupsCmd;
4445
import org.apache.cloudstack.api.command.user.tag.ListTagsCmd;
4546
import org.apache.cloudstack.api.command.user.template.ListTemplatesCmd;
@@ -50,6 +51,7 @@
5051
import org.apache.cloudstack.api.command.user.zone.ListZonesCmd;
5152
import org.apache.cloudstack.api.response.AccountResponse;
5253
import org.apache.cloudstack.api.response.AsyncJobResponse;
54+
import org.apache.cloudstack.api.response.DetailOptionsResponse;
5355
import org.apache.cloudstack.api.response.DiskOfferingResponse;
5456
import org.apache.cloudstack.api.response.DomainResponse;
5557
import org.apache.cloudstack.api.response.DomainRouterResponse;
@@ -134,6 +136,8 @@ public interface QueryService {
134136

135137
ListResponse<TemplateResponse> listIsos(ListIsosCmd cmd);
136138

139+
DetailOptionsResponse listDetailOptions(ListDetailOptionsCmd cmd);
140+
137141
ListResponse<AffinityGroupResponse> searchForAffinityGroups(ListAffinityGroupsCmd cmd);
138142

139143
List<ResourceDetailResponse> listResourceDetails(ListResourceDetailsCmd cmd);

engine/orchestration/src/main/java/com/cloud/vm/VirtualMachineManagerImpl.java

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1071,16 +1071,16 @@ public void orchestrateStart(final String vmUuid, final Map<VirtualMachineProfil
10711071
long destHostId = dest.getHost().getId();
10721072
vm.setPodIdToDeployIn(dest.getPod().getId());
10731073
final Long cluster_id = dest.getCluster().getId();
1074-
final ClusterDetailsVO cluster_detail_cpu = _clusterDetailsDao.findDetail(cluster_id, "cpuOvercommitRatio");
1075-
final ClusterDetailsVO cluster_detail_ram = _clusterDetailsDao.findDetail(cluster_id, "memoryOvercommitRatio");
1076-
//storing the value of overcommit in the vm_details table for doing a capacity check in case the cluster overcommit ratio is changed.
1077-
if (userVmDetailsDao.findDetail(vm.getId(), "cpuOvercommitRatio") == null &&
1074+
final ClusterDetailsVO cluster_detail_cpu = _clusterDetailsDao.findDetail(cluster_id, VmDetailConstants.CPU_OVER_COMMIT_RATIO);
1075+
final ClusterDetailsVO cluster_detail_ram = _clusterDetailsDao.findDetail(cluster_id, VmDetailConstants.MEMORY_OVER_COMMIT_RATIO);
1076+
//storing the value of overcommit in the user_vm_details table for doing a capacity check in case the cluster overcommit ratio is changed.
1077+
if (userVmDetailsDao.findDetail(vm.getId(), VmDetailConstants.CPU_OVER_COMMIT_RATIO) == null &&
10781078
(Float.parseFloat(cluster_detail_cpu.getValue()) > 1f || Float.parseFloat(cluster_detail_ram.getValue()) > 1f)) {
1079-
userVmDetailsDao.addDetail(vm.getId(), "cpuOvercommitRatio", cluster_detail_cpu.getValue(), true);
1080-
userVmDetailsDao.addDetail(vm.getId(), "memoryOvercommitRatio", cluster_detail_ram.getValue(), true);
1081-
} else if (userVmDetailsDao.findDetail(vm.getId(), "cpuOvercommitRatio") != null) {
1082-
userVmDetailsDao.addDetail(vm.getId(), "cpuOvercommitRatio", cluster_detail_cpu.getValue(), true);
1083-
userVmDetailsDao.addDetail(vm.getId(), "memoryOvercommitRatio", cluster_detail_ram.getValue(), true);
1079+
userVmDetailsDao.addDetail(vm.getId(), VmDetailConstants.CPU_OVER_COMMIT_RATIO, cluster_detail_cpu.getValue(), true);
1080+
userVmDetailsDao.addDetail(vm.getId(), VmDetailConstants.MEMORY_OVER_COMMIT_RATIO, cluster_detail_ram.getValue(), true);
1081+
} else if (userVmDetailsDao.findDetail(vm.getId(), VmDetailConstants.CPU_OVER_COMMIT_RATIO) != null) {
1082+
userVmDetailsDao.addDetail(vm.getId(), VmDetailConstants.CPU_OVER_COMMIT_RATIO, cluster_detail_cpu.getValue(), true);
1083+
userVmDetailsDao.addDetail(vm.getId(), VmDetailConstants.MEMORY_OVER_COMMIT_RATIO, cluster_detail_ram.getValue(), true);
10841084
}
10851085

10861086
vmProfile.setCpuOvercommitRatio(Float.parseFloat(cluster_detail_cpu.getValue()));
@@ -1162,8 +1162,8 @@ public void orchestrateStart(final String vmUuid, final Map<VirtualMachineProfil
11621162
// Remove the information on whether it was a deploy vm request.The deployvm=true information
11631163
// is set only when the vm is being deployed. When a vm is started from a stop state the
11641164
// information isn't set,
1165-
if (userVmDetailsDao.findDetail(vm.getId(), "deployvm") != null) {
1166-
userVmDetailsDao.removeDetail(vm.getId(), "deployvm");
1165+
if (userVmDetailsDao.findDetail(vm.getId(), VmDetailConstants.DEPLOY_VM) != null) {
1166+
userVmDetailsDao.removeDetail(vm.getId(), VmDetailConstants.DEPLOY_VM);
11671167
}
11681168

11691169
startedVm = vm;
@@ -1466,7 +1466,7 @@ protected boolean sendStop(final VirtualMachineGuru guru, final VirtualMachinePr
14661466
if (platform != null) {
14671467
final UserVmVO userVm = _userVmDao.findById(vm.getId());
14681468
_userVmDao.loadDetails(userVm);
1469-
userVm.setDetail("platform", platform);
1469+
userVm.setDetail(VmDetailConstants.PLATFORM, platform);
14701470
_userVmDao.saveDetails(userVm);
14711471
}
14721472
}
@@ -1742,7 +1742,7 @@ private void advanceStop(final VMInstanceVO vm, final boolean cleanUpEvenIfUnabl
17421742
if (platform != null) {
17431743
final UserVmVO userVm = _userVmDao.findById(vm.getId());
17441744
_userVmDao.loadDetails(userVm);
1745-
userVm.setDetail("platform", platform);
1745+
userVm.setDetail(VmDetailConstants.PLATFORM, platform);
17461746
_userVmDao.saveDetails(userVm);
17471747
}
17481748
}
@@ -3179,16 +3179,16 @@ public void syncVMMetaData(final Map<String, String> vmMetadatum) {
31793179
private void updateVmMetaData(Long vmId, String platform) {
31803180
UserVmVO userVm = _userVmDao.findById(vmId);
31813181
_userVmDao.loadDetails(userVm);
3182-
if ( userVm.details.containsKey("timeoffset")) {
3183-
userVm.details.remove("timeoffset");
3182+
if ( userVm.details.containsKey(VmDetailConstants.TIME_OFFSET)) {
3183+
userVm.details.remove(VmDetailConstants.TIME_OFFSET);
31843184
}
3185-
userVm.setDetail("platform", platform);
3185+
userVm.setDetail(VmDetailConstants.PLATFORM, platform);
31863186
String pvdriver = "xenserver56";
31873187
if ( platform.contains("device_id")) {
31883188
pvdriver = "xenserver61";
31893189
}
3190-
if (!userVm.details.containsKey("hypervisortoolsversion") || !userVm.details.get("hypervisortoolsversion").equals(pvdriver)) {
3191-
userVm.setDetail("hypervisortoolsversion", pvdriver);
3190+
if (!userVm.details.containsKey(VmDetailConstants.HYPERVISOR_TOOLS_VERSION) || !userVm.details.get(VmDetailConstants.HYPERVISOR_TOOLS_VERSION).equals(pvdriver)) {
3191+
userVm.setDetail(VmDetailConstants.HYPERVISOR_TOOLS_VERSION, pvdriver);
31923192
}
31933193
_userVmDao.saveDetails(userVm);
31943194
}

plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1876,7 +1876,7 @@ protected StartAnswer execute(StartCommand cmd) {
18761876

18771877
// Check for multi-cores per socket settings
18781878
int numCoresPerSocket = 1;
1879-
String coresPerSocket = vmSpec.getDetails().get("cpu.corespersocket");
1879+
String coresPerSocket = vmSpec.getDetails().get(VmDetailConstants.CPU_CORE_PER_SOCKET);
18801880
if (coresPerSocket != null) {
18811881
String apiVersion = HypervisorHostHelper.getVcenterApiVersion(vmMo.getContext());
18821882
// Property 'numCoresPerSocket' is supported since vSphere API 5.0

plugins/hypervisors/xenserver/src/main/java/com/cloud/hypervisor/xenserver/resource/CitrixResourceBase.java

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@
134134
import com.cloud.utils.ssh.SshHelper;
135135
import com.cloud.vm.VirtualMachine;
136136
import com.cloud.vm.VirtualMachine.PowerState;
137+
import com.cloud.vm.VmDetailConstants;
137138
import com.trilead.ssh2.SCPClient;
138139
import com.xensource.xenapi.Bond;
139140
import com.xensource.xenapi.Connection;
@@ -1870,26 +1871,26 @@ protected void finalizeVmMetaData(final VM vm, final Connection conn, final Virt
18701871

18711872
final Map<String, String> details = vmSpec.getDetails();
18721873
if (details != null) {
1873-
final String platformstring = details.get("platform");
1874+
final String platformstring = details.get(VmDetailConstants.PLATFORM);
18741875
if (platformstring != null && !platformstring.isEmpty()) {
18751876
final Map<String, String> platform = StringUtils.stringToMap(platformstring);
18761877
vm.setPlatform(conn, platform);
18771878
} else {
1878-
final String timeoffset = details.get("timeoffset");
1879+
final String timeoffset = details.get(VmDetailConstants.TIME_OFFSET);
18791880
if (timeoffset != null) {
18801881
final Map<String, String> platform = vm.getPlatform(conn);
1881-
platform.put("timeoffset", timeoffset);
1882+
platform.put(VmDetailConstants.TIME_OFFSET, timeoffset);
18821883
vm.setPlatform(conn, platform);
18831884
}
1884-
final String coresPerSocket = details.get("cpu.corespersocket");
1885+
final String coresPerSocket = details.get(VmDetailConstants.CPU_CORE_PER_SOCKET);
18851886
if (coresPerSocket != null) {
18861887
final Map<String, String> platform = vm.getPlatform(conn);
18871888
platform.put("cores-per-socket", coresPerSocket);
18881889
vm.setPlatform(conn, platform);
18891890
}
18901891
}
18911892
if (!BootloaderType.CD.equals(vmSpec.getBootloader())) {
1892-
final String xenservertoolsversion = details.get("hypervisortoolsversion");
1893+
final String xenservertoolsversion = details.get(VmDetailConstants.HYPERVISOR_TOOLS_VERSION);
18931894
if ((xenservertoolsversion == null || !xenservertoolsversion.equalsIgnoreCase("xenserver61")) && vmSpec.getGpuDevice() == null) {
18941895
final Map<String, String> platform = vm.getPlatform(conn);
18951896
platform.remove("device_id");

server/src/main/java/com/cloud/api/ApiDBUtils.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,7 @@
302302
import com.cloud.vm.UserVmVO;
303303
import com.cloud.vm.VMInstanceVO;
304304
import com.cloud.vm.VirtualMachine;
305+
import com.cloud.vm.VmDetailConstants;
305306
import com.cloud.vm.VmStats;
306307
import com.cloud.vm.dao.ConsoleProxyDao;
307308
import com.cloud.vm.dao.DomainRouterDao;
@@ -1454,7 +1455,7 @@ public static String getKeyPairName(String sshPublicKey) {
14541455
}
14551456

14561457
public static UserVmDetailVO findPublicKeyByVmId(long vmId) {
1457-
return s_userVmDetailsDao.findDetail(vmId, "SSH.PublicKey");
1458+
return s_userVmDetailsDao.findDetail(vmId, VmDetailConstants.SSH_PUBLIC_KEY);
14581459
}
14591460

14601461
public static void getAutoScaleVmGroupPolicies(long vmGroupId, List<AutoScalePolicy> scaleUpPolicies, List<AutoScalePolicy> scaleDownPolicies) {

0 commit comments

Comments
 (0)