api: instance and template details are free text (#3240)

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>
This commit is contained in:
Rohit Yadav 2019-06-27 09:14:47 +05:30 committed by GitHub
parent f9998e418c
commit 9f4f2c5348
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 548 additions and 165 deletions

View File

@ -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";
String ROOT_DISK_SIZE = "rootdisksize";
// 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 SSH_PUBLIC_KEY = "SSH.PublicKey";
String PASSWORD = "password";
String ENCRYPTED_PASSWORD = "Encrypted.Password";
}

View File

@ -0,0 +1,91 @@
// 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.acl.RoleType;
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,
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
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);
}
}

View File

@ -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<String, List<String>> details;
public DetailOptionsResponse(Map<String, List<String>> details) {
this.details = details;
}
public void setDetails(Map<String, List<String>> details) {
this.details = details;
}
public Map<String, List<String>> getDetails() {
return details;
}
}

View File

@ -20,8 +20,8 @@ import java.util.List;
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.ListDiskOfferingsCmd;
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.volume.ListVolumesCmd;
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;
@ -147,6 +149,8 @@ public interface QueryService {
ListResponse<TemplateResponse> listIsos(ListIsosCmd cmd);
DetailOptionsResponse listDetailOptions(ListDetailOptionsCmd cmd);
ListResponse<AffinityGroupResponse> searchForAffinityGroups(ListAffinityGroupsCmd cmd);
List<ResourceDetailResponse> listResourceDetails(ListResourceDetailsCmd cmd);

View File

@ -1071,16 +1071,16 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
long destHostId = dest.getHost().getId();
vm.setPodIdToDeployIn(dest.getPod().getId());
final Long cluster_id = dest.getCluster().getId();
final ClusterDetailsVO cluster_detail_cpu = _clusterDetailsDao.findDetail(cluster_id, "cpuOvercommitRatio");
final ClusterDetailsVO cluster_detail_ram = _clusterDetailsDao.findDetail(cluster_id, "memoryOvercommitRatio");
//storing the value of overcommit in the vm_details table for doing a capacity check in case the cluster overcommit ratio is changed.
if (userVmDetailsDao.findDetail(vm.getId(), "cpuOvercommitRatio") == null &&
final ClusterDetailsVO cluster_detail_cpu = _clusterDetailsDao.findDetail(cluster_id, VmDetailConstants.CPU_OVER_COMMIT_RATIO);
final ClusterDetailsVO cluster_detail_ram = _clusterDetailsDao.findDetail(cluster_id, VmDetailConstants.MEMORY_OVER_COMMIT_RATIO);
//storing the value of overcommit in the user_vm_details table for doing a capacity check in case the cluster overcommit ratio is changed.
if (userVmDetailsDao.findDetail(vm.getId(), VmDetailConstants.CPU_OVER_COMMIT_RATIO) == null &&
(Float.parseFloat(cluster_detail_cpu.getValue()) > 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()));
@ -1160,8 +1160,8 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
// Remove the information on whether it was a deploy vm request.The deployvm=true information
// is set only when the vm is being deployed. When a vm is started from a stop state the
// information isn't set,
if (userVmDetailsDao.findDetail(vm.getId(), "deployvm") != null) {
userVmDetailsDao.removeDetail(vm.getId(), "deployvm");
if (userVmDetailsDao.findDetail(vm.getId(), VmDetailConstants.DEPLOY_VM) != null) {
userVmDetailsDao.removeDetail(vm.getId(), VmDetailConstants.DEPLOY_VM);
}
startedVm = vm;
@ -1455,7 +1455,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
if (platform != null) {
final UserVmVO userVm = _userVmDao.findById(vm.getId());
_userVmDao.loadDetails(userVm);
userVm.setDetail("platform", platform);
userVm.setDetail(VmDetailConstants.PLATFORM, platform);
_userVmDao.saveDetails(userVm);
}
}
@ -1731,7 +1731,7 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
if (platform != null) {
final UserVmVO userVm = _userVmDao.findById(vm.getId());
_userVmDao.loadDetails(userVm);
userVm.setDetail("platform", platform);
userVm.setDetail(VmDetailConstants.PLATFORM, platform);
_userVmDao.saveDetails(userVm);
}
}
@ -3174,16 +3174,16 @@ public class VirtualMachineManagerImpl extends ManagerBase implements VirtualMac
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);
}

View File

@ -1874,7 +1874,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa
// 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

View File

