mirror of https://github.com/apache/cloudstack.git
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:
parent
f9998e418c
commit
9f4f2c5348
|
|
@ -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";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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() {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -168,7 +168,6 @@
|
|||
}],
|
||||
dataProvider: function(args) {
|
||||
var items = [];
|
||||
console.log(args);
|
||||
$.ajax({
|
||||
url: createURL("listLdapConfigurations&hostname=" + args.context.ldapConfiguration[0].hostname),
|
||||
dataType: "json",
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2170,6 +2170,7 @@
|
|||
settings: {
|
||||
title: 'label.settings',
|
||||
custom: cloudStack.uiCustom.granularDetails({
|
||||
resourceType: 'Template',
|
||||
dataProvider: function(args) {
|
||||
$.ajax({
|
||||
url: createURL('listTemplates'),
|
||||
|
|
|
|||
|
|
@ -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));
|
||||
|
|
|
|||
Loading…
Reference in New Issue