in server/src/main/java/com/cloud/vm/UserVmManagerImpl.java [4174:4471]
private UserVm getUncheckedUserVmResource(DataCenter zone, String hostName, String displayName, Account owner,
Long diskOfferingId, Long diskSize, List<NetworkVO> networkList, List<Long> securityGroupIdList, String group,
HTTPMethod httpmethod, String userData, Long userDataId, String userDataDetails, List<String> sshKeyPairs,
Account caller, Map<Long, IpAddresses> requestedIps, IpAddresses defaultIps, Boolean isDisplayVm,
String keyboard, List<Long> affinityGroupIdList, Map<String, String> customParameters, String customId,
Map<String, Map<Integer, String>> dhcpOptionMap, Map<Long, DiskOffering> datadiskTemplateToDiskOfferringMap,
Map<String, String> userVmOVFPropertiesMap, boolean dynamicScalingEnabled, String vmType, VMTemplateVO template,
HypervisorType hypervisorType, long accountId, ServiceOfferingVO offering, boolean isIso,
Long rootDiskOfferingId, long volumesSize, long additionalDiskSize) throws ResourceAllocationException
{
List<String> rootResourceLimitStorageTags = getResourceLimitStorageTags(rootDiskOfferingId != null ? rootDiskOfferingId : offering.getDiskOfferingId());
List<String> additionalResourceLimitStorageTags = diskOfferingId != null ? getResourceLimitStorageTags(diskOfferingId) : null;
try (CheckedReservation rootVolumeReservation = new CheckedReservation(owner, ResourceType.volume, rootResourceLimitStorageTags, 1L, reservationDao, resourceLimitService);
CheckedReservation additionalVolumeReservation = diskOfferingId != null ? new CheckedReservation(owner, ResourceType.volume, additionalResourceLimitStorageTags, 1L, reservationDao, resourceLimitService) : null;
CheckedReservation rootPrimaryStorageReservation = new CheckedReservation(owner, ResourceType.primary_storage, rootResourceLimitStorageTags, volumesSize, reservationDao, resourceLimitService);
CheckedReservation additionalPrimaryStorageReservation = diskOfferingId != null ? new CheckedReservation(owner, ResourceType.primary_storage, additionalResourceLimitStorageTags, additionalDiskSize, reservationDao, resourceLimitService) : null;
) {
// verify security group ids
if (securityGroupIdList != null) {
for (Long securityGroupId : securityGroupIdList) {
SecurityGroup sg = _securityGroupDao.findById(securityGroupId);
if (sg == null) {
throw new InvalidParameterValueException("Unable to find security group by id " + securityGroupId);
} else {
// verify permissions
_accountMgr.checkAccess(caller, null, true, owner, sg);
}
}
}
if (datadiskTemplateToDiskOfferringMap != null && !datadiskTemplateToDiskOfferringMap.isEmpty()) {
for (Entry<Long, DiskOffering> datadiskTemplateToDiskOffering : datadiskTemplateToDiskOfferringMap.entrySet()) {
VMTemplateVO dataDiskTemplate = _templateDao.findById(datadiskTemplateToDiskOffering.getKey());
DiskOffering dataDiskOffering = datadiskTemplateToDiskOffering.getValue();
if (dataDiskTemplate == null
|| (!dataDiskTemplate.getTemplateType().equals(TemplateType.DATADISK)) && (dataDiskTemplate.getState().equals(VirtualMachineTemplate.State.Active))) {
throw new InvalidParameterValueException("Invalid template id specified for Datadisk template" + datadiskTemplateToDiskOffering.getKey());
}
long dataDiskTemplateId = datadiskTemplateToDiskOffering.getKey();
if (!dataDiskTemplate.getParentTemplateId().equals(template.getId())) {
throw new InvalidParameterValueException(String.format("Invalid Datadisk template. Specified Datadisk template %s doesn't belong to template %s", dataDiskTemplate, template));
}
if (dataDiskOffering == null) {
throw new InvalidParameterValueException(String.format("Invalid disk offering %s specified for datadisk template %s", datadiskTemplateToDiskOffering.getValue(), dataDiskTemplate));
}
if (dataDiskOffering.isCustomized()) {
throw new InvalidParameterValueException(String.format("Invalid disk offering %s specified for datadisk template %s. Custom Disk offerings are not supported for Datadisk templates", dataDiskOffering, dataDiskTemplate));
}
if (dataDiskOffering.getDiskSize() < dataDiskTemplate.getSize()) {
throw new InvalidParameterValueException(String.format("Invalid disk offering %s specified for datadisk template %s. Disk offering size should be greater than or equal to the template size", dataDiskOffering, dataDiskTemplate));
}
_templateDao.loadDetails(dataDiskTemplate);
resourceLimitService.checkVolumeResourceLimit(owner, true, dataDiskOffering.getDiskSize(), dataDiskOffering);
}
}
// check that the affinity groups exist
if (affinityGroupIdList != null) {
for (Long affinityGroupId : affinityGroupIdList) {
AffinityGroupVO ag = _affinityGroupDao.findById(affinityGroupId);
if (ag == null) {
throw new InvalidParameterValueException("Unable to find affinity group " + ag);
} else if (!_affinityGroupService.isAffinityGroupProcessorAvailable(ag.getType())) {
throw new InvalidParameterValueException("Affinity group type is not supported for group: " + ag + " ,type: " + ag.getType()
+ " , Please try again after removing the affinity group");
} else {
// verify permissions
if (ag.getAclType() == ACLType.Domain) {
_accountMgr.checkAccess(caller, null, false, owner, ag);
// Root admin has access to both VM and AG by default,
// but
// make sure the owner of these entities is same
if (caller.getId() == Account.ACCOUNT_ID_SYSTEM || _accountMgr.isRootAdmin(caller.getId())) {
if (!_affinityGroupService.isAffinityGroupAvailableInDomain(ag.getId(), owner.getDomainId())) {
throw new PermissionDeniedException("Affinity Group " + ag + " does not belong to the VM's domain");
}
}
} else {
_accountMgr.checkAccess(caller, null, true, owner, ag);
// Root admin has access to both VM and AG by default,
// but
// make sure the owner of these entities is same
if (caller.getId() == Account.ACCOUNT_ID_SYSTEM || _accountMgr.isRootAdmin(caller.getId())) {
if (ag.getAccountId() != owner.getAccountId()) {
throw new PermissionDeniedException("Affinity Group " + ag + " does not belong to the VM's account");
}
}
}
}
}
}
if (hypervisorType != HypervisorType.BareMetal) {
// check if we have available pools for vm deployment
long availablePools = _storagePoolDao.countPoolsByStatus(StoragePoolStatus.Up);
if (availablePools < 1) {
throw new StorageUnavailableException("There are no available pools in the UP state for vm deployment", -1);
}
}
if (template.getTemplateType().equals(TemplateType.SYSTEM) && !CKS_NODE.equals(vmType) && !SHAREDFSVM.equals(vmType)) {
throw new InvalidParameterValueException(String.format("Unable to use system template %s to deploy a user vm", template));
}
List<VMTemplateZoneVO> listZoneTemplate = _templateZoneDao.listByZoneTemplate(zone.getId(), template.getId());
if (listZoneTemplate == null || listZoneTemplate.isEmpty()) {
throw new InvalidParameterValueException(String.format("The template %s is not available for use", template));
}
if (isIso && !template.isBootable()) {
throw new InvalidParameterValueException(String.format("Installing from ISO requires an ISO that is bootable: %s", template));
}
// Check templates permissions
_accountMgr.checkAccess(owner, AccessType.UseEntry, false, template);
// check if the user data is correct
userData = userDataManager.validateUserData(userData, httpmethod);
// Find an SSH public key corresponding to the key pair name, if one is
// given
String sshPublicKeys = "";
String keypairnames = "";
if (!sshKeyPairs.isEmpty()) {
List<SSHKeyPairVO> pairs = _sshKeyPairDao.findByNames(owner.getAccountId(), owner.getDomainId(), sshKeyPairs);
if (pairs == null || pairs.size() != sshKeyPairs.size()) {
throw new InvalidParameterValueException("Not all specified keypairs exist");
}
sshPublicKeys = pairs.stream().map(p -> p.getPublicKey()).collect(Collectors.joining("\n"));
keypairnames = String.join(",", sshKeyPairs);
}
LinkedHashMap<String, List<NicProfile>> networkNicMap = new LinkedHashMap<>();
short defaultNetworkNumber = 0;
boolean securityGroupEnabled = false;
int networkIndex = 0;
for (NetworkVO network : networkList) {
if ((network.getDataCenterId() != zone.getId())) {
if (!network.isStrechedL2Network()) {
throw new InvalidParameterValueException(String.format("Network %s doesn't belong to zone %s", network, zone));
}
NetworkOffering ntwkOffering = _networkOfferingDao.findById(network.getNetworkOfferingId());
Long physicalNetworkId = _networkModel.findPhysicalNetworkId(zone.getId(), ntwkOffering.getTags(), ntwkOffering.getTrafficType());
String provider = _ntwkSrvcDao.getProviderForServiceInNetwork(network.getId(), Service.Connectivity);
if (!_networkModel.isProviderEnabledInPhysicalNetwork(physicalNetworkId, provider)) {
throw new InvalidParameterValueException("Network in which is VM getting deployed could not be" +
" streched to the zone, as we could not find a valid physical network");
}
}
_accountMgr.checkAccess(owner, AccessType.UseEntry, false, network);
IpAddresses requestedIpPair = null;
if (requestedIps != null && !requestedIps.isEmpty()) {
requestedIpPair = requestedIps.get(network.getId());
}
if (requestedIpPair == null) {
requestedIpPair = new IpAddresses(null, null);
} else {
_networkModel.checkRequestedIpAddresses(network.getId(), requestedIpPair);
}
NicProfile profile = new NicProfile(requestedIpPair.getIp4Address(), requestedIpPair.getIp6Address(), requestedIpPair.getMacAddress());
profile.setOrderIndex(networkIndex);
if (defaultNetworkNumber == 0) {
defaultNetworkNumber++;
// if user requested specific ip for default network, add it
if (defaultIps.getIp4Address() != null || defaultIps.getIp6Address() != null) {
_networkModel.checkRequestedIpAddresses(network.getId(), defaultIps);
profile = new NicProfile(defaultIps.getIp4Address(), defaultIps.getIp6Address());
} else if (defaultIps.getMacAddress() != null) {
profile = new NicProfile(null, null, defaultIps.getMacAddress());
}
profile.setDefaultNic(true);
if (!_networkModel.areServicesSupportedInNetwork(network.getId(), new Service[]{Service.UserData})) {
if ((userData != null) && (!userData.isEmpty())) {
throw new InvalidParameterValueException(String.format("Unable to deploy VM as UserData is provided while deploying the VM, but there is no support for %s service in the default network %s/%s.", Service.UserData.getName(), network.getName(), network.getUuid()));
}
if ((sshPublicKeys != null) && (!sshPublicKeys.isEmpty())) {
throw new InvalidParameterValueException(String.format("Unable to deploy VM as SSH keypair is provided while deploying the VM, but there is no support for %s service in the default network %s/%s", Service.UserData.getName(), network.getName(), network.getUuid()));
}
if (template.isEnablePassword()) {
throw new InvalidParameterValueException(String.format("Unable to deploy VM as template %s is password enabled, but there is no support for %s service in the default network %s/%s", template, Service.UserData.getName(), network.getName(), network.getUuid()));
}
}
}
if (_networkModel.isSecurityGroupSupportedInNetwork(network)) {
securityGroupEnabled = true;
}
List<NicProfile> profiles = networkNicMap.get(network.getUuid());
if (CollectionUtils.isEmpty(profiles)) {
profiles = new ArrayList<>();
}
profiles.add(profile);
networkNicMap.put(network.getUuid(), profiles);
networkIndex++;
}
if (securityGroupIdList != null && !securityGroupIdList.isEmpty() && !securityGroupEnabled) {
throw new InvalidParameterValueException("Unable to deploy vm with security groups as SecurityGroup service is not enabled for the vm's network");
}
// Verify network information - network default network has to be set;
// and vm can't have more than one default network
// This is a part of business logic because default network is required
// by Agent Manager in order to configure default
// gateway for the vm
if (defaultNetworkNumber == 0) {
throw new InvalidParameterValueException("At least 1 default network has to be specified for the vm");
} else if (defaultNetworkNumber > 1) {
throw new InvalidParameterValueException("Only 1 default network per vm is supported");
}
long id = _vmDao.getNextInSequence(Long.class, "id");
if (hostName != null) {
// Check is hostName is RFC compliant
checkNameForRFCCompliance(hostName);
}
String instanceName = null;
String instanceSuffix = _instance;
String uuidName = _uuidMgr.generateUuid(UserVm.class, customId);
if (_instanceNameFlag && HypervisorType.VMware.equals(hypervisorType)) {
if (StringUtils.isNotEmpty(hostName)) {
instanceSuffix = hostName;
}
if (hostName == null) {
if (displayName != null) {
hostName = displayName;
} else {
hostName = generateHostName(uuidName);
}
}
// If global config vm.instancename.flag is set to true, then CS will set guest VM's name as it appears on the hypervisor, to its hostname.
// In case of VMware since VM name must be unique within a DC, check if VM with the same hostname already exists in the zone.
VMInstanceVO vmByHostName = _vmInstanceDao.findVMByHostNameInZone(hostName, zone.getId());
if (vmByHostName != null && vmByHostName.getState() != State.Expunging) {
throw new InvalidParameterValueException("There already exists a VM by the name: " + hostName + ".");
}
} else {
if (hostName == null) {
//Generate name using uuid and instance.name global config
hostName = generateHostName(uuidName);
}
}
if (hostName != null) {
// Check is hostName is RFC compliant
checkNameForRFCCompliance(hostName);
}
instanceName = VirtualMachineName.getVmName(id, owner.getId(), instanceSuffix);
if (_instanceNameFlag && HypervisorType.VMware.equals(hypervisorType) && !instanceSuffix.equals(_instance)) {
customParameters.put(VmDetailConstants.NAME_ON_HYPERVISOR, instanceName);
}
// Check if VM with instanceName already exists.
VMInstanceVO vmObj = _vmInstanceDao.findVMByInstanceName(instanceName);
if (vmObj != null && vmObj.getState() != State.Expunging) {
throw new InvalidParameterValueException("There already exists a VM by the display name supplied");
}
checkIfHostNameUniqueInNtwkDomain(hostName, networkList);
long userId = CallContext.current().getCallingUserId();
if (CallContext.current().getCallingAccount().getId() != owner.getId()) {
List<UserVO> userVOs = _userDao.listByAccount(owner.getAccountId());
if (!userVOs.isEmpty()) {
userId = userVOs.get(0).getId();
}
}
dynamicScalingEnabled = dynamicScalingEnabled && checkIfDynamicScalingCanBeEnabled(null, offering, template, zone.getId());
UserVmVO vm = commitUserVm(zone, template, hostName, displayName, owner, diskOfferingId, diskSize, userData, userDataId, userDataDetails, caller, isDisplayVm, keyboard, accountId, userId, offering,
isIso, sshPublicKeys, networkNicMap, id, instanceName, uuidName, hypervisorType, customParameters, dhcpOptionMap,
datadiskTemplateToDiskOfferringMap, userVmOVFPropertiesMap, dynamicScalingEnabled, vmType, rootDiskOfferingId, keypairnames);
assignInstanceToGroup(group, id);
return vm;
} catch (ResourceAllocationException | CloudRuntimeException e) {
throw e;
} catch (Exception e) {
logger.error("error during resource reservation and allocation", e);
throw new CloudRuntimeException(e);
}
}