cloudstack-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From GitBox <...@apache.org>
Subject [GitHub] [cloudstack] DaanHoogland commented on a change in pull request #3606: [WIP DO NOT MERGE] VM ingestion
Date Tue, 05 Nov 2019 16:06:17 GMT
DaanHoogland commented on a change in pull request #3606: [WIP DO NOT MERGE] VM ingestion
URL: https://github.com/apache/cloudstack/pull/3606#discussion_r342642749
 
 

 ##########
 File path: server/src/main/java/org/apache/cloudstack/vm/VmImportManagerImpl.java
 ##########
 @@ -0,0 +1,1189 @@
+// 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.vm;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.ApiErrorCode;
+import org.apache.cloudstack.api.ResponseGenerator;
+import org.apache.cloudstack.api.ResponseObject;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.command.admin.vm.ImportUnmanagedInstanceCmd;
+import org.apache.cloudstack.api.command.admin.vm.ListUnmanagedInstancesCmd;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.NicResponse;
+import org.apache.cloudstack.api.response.UnmanagedInstanceDiskResponse;
+import org.apache.cloudstack.api.response.UnmanagedInstanceResponse;
+import org.apache.cloudstack.api.response.UserVmResponse;
+import org.apache.cloudstack.context.CallContext;
+import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
+import org.apache.cloudstack.engine.orchestration.service.VolumeOrchestrationService;
+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.volume.VirtualMachineDiskInfo;
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.collections.MapUtils;
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.AgentManager;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.GetUnmanagedInstancesAnswer;
+import com.cloud.agent.api.GetUnmanagedInstancesCommand;
+import com.cloud.capacity.CapacityManager;
+import com.cloud.configuration.Config;
+import com.cloud.configuration.Resource;
+import com.cloud.dc.DataCenter;
+import com.cloud.dc.dao.ClusterDao;
+import com.cloud.dc.dao.DataCenterDao;
+import com.cloud.deploy.DataCenterDeployment;
+import com.cloud.deploy.DeployDestination;
+import com.cloud.deploy.DeploymentPlanner;
+import com.cloud.deploy.DeploymentPlanningManager;
+import com.cloud.event.EventTypes;
+import com.cloud.event.UsageEventUtils;
+import com.cloud.exception.InsufficientAddressCapacityException;
+import com.cloud.exception.InsufficientCapacityException;
+import com.cloud.exception.InsufficientVirtualNetworkCapacityException;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.PermissionDeniedException;
+import com.cloud.exception.ResourceAllocationException;
+import com.cloud.host.Host;
+import com.cloud.host.HostVO;
+import com.cloud.host.Status;
+import com.cloud.host.dao.HostDao;
+import com.cloud.hypervisor.Hypervisor;
+import com.cloud.network.Network;
+import com.cloud.network.NetworkModel;
+import com.cloud.network.Networks;
+import com.cloud.network.dao.NetworkDao;
+import com.cloud.network.dao.NetworkVO;
+import com.cloud.offering.DiskOffering;
+import com.cloud.offering.ServiceOffering;
+import com.cloud.org.Cluster;
+import com.cloud.resource.ResourceManager;
+import com.cloud.serializer.GsonHelper;
+import com.cloud.server.ManagementService;
+import com.cloud.service.ServiceOfferingVO;
+import com.cloud.service.dao.ServiceOfferingDao;
+import com.cloud.storage.GuestOS;
+import com.cloud.storage.GuestOSHypervisor;
+import com.cloud.storage.Storage;
+import com.cloud.storage.StoragePool;
+import com.cloud.storage.VMTemplateStoragePoolVO;
+import com.cloud.storage.VMTemplateVO;
+import com.cloud.storage.Volume;
+import com.cloud.storage.VolumeApiService;
+import com.cloud.storage.VolumeVO;
+import com.cloud.storage.dao.DiskOfferingDao;
+import com.cloud.storage.dao.GuestOSDao;
+import com.cloud.storage.dao.GuestOSHypervisorDao;
+import com.cloud.storage.dao.VMTemplateDao;
+import com.cloud.storage.dao.VMTemplatePoolDao;
+import com.cloud.storage.dao.VolumeDao;
+import com.cloud.template.VirtualMachineTemplate;
+import com.cloud.user.Account;
+import com.cloud.user.AccountService;
+import com.cloud.user.ResourceLimitService;
+import com.cloud.user.UserVO;
+import com.cloud.user.dao.UserDao;
+import com.cloud.uservm.UserVm;
+import com.cloud.utils.Pair;
+import com.cloud.utils.net.NetUtils;
+import com.cloud.vm.DiskProfile;
+import com.cloud.vm.NicProfile;
+import com.cloud.vm.UserVmManager;
+import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.VirtualMachineManager;
+import com.cloud.vm.VirtualMachineProfile;
+import com.cloud.vm.VirtualMachineProfileImpl;
+import com.cloud.vm.VmDetailConstants;
+import com.cloud.vm.dao.NicDao;
+import com.cloud.vm.dao.VMInstanceDao;
+import com.google.common.base.Strings;
+import com.google.gson.Gson;
+
+public class VmImportManagerImpl implements VmImportService {
+    public static final String VM_IMPORT_DEFAULT_TEMPLATE_NAME = "system-default-vm-import-dummy-template.iso";
+    private static final Logger LOGGER = Logger.getLogger(VmImportManagerImpl.class);
+
+    @Inject
+    private AgentManager agentManager;
+    @Inject
+    private DataCenterDao dataCenterDao;
+    @Inject
+    private ClusterDao clusterDao;
+    @Inject
+    private HostDao hostDao;
+    @Inject
+    private AccountService accountService;
+    @Inject
+    private UserDao userDao;
+    @Inject
+    private VMTemplateDao templateDao;
+    @Inject
+    private VMTemplatePoolDao templatePoolDao;
+    @Inject
+    private ServiceOfferingDao serviceOfferingDao;
+    @Inject
+    private DiskOfferingDao diskOfferingDao;
+    @Inject
+    private ResourceManager resourceManager;
+    @Inject
+    private ResourceLimitService resourceLimitService;
+    @Inject
+    private UserVmManager userVmManager;
+    @Inject
+    private ResponseGenerator responseGenerator;
+    @Inject
+    private VolumeOrchestrationService volumeManager;
+    @Inject
+    private VolumeDao volumeDao;
+    @Inject
+    private PrimaryDataStoreDao primaryDataStoreDao;
+    @Inject
+    private NetworkDao networkDao;
+    @Inject
+    private NetworkOrchestrationService networkOrchestrationService;
+    @Inject
+    private VMInstanceDao vmDao;
+    @Inject
+    private CapacityManager capacityManager;
+    @Inject
+    private VolumeApiService volumeApiService;
+    @Inject
+    private DeploymentPlanningManager deploymentPlanningManager;
+    @Inject
+    private VirtualMachineManager virtualMachineManager;
+    @Inject
+    private ManagementService managementService;
+    @Inject
+    private NicDao nicDao;
+    @Inject
+    private NetworkModel networkModel;
+    @Inject
+    private ConfigurationDao configurationDao;
+    @Inject
+    private GuestOSDao guestOSDao;
+    @Inject
+    private GuestOSHypervisorDao guestOSHypervisorDao;
+
+    protected Gson gson;
+
+    public VmImportManagerImpl() {
+        gson = GsonHelper.getGsonLogger();
+    }
+
+    private VMTemplateVO createDefaultDummyVmImportTemplate() {
+        VMTemplateVO template = null;
+        try {
+            template = VMTemplateVO.createSystemIso(templateDao.getNextInSequence(Long.class,
"id"), VM_IMPORT_DEFAULT_TEMPLATE_NAME, VM_IMPORT_DEFAULT_TEMPLATE_NAME, true,
+                    "", true, 64, Account.ACCOUNT_ID_SYSTEM, "",
+                    "VM Import Default Template", false, 1);
+            template.setState(VirtualMachineTemplate.State.Inactive);
+            template = templateDao.persist(template);
+            if (template == null) {
+                return null;
+            }
+            templateDao.remove(template.getId());
+            template = templateDao.findByName(VM_IMPORT_DEFAULT_TEMPLATE_NAME);
+        } catch (Exception e) {
+            LOGGER.error("Unable to create default dummy template for VM import", e);
+        }
+        return template;
+    }
+
+    private UnmanagedInstanceResponse createUnmanagedInstanceResponse(UnmanagedInstance instance,
Cluster cluster, Host host) {
+        UnmanagedInstanceResponse response = new UnmanagedInstanceResponse();
+        response.setName(instance.getName());
+        if (cluster != null) {
+            response.setClusterId(cluster.getUuid());
+        }
+        if (host != null) {
+            response.setHostId(host.getUuid());
+        }
+        response.setPowerState(instance.getPowerState().toString());
+        response.setCpuCores(instance.getCpuCores());
+        response.setCpuSpeed(instance.getCpuSpeed());
+        response.setCpuCoresPerSocket(instance.getCpuCoresPerSocket());
+        response.setMemory(instance.getMemory());
+        response.setOperatingSystemId(instance.getOperatingSystemId());
+        response.setOperatingSystem(instance.getOperatingSystem());
+        response.setObjectName(UnmanagedInstance.class.getSimpleName().toLowerCase());
+
+        if (instance.getDisks() != null) {
+            for (UnmanagedInstance.Disk disk : instance.getDisks()) {
+                UnmanagedInstanceDiskResponse diskResponse = new UnmanagedInstanceDiskResponse();
+                diskResponse.setDiskId(disk.getDiskId());
+                if (!Strings.isNullOrEmpty(disk.getLabel())) {
+                    diskResponse.setLabel(disk.getLabel());
+                }
+                diskResponse.setCapacity(disk.getCapacity());
+                diskResponse.setController(disk.getController());
+                diskResponse.setControllerUnit(disk.getControllerUnit());
+                diskResponse.setPosition(disk.getPosition());
+                diskResponse.setImagePath(disk.getImagePath());
+                diskResponse.setDatastoreName(disk.getDatastoreName());
+                diskResponse.setDatastoreHost(disk.getDatastoreHost());
+                diskResponse.setDatastorePath(disk.getDatastorePath());
+                diskResponse.setDatastoreType(disk.getDatastoreType());
+                response.addDisk(diskResponse);
+            }
+        }
+
+        if (instance.getNics() != null) {
+            for (UnmanagedInstance.Nic nic : instance.getNics()) {
+                NicResponse nicResponse = new NicResponse();
+                nicResponse.setId(nic.getNicId());
+                nicResponse.setNetworkName(nic.getNetwork());
+                nicResponse.setMacAddress(nic.getMacAddress());
+                if (!Strings.isNullOrEmpty(nic.getAdapterType())) {
+                    nicResponse.setAdapterType(nic.getAdapterType());
+                }
+                if (!CollectionUtils.isEmpty(nic.getIpAddress())) {
+                    nicResponse.setIpAddresses(nic.getIpAddress());
+                }
+                nicResponse.setVlanId(nic.getVlan());
+                response.addNic(nicResponse);
+            }
+        }
+        return response;
+    }
+
+    private List<String> getAdditionalNameFilters(Cluster cluster) {
+        List<String> additionalNameFilter = new ArrayList<>();
+        if (cluster == null) {
+            return additionalNameFilter;
+        }
+        if (cluster.getHypervisorType() == Hypervisor.HypervisorType.VMware) {
+            // VMWare considers some templates as VM and they are not filtered by VirtualMachineMO.isTemplate()
+            List<VMTemplateStoragePoolVO> templates = templatePoolDao.listAll();
+            for (VMTemplateStoragePoolVO template : templates) {
+                additionalNameFilter.add(template.getInstallPath());
+            }
+
+            // VMWare considers some removed volumes as VM
+            List<VolumeVO> volumes = volumeDao.findIncludingRemovedByZone(cluster.getDataCenterId());
+            for (VolumeVO volumeVO : volumes) {
+                if (volumeVO.getRemoved() == null) {
+                    continue;
+                }
+                if (Strings.isNullOrEmpty(volumeVO.getChainInfo())) {
+                    continue;
+                }
+                List<String> volumeFileNames = new ArrayList<>();
+                try {
+                    VirtualMachineDiskInfo diskInfo = gson.fromJson(volumeVO.getChainInfo(),
VirtualMachineDiskInfo.class);
+                    String[] files = diskInfo.getDiskChain();
+                    if (files.length == 1) {
+                        continue;
+                    }
+                    boolean firstFile = true;
+                    for (final String file : files) {
+                        if (firstFile) {
+                            firstFile = false;
+                            continue;
+                        }
+                        String path = file;
+                        String[] split = path.split(" ");
+                        path = split[split.length - 1];
+                        split = path.split("/");
+                        ;
+                        path = split[split.length - 1];
+                        split = path.split("\\.");
+                        path = split[0];
+                        if (!Strings.isNullOrEmpty(path)) {
+                            if (!additionalNameFilter.contains(path)) {
+                                volumeFileNames.add(path);
+                            }
+                            if (path.contains("-")) {
+                                split = path.split("-");
+                                path = split[0];
+                                if (!Strings.isNullOrEmpty(path) && !path.equals("ROOT")
&& !additionalNameFilter.contains(path)) {
+                                    volumeFileNames.add(path);
+                                }
+                            }
+                        }
+                    }
+                } catch (Exception e) {
+                }
+                if (!volumeFileNames.isEmpty()) {
+                    additionalNameFilter.addAll(volumeFileNames);
+                }
+            }
+        }
+        return additionalNameFilter;
+    }
+
+    private List<String> getHostManagedVms(Host host) {
+        List<String> managedVms = new ArrayList<>();
+        List<VMInstanceVO> instances = vmDao.listByHostId(host.getId());
+        for (VMInstanceVO instance : instances) {
+            managedVms.add(instance.getInstanceName());
+        }
+        instances = vmDao.listByLastHostIdAndStates(host.getId(),
+                VirtualMachine.State.Stopped, VirtualMachine.State.Destroyed,
+                VirtualMachine.State.Expunging, VirtualMachine.State.Error,
+                VirtualMachine.State.Unknown, VirtualMachine.State.Shutdowned);
+        for (VMInstanceVO instance : instances) {
+            managedVms.add(instance.getInstanceName());
+        }
+        return managedVms;
+    }
+
+    private boolean hostSupportsServiceOffering(HostVO host, ServiceOffering serviceOffering)
{
+        if (host == null) {
+            return false;
+        }
+        if (serviceOffering == null) {
+            return false;
+        }
+        if (Strings.isNullOrEmpty(serviceOffering.getHostTag())) {
+            return true;
+        }
+        hostDao.loadHostTags(host);
+        return host.getHostTags() != null && host.getHostTags().contains(serviceOffering.getHostTag());
+    }
+
+    private boolean storagePoolSupportsDiskOffering(StoragePool pool, DiskOffering diskOffering)
{
+        if (pool == null) {
+            return false;
+        }
+        if (diskOffering == null) {
+            return false;
+        }
+        return volumeApiService.doesTargetStorageSupportDiskOffering(pool, diskOffering.getTags());
+    }
+
+    private boolean storagePoolSupportsServiceOffering(StoragePool pool, ServiceOffering
serviceOffering) {
+        if (pool == null) {
+            return false;
+        }
+        if (serviceOffering == null) {
+            return false;
+        }
+        return volumeApiService.doesTargetStorageSupportDiskOffering(pool, serviceOffering.getTags());
+    }
+
+    private ServiceOfferingVO getUnmanagedInstanceServiceOffering(final UnmanagedInstance
instance, ServiceOfferingVO serviceOffering, final Account owner, final DataCenter zone, final
Map<String, String> details)
+            throws ServerApiException, PermissionDeniedException, ResourceAllocationException
{
+        if (instance == null) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM is
not valid"));
+        }
+        if (serviceOffering == null) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Service
offering is not valid"));
+        }
+        accountService.checkAccess(owner, serviceOffering, zone);
+        final Integer cpu = instance.getCpuCores();
+        final Integer memory = instance.getMemory();
+        Integer cpuSpeed = instance.getCpuSpeed() == null ? 0 : instance.getCpuSpeed();
+        if (cpu == null || cpu == 0) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("CPU
cores for VM not valid"));
+        }
+        if (memory == null || memory == 0) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Memory
for VM not valid", instance.getName()));
+        }
+        if (serviceOffering.isDynamic()) {
+            if (details.containsKey(VmDetailConstants.CPU_SPEED)) {
+                try {
+                    cpuSpeed = Integer.parseInt(details.get(VmDetailConstants.CPU_SPEED));
+                } catch (Exception e) {
+                }
+            }
+            Map<String, String> parameters = new HashMap<>();
+            parameters.put(VmDetailConstants.CPU_NUMBER, String.valueOf(cpu));
+            parameters.put(VmDetailConstants.MEMORY, String.valueOf(memory));
+            if (serviceOffering.getSpeed() == null && cpuSpeed > 0) {
+                parameters.put(VmDetailConstants.CPU_SPEED, String.valueOf(cpuSpeed));
+            }
+            serviceOffering.setDynamicFlag(true);
+            userVmManager.validateCustomParameters(serviceOffering, parameters);
+            serviceOffering = serviceOfferingDao.getComputeOffering(serviceOffering, parameters);
+        } else {
+            if (!cpu.equals(serviceOffering.getCpu()) && !instance.getPowerState().equals(UnmanagedInstance.PowerState.PowerOff))
{
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Service
offering (%s) %d CPU cores does not matches VM CPU cores %d  and VM is not in powered off
state (Power state: %s)", serviceOffering.getUuid(), serviceOffering.getCpu(), cpu, instance.getPowerState()));
+            }
+            if (!memory.equals(serviceOffering.getRamSize()) && !instance.getPowerState().equals(UnmanagedInstance.PowerState.PowerOff))
{
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Service
offering (%s) %dMB memory does not matches VM memory %dMB and VM is not in powered off state
(Power state: %s)", serviceOffering.getUuid(), serviceOffering.getRamSize(), memory, instance.getPowerState()));
+            }
+            if (cpuSpeed != null && cpuSpeed > 0 && !cpuSpeed.equals(serviceOffering.getSpeed())
&& !instance.getPowerState().equals(UnmanagedInstance.PowerState.PowerOff)) {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Service
offering (%s) %dMHz CPU speed does not matches VM CPU speed %dMHz and VM is not in powered
off state (Power state: %s)", serviceOffering.getUuid(), serviceOffering.getSpeed(), cpuSpeed,
instance.getPowerState()));
+            }
+        }
+        resourceLimitService.checkResourceLimit(owner, Resource.ResourceType.cpu, new Long(serviceOffering.getCpu()));
+        resourceLimitService.checkResourceLimit(owner, Resource.ResourceType.memory, new
Long(serviceOffering.getRamSize()));
+        return serviceOffering;
+    }
+
+    private Map<String, Network.IpAddresses> getNicIpAddresses(final List<UnmanagedInstance.Nic>
nics, final Map<String, Network.IpAddresses> callerNicIpAddressMap) {
+        Map<String, Network.IpAddresses> nicIpAddresses = new HashMap<>();
+        for (UnmanagedInstance.Nic nic : nics) {
+            Network.IpAddresses ipAddresses = null;
+            if (MapUtils.isNotEmpty(callerNicIpAddressMap) && callerNicIpAddressMap.containsKey(nic.getNicId()))
{
+                ipAddresses = callerNicIpAddressMap.get(nic.getNicId());
+            }
+            // If IP is set to auto-assign, check NIC doesn't have more that one IP from
SDK
+            if (ipAddresses != null && ipAddresses.getIp4Address() != null &&
ipAddresses.getIp4Address().equals("auto") && !CollectionUtils.isEmpty(nic.getIpAddress()))
{
+                if (nic.getIpAddress().size() > 1) {
+                    throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Multiple
IP addresses (%s, %s) present for nic ID: %s. IP address cannot be assigned automatically,
only single IP address auto-assigning supported", nic.getIpAddress().get(0), nic.getIpAddress().get(1),
nic.getNicId()));
+                }
+                String address = nic.getIpAddress().get(0);
+                if (NetUtils.isValidIp4(address)) {
+                    ipAddresses.setIp4Address(address);
+                }
+            }
+            if (ipAddresses != null) {
+                nicIpAddresses.put(nic.getNicId(), ipAddresses);
+            }
+        }
+        return nicIpAddresses;
+    }
+
+    private StoragePool getStoragePool(final UnmanagedInstance.Disk disk, final DataCenter
zone, final Cluster cluster) {
+        StoragePool storagePool = null;
+        final String dsHost = disk.getDatastoreHost();
+        final String dsPath = disk.getDatastorePath();
+        final String dsType = disk.getDatastoreType();
+        final String dsName = disk.getDatastoreName();
+        if (dsType.equals("VMFS")) {
+            List<StoragePoolVO> pools = primaryDataStoreDao.listPoolsByCluster(cluster.getId());
+            pools.addAll(primaryDataStoreDao.listByDataCenterId(zone.getId()));
+            for (StoragePool pool : pools) {
+                if (pool.getPoolType() != Storage.StoragePoolType.VMFS) {
+                    continue;
+                }
+                if (pool.getPath().endsWith(dsName)) {
+                    storagePool = pool;
+                    break;
+                }
+            }
+        } else {
+            List<StoragePoolVO> pools = primaryDataStoreDao.listPoolByHostPath(dsHost,
dsPath);
+            for (StoragePool pool : pools) {
+                if (pool.getDataCenterId() == zone.getId() &&
+                        (pool.getClusterId() == null || pool.getClusterId().equals(cluster.getId())))
{
+                    storagePool = pool;
+                    break;
+                }
+            }
+        }
+        if (storagePool == null) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Storage
pool for disk %s(%s) with datastore: %s not found in zone ID: %s", disk.getLabel(), disk.getDiskId(),
disk.getDatastoreName(), zone.getUuid()));
+        }
+        return storagePool;
+    }
+
+    private void checkUnmanagedDiskAndOfferingForImport(UnmanagedInstance.Disk disk, DiskOffering
diskOffering, ServiceOffering serviceOffering, final Account owner, final DataCenter zone,
final Cluster cluster, final boolean migrateAllowed)
+            throws ServerApiException, PermissionDeniedException, ResourceAllocationException
{
+        if (diskOffering == null) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Disk
offering for disk ID: %s not found during VM import", disk.getDiskId()));
+        }
+        accountService.checkAccess(owner, diskOffering, zone);
+        resourceLimitService.checkResourceLimit(owner, Resource.ResourceType.volume);
+        if (disk.getCapacity() == null || disk.getCapacity() == 0) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Size
of disk(ID: %s) is found invalid during VM import", disk.getDiskId()));
+        }
+        if (!diskOffering.isCustomized() && diskOffering.getDiskSize() == 0) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Size
of fixed disk offering(ID: %s) is found invalid during VM import", diskOffering.getUuid()));
+        }
+        if (!diskOffering.isCustomized() && diskOffering.getDiskSize() < disk.getCapacity())
{
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Size
of disk offering(ID: %s) %dGB is found less than the size of disk(ID: %s) %dGB during VM import",
diskOffering.getUuid(), (diskOffering.getDiskSize() / Resource.ResourceType.bytesToGiB), disk.getDiskId(),
(disk.getCapacity() / (Resource.ResourceType.bytesToGiB))));
+        }
+        StoragePool storagePool = getStoragePool(disk, zone, cluster);
+        if (!migrateAllowed && !storagePoolSupportsDiskOffering(storagePool, diskOffering))
{
+            throw new InvalidParameterValueException(String.format("Disk offering: %s is
not compatible with storage pool: %s of unmanaged disk: %s", diskOffering.getUuid(), storagePool.getUuid(),
disk.getDiskId()));
+        }
+        if (serviceOffering != null && !migrateAllowed && !storagePoolSupportsServiceOffering(storagePool,
serviceOffering)) {
+            throw new InvalidParameterValueException(String.format("Service offering: %s
is not compatible with storage pool: %s of unmanaged disk: %s", diskOffering.getUuid(), storagePool.getUuid(),
disk.getDiskId()));
+        }
+    }
+
+    private void checkUnmanagedDiskAndOfferingForImport(List<UnmanagedInstance.Disk>
disks, final Map<String, Long> diskOfferingMap, final Account owner, final DataCenter
zone, final Cluster cluster, final boolean migrateAllowed)
+            throws ServerApiException, PermissionDeniedException, ResourceAllocationException
{
+        String diskController = null;
+        for (UnmanagedInstance.Disk disk : disks) {
+            if (disk == null) {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Unable
to retrieve disk details for VM"));
+            }
+            if (!diskOfferingMap.containsKey(disk.getDiskId())) {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Disk
offering for disk ID: %s not found during VM import", disk.getDiskId()));
+            }
+            if (Strings.isNullOrEmpty(diskController)) {
+                diskController = disk.getController();
+            } else {
+                if (!diskController.equals(disk.getController())) {
+                    throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Multiple
data disk controllers of different type (%s, %s) are not supported for import. Please make
sure that all data disk controllers are of the same type", diskController, disk.getController()));
+                }
+            }
+            checkUnmanagedDiskAndOfferingForImport(disk, diskOfferingDao.findById(diskOfferingMap.get(disk.getDiskId())),
null, owner, zone, cluster, migrateAllowed);
+        }
+    }
+
+    private void checkUnmanagedNicAndNetworkForImport(UnmanagedInstance.Nic nic, Network
network, final DataCenter zone, final Account owner, final boolean autoAssign) throws ServerApiException
{
+        if (nic == null) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Unable
to retrieve NIC details during VM import"));
+        }
+        if (network == null) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Network
for nic ID: %s not found during VM import", nic.getNicId()));
+        }
+        if (network.getDataCenterId() != zone.getId()) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Network(ID:
%s) for nic(ID: %s) belongs to a different zone than VM to be imported", network.getUuid(),
nic.getNicId()));
+        }
+        networkModel.checkNetworkPermissions(owner, network);
+        if (!autoAssign && network.getGuestType().equals(Network.GuestType.Isolated))
{
+            return;
+        }
+        if (nic.getVlan() != null && nic.getVlan() != 0 && (Strings.isNullOrEmpty(network.getBroadcastUri().toString())
|| !network.getBroadcastUri().toString().equals(String.format("vlan://%d", nic.getVlan()))))
{
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VLAN
of network(ID: %s) %s is found different from the VLAN of nic(ID: %s) vlan://%d during VM
import", network.getUuid(), network.getBroadcastUri().toString(), nic.getNicId(), nic.getVlan()));
+        }
+    }
+
+    private void checkUnmanagedNicAndNetworkHostnameForImport(UnmanagedInstance.Nic nic,
Network network, final String hostName) throws ServerApiException {
+        if (nic == null) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Unable
to retrieve NIC details during VM import!"));
+        }
+        if (network == null) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Network
for nic ID: %s not found during VM import!", nic.getNicId()));
+        }
+        // Check for duplicate hostname in network, get all vms hostNames in the network
+        List<String> hostNames = vmDao.listDistinctHostNames(network.getId());
+        if (CollectionUtils.isNotEmpty(hostNames) && hostNames.contains(hostName))
{
+            throw new InvalidParameterValueException("The vm with hostName " + hostName +
" already exists in the network domain: " + network.getNetworkDomain() + "; network="
+                    + network);
+        }
+    }
+
+    private void checkUnmanagedNicIpAndNetworkForImport(UnmanagedInstance.Nic nic, Network
network, final Network.IpAddresses ipAddresses) throws ServerApiException {
+        if (nic == null) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Unable
to retrieve NIC details during VM import"));
+        }
+        if (network == null) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Network
for nic ID: %s not found during VM import", nic.getNicId()));
+        }
+        // Check IP is assigned for non L2 networks
+        if (!network.getGuestType().equals(Network.GuestType.L2) && (ipAddresses
== null || Strings.isNullOrEmpty(ipAddresses.getIp4Address()))) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("NIC(ID:
%s) needs a valid IP address for it to be associated with network(ID: %s). %s parameter of
API can be used for this", nic.getNicId(), network.getUuid(), ApiConstants.NIC_IP_ADDRESS_LIST));
+        }
+        // If network is non L2, IP v4 is assigned and not set to auto-assign, check it is
available for network
+        if (!network.getGuestType().equals(Network.GuestType.L2) && ipAddresses !=
null && !Strings.isNullOrEmpty(ipAddresses.getIp4Address()) && !ipAddresses.getIp4Address().equals("auto"))
{
+            Set<Long> ips = networkModel.getAvailableIps(network, ipAddresses.getIp4Address());
+            if (CollectionUtils.isEmpty(ips) || !ips.contains(NetUtils.ip2Long(ipAddresses.getIp4Address())))
{
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("IP
address %s for NIC(ID: %s) is not available in network(ID: %s)", ipAddresses.getIp4Address(),
nic.getNicId(), network.getUuid()));
+            }
+        }
+    }
+
+    private Map<String, Long> getUnmanagedNicNetworkMap(List<UnmanagedInstance.Nic>
nics, final Map<String, Long> callerNicNetworkMap, final Map<String, Network.IpAddresses>
callerNicIpAddressMap, final DataCenter zone, final String hostName, final Account owner)
throws ServerApiException {
+        Map<String, Long> nicNetworkMap = new HashMap<>();
+        String nicAdapter = null;
+        for (UnmanagedInstance.Nic nic : nics) {
+            if (Strings.isNullOrEmpty(nicAdapter)) {
+                nicAdapter = nic.getAdapterType();
+            } else {
+                if (!nicAdapter.equals(nic.getAdapterType())) {
+                    throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Multiple
network adapter of different type (%s, %s) are not supported for import. Please make sure
that all network adapters are of the same type", nicAdapter, nic.getAdapterType()));
+                }
+            }
+            Network network = null;
+            Network.IpAddresses ipAddresses = null;
+            if (MapUtils.isNotEmpty(callerNicIpAddressMap) && callerNicIpAddressMap.containsKey(nic.getNicId()))
{
+                ipAddresses = callerNicIpAddressMap.get(nic.getNicId());
+            }
+            if (!callerNicNetworkMap.containsKey(nic.getNicId())) {
+                if (nic.getVlan() != null && nic.getVlan() != 0) {
+                    // Find a suitable network
+                    List<NetworkVO> networks = networkDao.listByZone(zone.getId());
+                    for (NetworkVO networkVO : networks) {
+                        if (networkVO.getTrafficType() == Networks.TrafficType.None || Networks.TrafficType.isSystemNetwork(networkVO.getTrafficType()))
{
+                            continue;
+                        }
+                        try {
+                            checkUnmanagedNicAndNetworkForImport(nic, networkVO, zone, owner,
true);
+                            network = networkVO;
+                        } catch (Exception e) {
+                        }
+                        if (network != null) {
+                            checkUnmanagedNicAndNetworkHostnameForImport(nic, network, hostName);
+                            checkUnmanagedNicIpAndNetworkForImport(nic, network, ipAddresses);
+                            break;
+                        }
+                    }
+                }
+            } else {
+                network = networkDao.findById(callerNicNetworkMap.get(nic.getNicId()));
+                checkUnmanagedNicAndNetworkForImport(nic, network, zone, owner, false);
+                checkUnmanagedNicAndNetworkHostnameForImport(nic, network, hostName);
+                checkUnmanagedNicIpAndNetworkForImport(nic, network, ipAddresses);
+            }
+            if (network == null) {
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Suitable
network for nic(ID: %s) not found during VM import", nic.getNicId()));
+            }
+            nicNetworkMap.put(nic.getNicId(), network.getId());
+        }
+        return nicNetworkMap;
+    }
+
+    private Pair<DiskProfile, StoragePool> importDisk(UnmanagedInstance.Disk disk,
VirtualMachine vm, Cluster cluster, DiskOffering diskOffering,
+                                                      Volume.Type type, String name, Long
diskSize, VirtualMachineTemplate template,
+                                                      Account owner, Long deviceId) {
+        final DataCenter zone = dataCenterDao.findById(vm.getDataCenterId());
+        final String path = Strings.isNullOrEmpty(disk.getFileBaseName()) ? disk.getImagePath()
: disk.getFileBaseName();
+        String chainInfo = disk.getChainInfo();
+        if (Strings.isNullOrEmpty(chainInfo)) {
+            VirtualMachineDiskInfo diskInfo = new VirtualMachineDiskInfo();
+            diskInfo.setDiskDeviceBusName(String.format("%s%d:%d", disk.getController(),
disk.getControllerUnit(), disk.getPosition()));
+            diskInfo.setDiskChain(new String[]{disk.getImagePath()});
+            chainInfo = gson.toJson(diskInfo);
+        }
+        StoragePool storagePool = getStoragePool(disk, zone, cluster);
+        DiskProfile profile = volumeManager.importVolume(type, name, diskOffering, diskSize,
+                diskOffering.getMinIops(), diskOffering.getMaxIops(), vm, template, owner,
deviceId, storagePool.getId(), path, disk.getChainInfo());
+
+        return new Pair<DiskProfile, StoragePool>(profile, storagePool);
+    }
+
+    private NicProfile importNic(UnmanagedInstance.Nic nic, VirtualMachine vm, Network network,
Network.IpAddresses ipAddresses, boolean isDefaultNic) throws InsufficientVirtualNetworkCapacityException,
InsufficientAddressCapacityException {
+        Pair<NicProfile, Integer> result = networkOrchestrationService.importNic(nic.getMacAddress(),
0, network, isDefaultNic, vm, ipAddresses);
+        if (result == null) {
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("NIC
ID: %s import failed", nic.getNicId()));
+        }
+        return result.first();
+    }
+
+    private void cleanupFailedImportVM(final UserVm userVm) {
+        if (userVm == null) {
+            return;
+        }
+        VirtualMachineProfile profile = new VirtualMachineProfileImpl(userVm);
+        // Remove all volumes
+        volumeDao.deleteVolumesByInstance(userVm.getId());
+        // Remove all nics
+        try {
+            networkOrchestrationService.release(profile, true);
+        } catch (Exception e) {
+            nicDao.removeNicsForInstance(userVm.getId());
+        }
+        // Remove vm
+        vmDao.remove(userVm.getId());
+    }
+
+    private UserVm migrateImportedVM(HostVO sourceHost, VirtualMachineTemplate template,
ServiceOfferingVO serviceOffering, UserVm userVm, final Account owner, List<Pair<DiskProfile,
StoragePool>> diskProfileStoragePoolList) {
+        UserVm vm = userVm;
+        if (vm == null) {
+            LOGGER.error(String.format("Failed to check migrations need during VM import"));
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed
to check migrations need during VM import"));
+        }
+        if (sourceHost == null || serviceOffering == null || diskProfileStoragePoolList ==
null) {
+            LOGGER.error(String.format("Failed to check migrations need during import, VM:
%s", userVm.getInstanceName()));
+            cleanupFailedImportVM(vm);
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed
to check migrations need during import, VM: %s", userVm.getInstanceName()));
+        }
+        if (!hostSupportsServiceOffering(sourceHost, serviceOffering)) {
+            LOGGER.debug(String.format("VM %s needs to be migrated", vm.getUuid()));
+            final VirtualMachineProfile profile = new VirtualMachineProfileImpl(vm, template,
serviceOffering, owner, null);
+            DeploymentPlanner.ExcludeList excludeList = new DeploymentPlanner.ExcludeList();
+            excludeList.addHost(sourceHost.getId());
+            final DataCenterDeployment plan = new DataCenterDeployment(sourceHost.getDataCenterId(),
sourceHost.getPodId(), sourceHost.getClusterId(), null, null, null);
+            DeployDestination dest = null;
+            try {
+                dest = deploymentPlanningManager.planDeployment(profile, plan, excludeList,
null);
+            } catch (Exception e) {
+                LOGGER.warn(String.format("VM import failed for unmanaged vm: %s during vm
migration, finding deployment destination", vm.getInstanceName()), e);
+                cleanupFailedImportVM(vm);
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM
import failed for unmanaged vm: %s during vm migration, finding deployment destination", vm.getInstanceName()));
+            }
+            if (dest != null) {
+                if (LOGGER.isDebugEnabled()) {
+                    LOGGER.debug(" Found " + dest + " for migrating the vm to");
+                }
+            }
+            if (dest == null) {
+                cleanupFailedImportVM(vm);
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM
import failed for unmanaged vm: %s during vm migration, no deployment destination found",
vm.getInstanceName()));
+            }
+            try {
+                if (vm.getState().equals(VirtualMachine.State.Stopped)) {
+                    VMInstanceVO vmInstanceVO = vmDao.findById(userVm.getId());
+                    vmInstanceVO.setHostId(dest.getHost().getId());
+                    vmInstanceVO.setLastHostId(dest.getHost().getId());
+                    vmDao.update(vmInstanceVO.getId(), vmInstanceVO);
+                } else {
+                    virtualMachineManager.migrate(vm.getUuid(), sourceHost.getId(), dest);
+                }
+                vm = userVmManager.getUserVm(vm.getId());
+            } catch (Exception e) {
+                LOGGER.error(String.format("VM import failed for unmanaged vm: %s during
vm migration", vm.getInstanceName()), e);
+                cleanupFailedImportVM(vm);
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM
import failed for unmanaged vm: %s during vm migration. %s", userVm.getInstanceName(), e.getMessage()));
+            }
+        }
+        for (Pair<DiskProfile, StoragePool> diskProfileStoragePool : diskProfileStoragePoolList)
{
+            if (diskProfileStoragePool == null ||
+                    diskProfileStoragePool.first() == null ||
+                    diskProfileStoragePool.second() == null) {
+                continue;
+            }
+            DiskProfile profile = diskProfileStoragePool.first();
+            DiskOffering dOffering = diskOfferingDao.findById(profile.getDiskOfferingId());
+            if (dOffering == null) {
+                continue;
+            }
+            VolumeVO volumeVO = volumeDao.findById(profile.getVolumeId());
+            if (volumeVO == null) {
+                continue;
+            }
+            boolean poolSupportsOfferings = storagePoolSupportsDiskOffering(diskProfileStoragePool.second(),
dOffering);
+            if (poolSupportsOfferings && profile.getType() == Volume.Type.ROOT) {
+                poolSupportsOfferings = storagePoolSupportsServiceOffering(diskProfileStoragePool.second(),
serviceOffering);
+            }
+            if (poolSupportsOfferings) {
+                continue;
+            }
+            LOGGER.debug(String.format("Volume %s needs to be migrated", volumeVO.getUuid()));
+            Pair<List<? extends StoragePool>, List<? extends StoragePool>>
poolsPair = managementService.listStoragePoolsForMigrationOfVolume(profile.getVolumeId());
+            if (CollectionUtils.isEmpty(poolsPair.first()) && CollectionUtils.isEmpty(poolsPair.second()))
{
+                cleanupFailedImportVM(vm);
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM
import failed for unmanaged vm: %s during volume ID: %s migration as no suitable pool(s) found",
userVm.getInstanceName(), volumeVO.getUuid()));
+            }
+            List<? extends StoragePool> storagePools = poolsPair.second();
+            StoragePool storagePool = null;
+            if (CollectionUtils.isNotEmpty(storagePools)) {
+                for (StoragePool pool : storagePools) {
+                    if (diskProfileStoragePool.second().getId() != pool.getId() &&
+                            storagePoolSupportsDiskOffering(pool, dOffering) &&
+                            (!profile.getType().equals(Volume.Type.ROOT) ||
+                                    profile.getType().equals(Volume.Type.ROOT) &&
storagePoolSupportsServiceOffering(pool, serviceOffering))) {
+                        storagePool = pool;
+                        break;
+                    }
+                }
+            }
+            // For zone-wide pools, at times, suitable storage pools are not returned therefore
consider all pools.
+            if (storagePool == null && CollectionUtils.isNotEmpty(poolsPair.first()))
{
+                storagePools = poolsPair.first();
+                for (StoragePool pool : storagePools) {
+                    if (diskProfileStoragePool.second().getId() != pool.getId() &&
+                            storagePoolSupportsDiskOffering(pool, dOffering) &&
+                            (!profile.getType().equals(Volume.Type.ROOT) ||
+                                    profile.getType().equals(Volume.Type.ROOT) &&
storagePoolSupportsServiceOffering(pool, serviceOffering))) {
+                        storagePool = pool;
+                        break;
+                    }
+                }
+            }
+            if (storagePool == null) {
+                cleanupFailedImportVM(vm);
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM
import failed for unmanaged vm: %s during volume ID: %s migration as no suitable pool found",
userVm.getInstanceName(), volumeVO.getUuid()));
+            } else {
+                LOGGER.debug(String.format("Found storage pool %s(%s) for migrating the volume
%s to", storagePool.getName(), storagePool.getUuid(), volumeVO.getUuid()));
+            }
+            try {
+                Volume volume = null;
+                if (vm.getState().equals(VirtualMachine.State.Running)) {
+                    volume = volumeManager.liveMigrateVolume(volumeVO, storagePool);
+                } else {
+                    volume = volumeManager.migrateVolume(volumeVO, storagePool);
+                }
+                if (volume == null) {
+                    throw new Exception();
+                }
+            } catch (Exception e) {
+                LOGGER.error(String.format("VM import failed for unmanaged vm: %s during
volume migration", vm.getInstanceName()), e);
+                cleanupFailedImportVM(vm);
+                throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM
import failed for unmanaged vm: %s during volume migration. %s", userVm.getInstanceName(),
Strings.nullToEmpty(e.getMessage())));
+            }
+        }
+        return userVm;
+    }
+
+    private void publishVMUsageUpdateResourceCount(final UserVm userVm, ServiceOfferingVO
serviceOfferingVO) {
+        if (userVm == null || serviceOfferingVO == null) {
+            LOGGER.error("Failed to publish usage records during VM import");
+            cleanupFailedImportVM(userVm);
+            throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM import
failed for unmanaged vm during publishing usage records"));
+        }
+        try {
+            if (!serviceOfferingVO.isDynamic()) {
+                UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_IMPORT, userVm.getAccountId(),
userVm.getDataCenterId(), userVm.getId(), userVm.getHostName(), serviceOfferingVO.getId(),
userVm.getTemplateId(),
+                        userVm.getHypervisorType().toString(), VirtualMachine.class.getName(),
userVm.getUuid(), userVm.isDisplayVm());
+            } else {
+                UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_IMPORT, userVm.getAccountId(),
userVm.getAccountId(), userVm.getDataCenterId(), userVm.getHostName(), serviceOfferingVO.getId(),
userVm.getTemplateId(),
+                        userVm.getHypervisorType().toString(), VirtualMachine.class.getName(),
userVm.getUuid(), userVm.getDetails(), userVm.isDisplayVm());
+            }
+        } catch (Exception e) {
 
 Review comment:
   this exception seems to be ignored in the catch block please log a stacktrace.

----------------------------------------------------------------
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
 
For queries about this service, please contact Infrastructure at:
users@infra.apache.org


With regards,
Apache Git Services

Mime
View raw message