@ -134,6 +134,7 @@ import com.cloud.utils.ssh.SSHCmdHelper;
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;
@ -1862,18 +1863,18 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
final Map<String, String> 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<String, String> 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<String, String> 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<String, String> platform = vm.getPlatform(conn);
platform.put("cores-per-socket", coresPerSocket);
@ -1881,7 +1882,7 @@ public abstract class CitrixResourceBase implements ServerResource, HypervisorRe
}
}
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<String, String> platform = vm.getPlatform(conn);
platform.remove("device_id");

View File

@ -302,6 +302,7 @@ import com.cloud.vm.UserVmManager;
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 class ApiDBUtils {
}
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<AutoScalePolicy> scaleUpPolicies, List<AutoScalePolicy> scaleDownPolicies) {

View File

@ -17,11 +17,16 @@
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;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.inject.Inject;
@ -61,6 +66,7 @@ import org.apache.cloudstack.api.command.user.offering.ListDiskOfferingsCmd;
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;
@ -71,6 +77,7 @@ import org.apache.cloudstack.api.command.user.volume.ListVolumesCmd;
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;
@ -212,13 +219,16 @@ import com.cloud.utils.db.SearchBuilder;
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.VMInstanceDao;
import com.google.common.base.Strings;
@Component
public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements QueryService, Configurable {
@ -3381,6 +3391,61 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
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<String, List<String>> 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.");
}
if (CallContext.current().getCallingAccount().getType() != Account.ACCOUNT_TYPE_ADMIN) {
final List<String> userBlacklistedSettings = Stream.of(QueryService.UserVMBlacklistedDetails.value().split(","))
.map(item -> (item).trim())
.collect(Collectors.toList());
for (final String detail : userBlacklistedSettings) {
if (options.containsKey(detail)) {
options.remove(detail);
}
}
}
return new DetailOptionsResponse(options);
}
private void fillVMOrTemplateDetailOptions(final Map<String, List<String>> 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());
options.put(VmDetailConstants.ROOT_DISK_SIZE, Collections.emptyList());
if (HypervisorType.KVM.equals(hypervisorType)) {
options.put(VmDetailConstants.ROOT_DISK_CONTROLLER, Arrays.asList("osdefault", "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<AffinityGroupResponse> searchForAffinityGroups(ListAffinityGroupsCmd cmd) {
Pair<List<AffinityGroupJoinVO>, Integer> result = searchForAffinityGroupsInternal(cmd);
@ -3687,7 +3752,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q
}
response.setResponses(result);
return response;
}
}
@Override
public String getConfigComponentName() {

View File

@ -89,6 +89,7 @@ import com.cloud.vm.VMInstanceVO;
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<String, Object> params) throws ConfigurationException {
_vmCapacityReleaseInterval = NumbersUtil.parseInt(_configDao.getValue(Config.CapacitySkipcountingHours.key()), 3600);
@ -638,8 +637,8 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager,
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());
@ -669,14 +668,14 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager,
} 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);
}
}
@ -903,7 +902,7 @@ public class CapacityManagerImpl extends ManagerBase implements CapacityManager,
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);
}

View File

@ -77,6 +77,7 @@ import com.cloud.vm.UserVmVO;
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 class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
}
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 @@ public class ConfigDriveNetworkElement extends AdapterBase implements NetworkEle
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);

View File

@ -31,6 +31,7 @@ import org.cloud.network.router.deployment.RouterDeploymentDefinitionBuilder;
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 @@ NetworkMigrationResponder, AggregatedCommandExecutor, RedundantResource, DnsServ
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);

View File

@ -31,13 +31,6 @@ import java.util.concurrent.ConcurrentHashMap;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
import com.cloud.utils.Pair;
import com.cloud.vm.dao.UserVmDetailsDao;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.commons.lang.ObjectUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.command.admin.cluster.AddClusterCmd;
import org.apache.cloudstack.api.command.admin.cluster.DeleteClusterCmd;
@ -49,21 +42,25 @@ import org.apache.cloudstack.api.command.admin.host.ReconnectHostCmd;
import org.apache.cloudstack.api.command.admin.host.UpdateHostCmd;
import org.apache.cloudstack.api.command.admin.host.UpdateHostPasswordCmd;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
import org.apache.cloudstack.utils.identity.ManagementServerNode;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang.ObjectUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.agent.AgentManager;
import com.cloud.agent.api.Answer;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.GetVncPortCommand;
import com.cloud.agent.api.GetVncPortAnswer;
import com.cloud.agent.api.GetGPUStatsAnswer;
import com.cloud.agent.api.GetGPUStatsCommand;
import com.cloud.agent.api.GetHostStatsAnswer;
import com.cloud.agent.api.GetHostStatsCommand;
import com.cloud.agent.api.GetVncPortAnswer;
import com.cloud.agent.api.GetVncPortCommand;
import com.cloud.agent.api.MaintainAnswer;
import com.cloud.agent.api.MaintainCommand;
import com.cloud.agent.api.PropagateResourceEventCommand;
@ -148,6 +145,7 @@ import com.cloud.storage.dao.StoragePoolHostDao;
import com.cloud.storage.dao.VMTemplateDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.utils.Pair;
import com.cloud.utils.StringUtils;
import com.cloud.utils.UriUtils;
import com.cloud.utils.component.Manager;
@ -177,6 +175,8 @@ import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.State;
import com.cloud.vm.VirtualMachineManager;
import com.cloud.vm.VmDetailConstants;
import com.cloud.vm.dao.UserVmDetailsDao;
import com.cloud.vm.dao.VMInstanceDao;
import com.google.gson.Gson;
@ -1314,8 +1314,8 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
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);
}
}
}

View File

@ -411,6 +411,7 @@ import org.apache.cloudstack.api.command.user.region.ha.gslb.ListGlobalLoadBalan
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;
@ -2900,6 +2901,7 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
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);

View File

@ -41,6 +41,7 @@ import org.apache.log4j.Logger;
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 @@ public class ConsoleProxyServlet extends HttpServlet {
Pair<String, Integer> 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 @@ public class ConsoleProxyServlet extends HttpServlet {
}
String sid = vm.getVncPassword();
UserVmDetailVO details = _userVmDetailsDao.findDetail(vm.getId(), "keyboard");
UserVmDetailVO details = _userVmDetailsDao.findDetail(vm.getId(), VmDetailConstants.KEYBOARD);
String tag = vm.getUuid();

View File

@ -39,6 +39,7 @@ import com.cloud.utils.EncryptionUtil;
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;
@ -1918,7 +1919,7 @@ public class TemplateManagerImpl extends ManagerBase implements TemplateManager,
}
}
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()) {

View File

@ -35,6 +35,7 @@ import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import javax.inject.Inject;
import javax.naming.ConfigurationException;
@ -85,6 +86,7 @@ import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.managed.context.ManagedContextRunnable;
import org.apache.cloudstack.query.QueryService;
import org.apache.cloudstack.storage.command.DeleteCommand;
import org.apache.cloudstack.storage.command.DettachCommand;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
@ -847,7 +849,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
} 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
@ -2426,11 +2428,36 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
if (isDisplayVm != null && isDisplayVm != vmInstance.isDisplay()) {
updateDisplayVmFlag(isDisplayVm, id, vmInstance);
}
final Account caller = CallContext.current().getCallingAccount();
final List<String> userBlacklistedSettings = Stream.of(QueryService.UserVMBlacklistedDetails.value().split(","))
.map(item -> (item).trim())
.collect(Collectors.toList());
if (cleanupDetails){
userVmDetailsDao.removeDetails(id);
}
else {
if (caller != null && caller.getType() == Account.ACCOUNT_TYPE_ADMIN) {
userVmDetailsDao.removeDetails(id);
} else {
for (final UserVmDetailVO detail : userVmDetailsDao.listDetails(id)) {
if (detail != null && !userBlacklistedSettings.contains(detail.getName())) {
userVmDetailsDao.removeDetail(id, detail.getName());
}
}
}
} else {
if (MapUtils.isNotEmpty(details)) {
if (caller != null && caller.getType() != Account.ACCOUNT_TYPE_ADMIN) {
// Ensure blacklisted detail is not passed by non-root-admin user
for (final String detailName : details.keySet()) {
if (userBlacklistedSettings.contains(detailName)) {
throw new InvalidParameterValueException("You're not allowed to add or edit the restricted setting: " + detailName);
}
}
// Add any hidden/blacklisted detail
for (final UserVmDetailVO detail : userVmDetailsDao.listDetails(id)) {
if (userBlacklistedSettings.contains(detail.getName())) {
details.put(detail.getName(), detail.getValue());
}
}
}
vmInstance.setDetails(details);
_vmDao.saveDetails(vmInstance);
}
@ -3379,13 +3406,13 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
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.");
}
@ -3768,7 +3795,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
if (sshPublicKey != null) {
vm.setDetail("SSH.PublicKey", sshPublicKey);
vm.setDetail(VmDetailConstants.SSH_PUBLIC_KEY, sshPublicKey);
}
if (keyboard != null && !keyboard.isEmpty()) {
@ -3780,9 +3807,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
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) {
@ -3806,10 +3833,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
// 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");
@ -3838,7 +3865,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
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");
@ -3888,10 +3915,10 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
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 {
@ -3899,7 +3926,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
} 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);
}
}
@ -4182,7 +4209,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
boolean isWindows = _guestOSCategoryDao.findById(_guestOSDao.findById(vm.getGuestOSId()).getCategoryId()).getName().equalsIgnoreCase("Windows");
List<String[]> 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";
@ -4574,8 +4601,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
// 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);
@ -6334,7 +6361,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
if (needRestart) {
try {
if (vm.getDetail("password") != null) {
if (vm.getDetail(VmDetailConstants.PASSWORD) != null) {
params = new HashMap<VirtualMachineProfile.Param, Object>();
params.put(VirtualMachineProfile.Param.VmPassword, password);
}
@ -6347,8 +6374,8 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
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);
}
@ -6526,7 +6553,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
}
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.");
@ -6537,7 +6564,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
throw new CloudRuntimeException("Error encrypting password");
}
vm.setDetail("Encrypted.Password", encryptedPasswd);
vm.setDetail(VmDetailConstants.ENCRYPTED_PASSWORD, encryptedPasswd);
_vmDao.saveDetails(vm);
}
}
@ -6569,7 +6596,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir
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);

View File

@ -22,6 +22,7 @@ import java.util.HashMap;
import org.apache.cloudstack.api.BaseCmd.HTTPMethod;
import org.apache.cloudstack.api.command.user.vm.UpdateVMCmd;
import org.apache.cloudstack.context.CallContext;
import org.junit.After;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
@ -44,6 +45,8 @@ import com.cloud.storage.GuestOSVO;
import com.cloud.storage.dao.GuestOSDao;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.user.AccountVO;
import com.cloud.user.UserVO;
import com.cloud.uservm.UserVm;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.UserVmDetailsDao;
@ -76,6 +79,12 @@ public class UserVmManagerImplTest {
@Mock
private NetworkModel networkModel;
@Mock
private AccountVO callerAccount;
@Mock
private UserVO callerUser;
private long vmId = 1l;
@Before
@ -83,6 +92,14 @@ public class UserVmManagerImplTest {
Mockito.when(updateVmCommand.getId()).thenReturn(vmId);
Mockito.when(userVmDao.findById(Mockito.eq(vmId))).thenReturn(userVmVoMock);
Mockito.when(callerAccount.getType()).thenReturn(Account.ACCOUNT_TYPE_ADMIN);
CallContext.register(callerUser, callerAccount);
}
@After
public void afterTest() {
CallContext.unregister();
}
@Test

View File

@ -13015,6 +13015,29 @@ div.gpugroups div.list-view {
background: transparent url("../images/icons.png") no-repeat -626px -209px;
}
ul.ui-autocomplete.ui-menu {
width: 250px;
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;
}
.copy-template-destination-list div.text-search {
right: 5px;
}

View File

@ -168,7 +168,6 @@
}],
dataProvider: function(args) {
var items = [];
console.log(args);
$.ajax({
url: createURL("listLdapConfigurations&hostname=" + args.context.ldapConfiguration[0].hostname),
dataType: "json",

View File

@ -3329,6 +3329,7 @@
settings: {
title: 'label.settings',
custom: cloudStack.uiCustom.granularDetails({
resourceType: 'UserVm',
dataProvider: function(args) {
$.ajax({
url: createURL('listVirtualMachines&id=' + args.context.instances[0].id),
@ -3388,7 +3389,6 @@
// It could happen that a stale web page has been opened up when VM was stopped but
// vm was turned on through another route - UI or API. so we should check again.
var existingDetails = virtualMachine.details;
console.log(existingDetails);
var newDetails = {};
for (d in existingDetails) {
if (d != data.name) {

View File

@ -327,31 +327,24 @@
});
}
});
var setupAutocompletion = function() {
var $target = $($.find('input[name="rule"]'));
if ($target.hasClass('ui-autocomplete')) {
$target.autocomplete('destroy');
$.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());
});
}
$($.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();
}
});
}
});
}

View File

@ -2170,6 +2170,7 @@
settings: {
title: 'label.settings',
custom: cloudStack.uiCustom.granularDetails({
resourceType: 'Template',
dataProvider: function(args) {
$.ajax({
url: createURL('listTemplates'),

View File

@ -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,141 @@
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) {
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("");
});
$(row).find('input.edit').blur();
}
});
});
dataProvider(args);
}
});
}
};
var $listView = $('<div>').listView({
@ -138,4 +223,4 @@
return $listView;
}
};
}(jQuery, cloudStack));
}(jQuery, cloudStack));