diff --git a/api/src/main/java/com/cloud/event/EventTypes.java b/api/src/main/java/com/cloud/event/EventTypes.java index a30518aaf176..59c4d689af1c 100644 --- a/api/src/main/java/com/cloud/event/EventTypes.java +++ b/api/src/main/java/com/cloud/event/EventTypes.java @@ -19,6 +19,13 @@ import java.util.HashMap; import java.util.Map; +import org.apache.cloudstack.acl.Role; +import org.apache.cloudstack.acl.RolePermission; +import org.apache.cloudstack.annotation.Annotation; +import org.apache.cloudstack.config.Configuration; +import org.apache.cloudstack.ha.HAConfig; +import org.apache.cloudstack.usage.Usage; + import com.cloud.dc.DataCenter; import com.cloud.dc.Pod; import com.cloud.dc.StorageNetworkIpRange; @@ -69,12 +76,6 @@ import com.cloud.vm.Nic; import com.cloud.vm.NicSecondaryIp; import com.cloud.vm.VirtualMachine; -import org.apache.cloudstack.acl.Role; -import org.apache.cloudstack.acl.RolePermission; -import org.apache.cloudstack.annotation.Annotation; -import org.apache.cloudstack.config.Configuration; -import org.apache.cloudstack.ha.HAConfig; -import org.apache.cloudstack.usage.Usage; public class EventTypes { @@ -96,6 +97,7 @@ public class EventTypes { public static final String EVENT_VM_MOVE = "VM.MOVE"; public static final String EVENT_VM_RESTORE = "VM.RESTORE"; public static final String EVENT_VM_EXPUNGE = "VM.EXPUNGE"; + public static final String EVENT_VM_IMPORT = "VM.IMPORT"; // Domain Router public static final String EVENT_ROUTER_CREATE = "ROUTER.CREATE"; @@ -594,6 +596,7 @@ public class EventTypes { entityEventDetails.put(EVENT_VM_MOVE, VirtualMachine.class); entityEventDetails.put(EVENT_VM_RESTORE, VirtualMachine.class); entityEventDetails.put(EVENT_VM_EXPUNGE, VirtualMachine.class); + entityEventDetails.put(EVENT_VM_IMPORT, VirtualMachine.class); entityEventDetails.put(EVENT_ROUTER_CREATE, VirtualRouter.class); entityEventDetails.put(EVENT_ROUTER_DESTROY, VirtualRouter.class); diff --git a/api/src/main/java/com/cloud/vm/UserVmService.java b/api/src/main/java/com/cloud/vm/UserVmService.java index 99eb827c1227..23c6b38d8aab 100644 --- a/api/src/main/java/com/cloud/vm/UserVmService.java +++ b/api/src/main/java/com/cloud/vm/UserVmService.java @@ -513,4 +513,8 @@ UserVm upgradeVirtualMachine(ScaleVMCmd cmd) throws ResourceUnavailableException void collectVmNetworkStatistics (UserVm userVm); + UserVm importVM(final DataCenter zone, final Host host, final VirtualMachineTemplate template, final String instanceName, final String displayName, final Account owner, final String userData, final Account caller, final Boolean isDisplayVm, final String keyboard, + final long accountId, final long userId, final ServiceOffering serviceOffering, final String sshPublicKey, + final String hostName, final HypervisorType hypervisorType, final Map customParameters, final VirtualMachine.PowerState powerState) throws InsufficientCapacityException; + } diff --git a/api/src/main/java/com/cloud/vm/VmDetailConstants.java b/api/src/main/java/com/cloud/vm/VmDetailConstants.java index 84de8c9ebac8..7c40a7ba421c 100644 --- a/api/src/main/java/com/cloud/vm/VmDetailConstants.java +++ b/api/src/main/java/com/cloud/vm/VmDetailConstants.java @@ -54,4 +54,12 @@ public interface VmDetailConstants { String SSH_PUBLIC_KEY = "SSH.PublicKey"; String PASSWORD = "password"; String ENCRYPTED_PASSWORD = "Encrypted.Password"; + + // VM import with nic, disk and custom params for custom compute offering + String NIC = "nic"; + String NETWORK = "network"; + String IP4_ADDRESS = "ip4Address"; + String IP6_ADDRESS = "ip6Address"; + String DISK = "disk"; + String DISK_OFFERING = "diskOffering"; } diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 44c53f690fb8..4c0d014c5362 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -22,6 +22,7 @@ public class ApiConstants { public static final String ACCOUNT_TYPE = "accounttype"; public static final String ACCOUNT_ID = "accountid"; public static final String ACTIVITY = "activity"; + public static final String ADAPTER_TYPE = "adaptertype"; public static final String ADDRESS = "address"; public static final String ALGORITHM = "algorithm"; public static final String ALLOCATED_ONLY = "allocatedonly"; @@ -43,6 +44,7 @@ public class ApiConstants { public static final String BYTES_WRITE_RATE_MAX = "byteswriteratemax"; public static final String BYTES_WRITE_RATE_MAX_LENGTH = "byteswriteratemaxlength"; public static final String BYPASS_VLAN_OVERLAP_CHECK = "bypassvlanoverlapcheck"; + public static final String CAPACITY = "capacity"; public static final String CATEGORY = "category"; public static final String CAN_REVERT = "canrevert"; public static final String CA_CERTIFICATES = "cacertificates"; @@ -50,9 +52,15 @@ public class ApiConstants { public static final String CERTIFICATE_CHAIN = "certchain"; public static final String CERTIFICATE_FINGERPRINT = "fingerprint"; public static final String CERTIFICATE_ID = "certid"; + public static final String CONTROLLER = "controller"; + public static final String CONTROLLER_UNIT = "controllerunit"; public static final String COPY_IMAGE_TAGS = "copyimagetags"; public static final String CSR = "csr"; public static final String PRIVATE_KEY = "privatekey"; + public static final String DATASTORE_HOST = "datastorehost"; + public static final String DATASTORE_NAME = "datastorename"; + public static final String DATASTORE_PATH = "datastorepath"; + public static final String DATASTORE_TYPE = "datastoretype"; public static final String DOMAIN_SUFFIX = "domainsuffix"; public static final String DNS_SEARCH_ORDER = "dnssearchorder"; public static final String CHAIN_INFO = "chaininfo"; @@ -69,6 +77,7 @@ public class ApiConstants { public static final String COMMAND = "command"; public static final String CMD_EVENT_TYPE = "cmdeventtype"; public static final String COMPONENT = "component"; + public static final String CPU_CORE_PER_SOCKET = "cpucorepersocket"; public static final String CPU_NUMBER = "cpunumber"; public static final String CPU_SPEED = "cpuspeed"; public static final String CPU_LOAD_AVERAGE = "cpuloadaverage"; @@ -91,6 +100,7 @@ public class ApiConstants { public static final String DETAILS = "details"; public static final String DEVICE_ID = "deviceid"; public static final String DIRECT_DOWNLOAD = "directdownload"; + public static final String DISK = "disk"; public static final String DISK_OFFERING_ID = "diskofferingid"; public static final String NEW_DISK_OFFERING_ID = "newdiskofferingid"; public static final String DISK_KBS_READ = "diskkbsread"; @@ -170,6 +180,7 @@ public class ApiConstants { public static final String PREVIOUS_ACL_RULE_ID = "previousaclruleid"; public static final String NEXT_ACL_RULE_ID = "nextaclruleid"; public static final String MOVE_ACL_CONSISTENCY_HASH = "aclconsistencyhash"; + public static final String IMAGE_PATH = "imagepath"; public static final String INTERNAL_DNS1 = "internaldns1"; public static final String INTERNAL_DNS2 = "internaldns2"; public static final String INTERVAL_TYPE = "intervaltype"; @@ -181,6 +192,7 @@ public class ApiConstants { public static final String IOPS_WRITE_RATE_MAX = "iopswriteratemax"; public static final String IOPS_WRITE_RATE_MAX_LENGTH = "iopswriteratemaxlength"; public static final String IP_ADDRESS = "ipaddress"; + public static final String IP_ADDRESSES = "ipaddresses"; public static final String IP6_ADDRESS = "ip6address"; public static final String IP_ADDRESS_ID = "ipaddressid"; public static final String IS_ASYNC = "isasync"; @@ -224,6 +236,9 @@ public class ApiConstants { public static final String NETWORK_DOMAIN = "networkdomain"; public static final String NETMASK = "netmask"; public static final String NEW_NAME = "newname"; + public static final String NIC = "nic"; + public static final String NIC_NETWORK_LIST = "nicnetworklist"; + public static final String NIC_IP_ADDRESS_LIST = "nicipaddresslist"; public static final String NUM_RETRIES = "numretries"; public static final String OFFER_HA = "offerha"; public static final String IS_SYSTEM_OFFERING = "issystem"; @@ -231,6 +246,7 @@ public class ApiConstants { public static final String OLD_FORMAT = "oldformat"; public static final String OP = "op"; public static final String OS_CATEGORY_ID = "oscategoryid"; + public static final String OS_ID = "osid"; public static final String OS_TYPE_ID = "ostypeid"; public static final String OS_DISPLAY_NAME = "osdisplayname"; public static final String OS_NAME_FOR_HYPERVISOR = "osnameforhypervisor"; @@ -255,6 +271,7 @@ public class ApiConstants { public static final String PORTAL = "portal"; public static final String PORTABLE_IP_ADDRESS = "portableipaddress"; public static final String PORT_FORWARDING_SERVICE_ID = "portforwardingserviceid"; + public static final String POSITION = "position"; public static final String POST_URL = "postURL"; public static final String POWER_STATE = "powerstate"; public static final String PRIVATE_INTERFACE = "privateinterface"; @@ -357,6 +374,7 @@ public class ApiConstants { public static final String REMOVE_VLAN = "removevlan"; public static final String VLAN_ID = "vlanid"; public static final String ISOLATED_PVLAN = "isolatedpvlan"; + public static final String ISOLATED_PVLAN_TYPE = "isolatedpvlantype"; public static final String ISOLATION_URI = "isolationuri"; public static final String VM_AVAILABLE = "vmavailable"; public static final String VM_LIMIT = "vmlimit"; @@ -528,6 +546,7 @@ public class ApiConstants { public static final String CUSTOM_DISK_OFF_MAX_SIZE = "customdiskofferingmaxsize"; public static final String DEFAULT_ZONE_ID = "defaultzoneid"; public static final String LIVE_MIGRATE = "livemigrate"; + public static final String MIGRATE_ALLOWED = "migrateallowed"; public static final String MIGRATE_TO = "migrateto"; public static final String GUID = "guid"; public static final String VSWITCH_TYPE_GUEST_TRAFFIC = "guestvswitchtype"; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ImportUnmanagedInstanceCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ImportUnmanagedInstanceCmd.java new file mode 100644 index 000000000000..4b367f8f08c9 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ImportUnmanagedInstanceCmd.java @@ -0,0 +1,300 @@ +// 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.admin.vm; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import javax.inject.Inject; + +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ResponseObject; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ClusterResponse; +import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.ProjectResponse; +import org.apache.cloudstack.api.response.ServiceOfferingResponse; +import org.apache.cloudstack.api.response.TemplateResponse; +import org.apache.cloudstack.api.response.UserVmResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.vm.VmImportService; +import org.apache.commons.collections.MapUtils; +import org.apache.log4j.Logger; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Network; +import com.cloud.offering.DiskOffering; +import com.cloud.user.Account; +import com.cloud.utils.net.NetUtils; +import com.cloud.vm.VmDetailConstants; +import com.google.common.base.Strings; + +@APICommand(name = ImportUnmanagedInstanceCmd.API_NAME, + description = "Import unmanaged virtual machine from a given cluster.", + responseObject = UserVmResponse.class, + responseView = ResponseObject.ResponseView.Full, + requestHasSensitiveInfo = false, + responseHasSensitiveInfo = true, + authorized = {RoleType.Admin}, + since = "4.14.0") +public class ImportUnmanagedInstanceCmd extends BaseAsyncCmd { + public static final Logger LOGGER = Logger.getLogger(ImportUnmanagedInstanceCmd.class); + public static final String API_NAME = "importUnmanagedInstance"; + + @Inject + public VmImportService vmImportService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.CLUSTER_ID, + type = CommandType.UUID, + entityType = ClusterResponse.class, + required = true, + description = "the cluster ID") + private Long clusterId; + + @Parameter(name = ApiConstants.NAME, + type = CommandType.STRING, + required = true, + description = "the hypervisor name of the instance") + private String name; + + @Parameter(name = ApiConstants.DISPLAY_NAME, + type = CommandType.STRING, + description = "the display name of the instance") + private String displayName; + + @Parameter(name = ApiConstants.HOST_NAME, + type = CommandType.STRING, + description = "the host name of the instance") + private String hostName; + + @Parameter(name = ApiConstants.ACCOUNT, + type = CommandType.STRING, + description = "an optional account for the virtual machine. Must be used with domainId.") + private String accountName; + + @Parameter(name = ApiConstants.DOMAIN_ID, + type = CommandType.UUID, + entityType = DomainResponse.class, + description = "import instance to the domain specified") + private Long domainId; + + @Parameter(name = ApiConstants.PROJECT_ID, + type = CommandType.UUID, + entityType = ProjectResponse.class, + description = "import instance for the project") + private Long projectId; + + @Parameter(name = ApiConstants.TEMPLATE_ID, + type = CommandType.UUID, + entityType = TemplateResponse.class, + description = "the ID of the template for the virtual machine") + private Long templateId; + + @Parameter(name = ApiConstants.SERVICE_OFFERING_ID, + type = CommandType.UUID, + entityType = ServiceOfferingResponse.class, + required = true, + description = "the ID of the service offering for the virtual machine") + private Long serviceOfferingId; + + @Parameter(name = ApiConstants.NIC_NETWORK_LIST, + type = CommandType.MAP, + description = "VM nic to network id mapping using keys nic and network") + private Map nicNetworkList; + + @Parameter(name = ApiConstants.NIC_IP_ADDRESS_LIST, + type = CommandType.MAP, + description = "VM nic to ip address mapping using keys nic, ip4Address") + private Map nicIpAddressList; + + @Parameter(name = ApiConstants.DATADISK_OFFERING_LIST, + type = CommandType.MAP, + description = "datadisk template to disk-offering mapping using keys disk and diskOffering") + private Map dataDiskToDiskOfferingList; + + @Parameter(name = ApiConstants.DETAILS, + type = CommandType.MAP, + description = "used to specify the custom parameters.") + private Map details; + + @Parameter(name = ApiConstants.MIGRATE_ALLOWED, + type = CommandType.BOOLEAN, + description = "vm and its volumes are allowed to migrate to different host/pool when offerings passed are incompatible with current host/pool") + private Boolean migrateAllowed; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getClusterId() { + return clusterId; + } + + public String getName() { + return name; + } + + public String getDisplayName() { + return displayName; + } + + public String getHostName() { + return hostName; + } + + public String getAccountName() { + return accountName; + } + + public Long getDomainId() { + return domainId; + } + + public Long getTemplateId() { + return templateId; + } + + public Long getProjectId() { + return projectId; + } + + public Long getServiceOfferingId() { + return serviceOfferingId; + } + + public Map getNicNetworkList() { + Map nicNetworkMap = new HashMap<>(); + if (MapUtils.isNotEmpty(nicNetworkList)) { + for (Map entry : (Collection>)nicNetworkList.values()) { + String nic = entry.get(VmDetailConstants.NIC); + String networkUuid = entry.get(VmDetailConstants.NETWORK); + if (Strings.isNullOrEmpty(nic) || Strings.isNullOrEmpty(networkUuid) || _entityMgr.findByUuid(Network.class, networkUuid) == null) { + throw new InvalidParameterValueException(String.format("Network ID: %s for NIC ID: %s is invalid", networkUuid, nic)); + } + nicNetworkMap.put(nic, _entityMgr.findByUuid(Network.class, networkUuid).getId()); + } + } + return nicNetworkMap; + } + + public Map getNicIpAddressList() { + Map nicIpAddressMap = new HashMap<>(); + if (MapUtils.isNotEmpty(nicIpAddressList)) { + for (Map entry : (Collection>)nicIpAddressList.values()) { + String nic = entry.get(VmDetailConstants.NIC); + String ipAddress = Strings.emptyToNull(entry.get(VmDetailConstants.IP4_ADDRESS)); + if (Strings.isNullOrEmpty(nic)) { + throw new InvalidParameterValueException(String.format("NIC ID: '%s' is invalid for IP address mapping", nic)); + } + if (Strings.isNullOrEmpty(ipAddress)) { + throw new InvalidParameterValueException(String.format("IP address '%s' for NIC ID: %s is invalid", ipAddress, nic)); + } + if (!Strings.isNullOrEmpty(ipAddress) && !ipAddress.equals("auto") && !NetUtils.isValidIp4(ipAddress)) { + throw new InvalidParameterValueException(String.format("IP address '%s' for NIC ID: %s is invalid", ipAddress, nic)); + } + Network.IpAddresses ipAddresses = new Network.IpAddresses(ipAddress, null); + nicIpAddressMap.put(nic, ipAddresses); + } + } + return nicIpAddressMap; + } + + public Map getDataDiskToDiskOfferingList() { + Map dataDiskToDiskOfferingMap = new HashMap<>(); + if (MapUtils.isNotEmpty(dataDiskToDiskOfferingList)) { + for (Map entry : (Collection>)dataDiskToDiskOfferingList.values()) { + String nic = entry.get(VmDetailConstants.DISK); + String offeringUuid = entry.get(VmDetailConstants.DISK_OFFERING); + if (Strings.isNullOrEmpty(nic) || Strings.isNullOrEmpty(offeringUuid) || _entityMgr.findByUuid(DiskOffering.class, offeringUuid) == null) { + throw new InvalidParameterValueException(String.format("Disk offering ID: %s for disk ID: %s is invalid", offeringUuid, nic)); + } + dataDiskToDiskOfferingMap.put(nic, _entityMgr.findByUuid(DiskOffering.class, offeringUuid).getId()); + } + } + return dataDiskToDiskOfferingMap; + } + + public Map getDetails() { + if (MapUtils.isEmpty(details)) { + return new HashMap(); + } + + Collection paramsCollection = details.values(); + Map params = (Map) (paramsCollection.toArray())[0]; + return params; + } + + public Boolean getMigrateAllowed() { + return migrateAllowed == Boolean.TRUE; + } + + @Override + public String getEventType() { + return EventTypes.EVENT_VM_IMPORT; + } + + @Override + public String getEventDescription() { + return "Importing unmanaged VM"; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + UserVmResponse response = vmImportService.importUnmanagedInstance(this); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return API_NAME.toLowerCase() + BaseAsyncCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true); + if (accountId == null) { + Account account = CallContext.current().getCallingAccount(); + if (account != null) { + accountId = account.getId(); + } else { + accountId = Account.ACCOUNT_ID_SYSTEM; + } + } + return accountId; + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ListUnmanagedInstancesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ListUnmanagedInstancesCmd.java new file mode 100644 index 000000000000..a991ef4e03d6 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ListUnmanagedInstancesCmd.java @@ -0,0 +1,113 @@ +// 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.admin.vm; + +import javax.inject.Inject; + +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ResponseObject; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ClusterResponse; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.UnmanagedInstanceResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.vm.UnmanagedInstanceTO; +import org.apache.cloudstack.vm.VmImportService; +import org.apache.log4j.Logger; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; + +@APICommand(name = ListUnmanagedInstancesCmd.API_NAME, + description = "Lists unmanaged virtual machines for a given cluster.", + responseObject = UnmanagedInstanceResponse.class, + responseView = ResponseObject.ResponseView.Full, + entityType = {UnmanagedInstanceTO.class}, + requestHasSensitiveInfo = false, + responseHasSensitiveInfo = true, + authorized = {RoleType.Admin}, + since = "4.14.0") +public class ListUnmanagedInstancesCmd extends BaseListCmd { + public static final Logger LOGGER = Logger.getLogger(ListUnmanagedInstancesCmd.class.getName()); + public static final String API_NAME = "listUnmanagedInstances"; + + @Inject + public VmImportService vmImportService; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.CLUSTER_ID, + type = CommandType.UUID, + entityType = ClusterResponse.class, + required = true, + description = "the cluster ID") + private Long clusterId; + + @Parameter(name = ApiConstants.NAME, + type = CommandType.STRING, + description = "the hypervisor name of the instance") + private String name; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getClusterId() { + return clusterId; + } + + public String getName() { + return name; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + ListResponse response = vmImportService.listUnmanagedInstances(this); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + + @Override + public String getCommandName() { + return API_NAME.toLowerCase() + BaseAsyncCmd.RESPONSE_SUFFIX; + } + + @Override + public long getEntityOwnerId() { + Account account = CallContext.current().getCallingAccount(); + if (account != null) { + return account.getId(); + } + return Account.ACCOUNT_ID_SYSTEM; + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/response/DomainRouterResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/DomainRouterResponse.java index 131e3e1de7ed..f69f0153dae3 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/DomainRouterResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/DomainRouterResponse.java @@ -20,8 +20,6 @@ import java.util.LinkedHashSet; import java.util.Set; -import com.google.gson.annotations.SerializedName; - import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; @@ -29,6 +27,7 @@ import com.cloud.serializer.Param; import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.State; +import com.google.gson.annotations.SerializedName; @EntityReference(value = VirtualMachine.class) @SuppressWarnings("unused") @@ -258,6 +257,10 @@ public void setGateway(String gateway) { this.gateway = gateway; } + public String getName() { + return name; + } + public void setName(String name) { this.name = name; } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/NicResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/NicResponse.java index 5c3fd7a75a67..72a2bbcabfd5 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/NicResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/NicResponse.java @@ -16,14 +16,15 @@ // under the License. package org.apache.cloudstack.api.response; -import com.cloud.serializer.Param; -import com.cloud.vm.Nic; -import com.google.gson.annotations.SerializedName; +import java.util.List; + import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; -import java.util.List; +import com.cloud.serializer.Param; +import com.cloud.vm.Nic; +import com.google.gson.annotations.SerializedName; @SuppressWarnings("unused") @EntityReference(value = Nic.class) @@ -113,6 +114,26 @@ public class NicResponse extends BaseResponse { @Param(description = "Id of the NSX Logical Switch Port (if NSX based), null otherwise", since="4.6.0") private String nsxLogicalSwitchPort; + @SerializedName(ApiConstants.VLAN_ID) + @Param(description = "ID of the VLAN/VNI if available", since="4.14.0") + private Integer vlanId; + + @SerializedName(ApiConstants.ISOLATED_PVLAN) + @Param(description = "the isolated private VLAN if available", since="4.14.0") + private Integer isolatedPvlanId; + + @SerializedName(ApiConstants.ISOLATED_PVLAN_TYPE) + @Param(description = "the isolated private VLAN type if available", since="4.14.0") + private String isolatedPvlanType; + + @SerializedName(ApiConstants.ADAPTER_TYPE) + @Param(description = "Type of adapter if available", since="4.14.0") + private String adapterType; + + @SerializedName(ApiConstants.IP_ADDRESSES) + @Param(description = "IP addresses associated with NIC found for unmanaged VM", since="4.14.0") + private List ipAddresses; + public void setVmId(String vmId) { this.vmId = vmId; } @@ -303,4 +324,44 @@ public String getNsxLogicalSwitch() { public String getNsxLogicalSwitchPort() { return nsxLogicalSwitchPort; } + + public Integer getVlanId() { + return vlanId; + } + + public void setVlanId(Integer vlanId) { + this.vlanId = vlanId; + } + + public Integer getIsolatedPvlanId() { + return isolatedPvlanId; + } + + public void setIsolatedPvlanId(Integer isolatedPvlanId) { + this.isolatedPvlanId = isolatedPvlanId; + } + + public String getIsolatedPvlanType() { + return isolatedPvlanType; + } + + public void setIsolatedPvlanType(String isolatedPvlanType) { + this.isolatedPvlanType = isolatedPvlanType; + } + + public String getAdapterType() { + return adapterType; + } + + public void setAdapterType(String adapterType) { + this.adapterType = adapterType; + } + + public List getIpAddresses() { + return ipAddresses; + } + + public void setIpAddresses(List ipAddresses) { + this.ipAddresses = ipAddresses; + } } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/UnmanagedInstanceDiskResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/UnmanagedInstanceDiskResponse.java new file mode 100644 index 000000000000..083c83fbf85a --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/response/UnmanagedInstanceDiskResponse.java @@ -0,0 +1,159 @@ +// 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 org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +public class UnmanagedInstanceDiskResponse extends BaseResponse { + + @SerializedName(ApiConstants.ID) + @Param(description = "the ID of the disk") + private String diskId; + + @SerializedName(ApiConstants.LABEL) + @Param(description = "the label of the disk") + private String label; + + @SerializedName(ApiConstants.CAPACITY) + @Param(description = "the capacity of the disk in bytes") + private Long capacity; + + @SerializedName(ApiConstants.IMAGE_PATH) + @Param(description = "the file path of the disk image") + private String imagePath; + + @SerializedName(ApiConstants.CONTROLLER) + @Param(description = "the controller of the disk") + private String controller; + + @SerializedName(ApiConstants.CONTROLLER_UNIT) + @Param(description = "the controller unit of the disk") + private Integer controllerUnit; + + @SerializedName(ApiConstants.POSITION) + @Param(description = "the position of the disk") + private Integer position; + + @SerializedName(ApiConstants.DATASTORE_NAME) + @Param(description = "the controller of the disk") + private String datastoreName; + + @SerializedName(ApiConstants.DATASTORE_HOST) + @Param(description = "the controller of the disk") + private String datastoreHost; + + @SerializedName(ApiConstants.DATASTORE_PATH) + @Param(description = "the controller of the disk") + private String datastorePath; + + @SerializedName(ApiConstants.DATASTORE_TYPE) + @Param(description = "the controller of the disk") + private String datastoreType; + + public String getDiskId() { + return diskId; + } + + public void setDiskId(String diskId) { + this.diskId = diskId; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public Long getCapacity() { + return capacity; + } + + public void setCapacity(Long capacity) { + this.capacity = capacity; + } + + public String getImagePath() { + return imagePath; + } + + public void setImagePath(String imagePath) { + this.imagePath = imagePath; + } + + public String getController() { + return controller; + } + + public void setController(String controller) { + this.controller = controller; + } + + public Integer getControllerUnit() { + return controllerUnit; + } + + public void setControllerUnit(Integer controllerUnit) { + this.controllerUnit = controllerUnit; + } + + public Integer getPosition() { + return position; + } + + public void setPosition(Integer position) { + this.position = position; + } + + public String getDatastoreName() { + return datastoreName; + } + + public void setDatastoreName(String datastoreName) { + this.datastoreName = datastoreName; + } + + public String getDatastoreHost() { + return datastoreHost; + } + + public void setDatastoreHost(String datastoreHost) { + this.datastoreHost = datastoreHost; + } + + public String getDatastorePath() { + return datastorePath; + } + + public void setDatastorePath(String datastorePath) { + this.datastorePath = datastorePath; + } + + public String getDatastoreType() { + return datastoreType; + } + + public void setDatastoreType(String datastoreType) { + this.datastoreType = datastoreType; + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/response/UnmanagedInstanceResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/UnmanagedInstanceResponse.java new file mode 100644 index 000000000000..5167f1788ce1 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/response/UnmanagedInstanceResponse.java @@ -0,0 +1,190 @@ +// 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.LinkedHashSet; +import java.util.Set; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; +import org.apache.cloudstack.vm.UnmanagedInstanceTO; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; + +@EntityReference(value = UnmanagedInstanceTO.class) +public class UnmanagedInstanceResponse extends BaseResponse { + + @SerializedName(ApiConstants.NAME) + @Param(description = "the name of the virtual machine") + private String name; + + @SerializedName(ApiConstants.CLUSTER_ID) + @Param(description = "the ID of the cluster to which virtual machine belongs") + private String clusterId; + + @SerializedName(ApiConstants.HOST_ID) + @Param(description = "the ID of the host to which virtual machine belongs") + private String hostId; + + @SerializedName(ApiConstants.POWER_STATE) + @Param(description = "the power state of the virtual machine") + private String powerState; + + @SerializedName(ApiConstants.CPU_NUMBER) + @Param(description = "the CPU cores of the virtual machine") + private Integer cpuCores; + + @SerializedName(ApiConstants.CPU_CORE_PER_SOCKET) + @Param(description = "the CPU cores per socket for the virtual machine. VMware specific") + private Integer cpuCoresPerSocket; + + @SerializedName(ApiConstants.CPU_SPEED) + @Param(description = "the CPU speed of the virtual machine") + private Integer cpuSpeed; + + @SerializedName(ApiConstants.MEMORY) + @Param(description = "the memory of the virtual machine in MB") + private Integer memory; + + @SerializedName(ApiConstants.OS_ID) + @Param(description = "the operating system ID of the virtual machine") + private String operatingSystemId; + + @SerializedName(ApiConstants.OS_DISPLAY_NAME) + @Param(description = "the operating system of the virtual machine") + private String operatingSystem; + + @SerializedName(ApiConstants.DISK) + @Param(description = "the list of disks associated with the virtual machine", responseObject = UnmanagedInstanceDiskResponse.class) + private Set disks; + + @SerializedName(ApiConstants.NIC) + @Param(description = "the list of nics associated with the virtual machine", responseObject = NicResponse.class) + private Set nics; + + public UnmanagedInstanceResponse() { + disks = new LinkedHashSet(); + nics = new LinkedHashSet(); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getClusterId() { + return clusterId; + } + + public void setClusterId(String clusterId) { + this.clusterId = clusterId; + } + + public String getHostId() { + return hostId; + } + + public void setHostId(String hostId) { + this.hostId = hostId; + } + + public String getPowerState() { + return powerState; + } + + public void setPowerState(String powerState) { + this.powerState = powerState; + } + + public Integer getCpuCores() { + return cpuCores; + } + + public void setCpuCores(Integer cpuCores) { + this.cpuCores = cpuCores; + } + + public Integer getCpuCoresPerSocket() { + return cpuCoresPerSocket; + } + + public void setCpuCoresPerSocket(Integer cpuCoresPerSocket) { + this.cpuCoresPerSocket = cpuCoresPerSocket; + } + + public Integer getCpuSpeed() { + return cpuSpeed; + } + + public void setCpuSpeed(Integer cpuSpeed) { + this.cpuSpeed = cpuSpeed; + } + + public Integer getMemory() { + return memory; + } + + public void setMemory(Integer memory) { + this.memory = memory; + } + + public String getOperatingSystemId() { + return operatingSystemId; + } + + public void setOperatingSystemId(String operatingSystemId) { + this.operatingSystemId = operatingSystemId; + } + + public String getOperatingSystem() { + return operatingSystem; + } + + public void setOperatingSystem(String operatingSystem) { + this.operatingSystem = operatingSystem; + } + + public Set getDisks() { + return disks; + } + + public void setDisks(Set disks) { + this.disks = disks; + } + + public void addDisk(UnmanagedInstanceDiskResponse disk) { + this.disks.add(disk); + } + + public Set getNics() { + return nics; + } + + public void setNics(Set nics) { + this.nics = nics; + } + + public void addNic(NicResponse nic) { + this.nics.add(nic); + } +} diff --git a/api/src/main/java/org/apache/cloudstack/vm/UnmanagedInstanceTO.java b/api/src/main/java/org/apache/cloudstack/vm/UnmanagedInstanceTO.java new file mode 100644 index 000000000000..860ecdc3ba14 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/vm/UnmanagedInstanceTO.java @@ -0,0 +1,353 @@ +// 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.List; + +public class UnmanagedInstanceTO { + + public enum PowerState { + PowerUnknown, + PowerOn, + PowerOff + } + + private String name; + + private PowerState powerState; + + private Integer cpuCores; + + private Integer cpuCoresPerSocket; + + private Integer memory; + + private Integer cpuSpeed; + + private String operatingSystemId; + + private String operatingSystem; + + private List disks; + + private List nics; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public PowerState getPowerState() { + return powerState; + } + + public void setPowerState(PowerState powerState) { + this.powerState = powerState; + } + + public Integer getCpuCores() { + return cpuCores; + } + + public void setCpuCores(Integer cpuCores) { + this.cpuCores = cpuCores; + } + + public Integer getCpuCoresPerSocket() { + return cpuCoresPerSocket; + } + + public void setCpuCoresPerSocket(Integer cpuCoresPerSocket) { + this.cpuCoresPerSocket = cpuCoresPerSocket; + } + + public Integer getMemory() { + return memory; + } + + public void setMemory(Integer memory) { + this.memory = memory; + } + + public Integer getCpuSpeed() { + return cpuSpeed; + } + + public void setCpuSpeed(Integer cpuSpeed) { + this.cpuSpeed = cpuSpeed; + } + + public String getOperatingSystemId() { + return operatingSystemId; + } + + public void setOperatingSystemId(String operatingSystemId) { + this.operatingSystemId = operatingSystemId; + } + + public String getOperatingSystem() { + return operatingSystem; + } + + public void setOperatingSystem(String operatingSystem) { + this.operatingSystem = operatingSystem; + } + + public List getDisks() { + return disks; + } + + public void setDisks(List disks) { + this.disks = disks; + } + + public List getNics() { + return nics; + } + + public void setNics(List nics) { + this.nics = nics; + } + + public static class Disk { + private String diskId; + + private String label; + + private Long capacity; + + private String fileBaseName; + + private String imagePath; + + private String controller; + + private Integer controllerUnit; + + private Integer position; + + private String chainInfo; + + private String datastoreName; + + private String datastoreHost; + + private String datastorePath; + + private String datastoreType; + + public String getDiskId() { + return diskId; + } + + public void setDiskId(String diskId) { + this.diskId = diskId; + } + + public String getLabel() { + return label; + } + + public void setLabel(String label) { + this.label = label; + } + + public Long getCapacity() { + return capacity; + } + + public void setCapacity(Long capacity) { + this.capacity = capacity; + } + + public String getFileBaseName() { + return fileBaseName; + } + + public void setFileBaseName(String fileBaseName) { + this.fileBaseName = fileBaseName; + } + + public String getImagePath() { + return imagePath; + } + + public void setImagePath(String imagePath) { + this.imagePath = imagePath; + } + + public String getController() { + return controller; + } + + public void setController(String controller) { + this.controller = controller; + } + + public Integer getControllerUnit() { + return controllerUnit; + } + + public void setControllerUnit(Integer controllerUnit) { + this.controllerUnit = controllerUnit; + } + + public Integer getPosition() { + return position; + } + + public void setPosition(Integer position) { + this.position = position; + } + + public String getChainInfo() { + return chainInfo; + } + + public void setChainInfo(String chainInfo) { + this.chainInfo = chainInfo; + } + + public String getDatastoreName() { + return datastoreName; + } + + public void setDatastoreName(String datastoreName) { + this.datastoreName = datastoreName; + } + + public String getDatastoreHost() { + return datastoreHost; + } + + public void setDatastoreHost(String datastoreHost) { + this.datastoreHost = datastoreHost; + } + + public String getDatastorePath() { + return datastorePath; + } + + public void setDatastorePath(String datastorePath) { + this.datastorePath = datastorePath; + } + + public String getDatastoreType() { + return datastoreType; + } + + public void setDatastoreType(String datastoreType) { + this.datastoreType = datastoreType; + } + } + + public static class Nic { + private String nicId; + + private String adapterType; + + private String macAddress; + + private String network; + + private Integer vlan; + + private Integer pvlan; + + private String pvlanType; + + private List ipAddress; + + private String pciSlot; + + public String getNicId() { + return nicId; + } + + public void setNicId(String nicId) { + this.nicId = nicId; + } + + public String getAdapterType() { + return adapterType; + } + + public void setAdapterType(String adapterType) { + this.adapterType = adapterType; + } + + public String getMacAddress() { + return macAddress; + } + + public void setMacAddress(String macAddress) { + this.macAddress = macAddress; + } + + public String getNetwork() { + return network; + } + + public void setNetwork(String network) { + this.network = network; + } + + public Integer getVlan() { + return vlan; + } + + public void setVlan(Integer vlan) { + this.vlan = vlan; + } + + public Integer getPvlan() { + return pvlan; + } + + public void setPvlan(Integer pvlan) { + this.pvlan = pvlan; + } + + public String getPvlanType() { + return pvlanType; + } + + public void setPvlanType(String pvlanType) { + this.pvlanType = pvlanType; + } + + public List getIpAddress() { + return ipAddress; + } + + public void setIpAddress(List ipAddress) { + this.ipAddress = ipAddress; + } + + public String getPciSlot() { + return pciSlot; + } + + public void setPciSlot(String pciSlot) { + this.pciSlot = pciSlot; + } + } +} diff --git a/api/src/main/java/org/apache/cloudstack/vm/VmImportService.java b/api/src/main/java/org/apache/cloudstack/vm/VmImportService.java new file mode 100644 index 000000000000..783a5d295eed --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/vm/VmImportService.java @@ -0,0 +1,31 @@ +// 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 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.UnmanagedInstanceResponse; +import org.apache.cloudstack.api.response.UserVmResponse; + +import com.cloud.utils.component.PluggableService; + +public interface VmImportService extends PluggableService { + ListResponse listUnmanagedInstances(ListUnmanagedInstancesCmd cmd); + UserVmResponse importUnmanagedInstance(ImportUnmanagedInstanceCmd cmd); +} diff --git a/core/src/main/java/com/cloud/agent/api/GetUnmanagedInstancesAnswer.java b/core/src/main/java/com/cloud/agent/api/GetUnmanagedInstancesAnswer.java new file mode 100644 index 000000000000..3c6118d426e6 --- /dev/null +++ b/core/src/main/java/com/cloud/agent/api/GetUnmanagedInstancesAnswer.java @@ -0,0 +1,58 @@ +// 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 com.cloud.agent.api; + +import java.util.HashMap; + +import org.apache.cloudstack.vm.UnmanagedInstanceTO; + +@LogLevel(LogLevel.Log4jLevel.Trace) +public class GetUnmanagedInstancesAnswer extends Answer { + + private String instanceName; + private HashMap unmanagedInstances; + + GetUnmanagedInstancesAnswer() { + } + + public GetUnmanagedInstancesAnswer(GetUnmanagedInstancesCommand cmd, String details, HashMap unmanagedInstances) { + super(cmd, true, details); + this.instanceName = cmd.getInstanceName(); + this.unmanagedInstances = unmanagedInstances; + } + + public String getInstanceName() { + return instanceName; + } + + public void setInstanceName(String instanceName) { + this.instanceName = instanceName; + } + + public HashMap getUnmanagedInstances() { + return unmanagedInstances; + } + + public void setUnmanagedInstances(HashMap unmanagedInstances) { + this.unmanagedInstances = unmanagedInstances; + } + + public String getString() { + return "GetUnmanagedInstancesAnswer [instanceName=" + instanceName + "]"; + } +} diff --git a/core/src/main/java/com/cloud/agent/api/GetUnmanagedInstancesCommand.java b/core/src/main/java/com/cloud/agent/api/GetUnmanagedInstancesCommand.java new file mode 100644 index 000000000000..968c58611bb7 --- /dev/null +++ b/core/src/main/java/com/cloud/agent/api/GetUnmanagedInstancesCommand.java @@ -0,0 +1,73 @@ +// 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 com.cloud.agent.api; + +import java.util.List; + +/** + * Unmanaged instances are those virtual machines which are present at hypervisor end but not available in CloudStack. + * Such virtual machines might have been created out of band, directly from hypervisor. + * Managed instances will be those virtual machines that are created from CloudStack or CloudStack have database record for them. + * All managed instances will be filtered while trying to find unmanaged instances. + */ + +@LogLevel(LogLevel.Log4jLevel.Trace) +public class GetUnmanagedInstancesCommand extends Command { + + String instanceName; + List managedInstancesNames; + + public GetUnmanagedInstancesCommand() { + } + + public GetUnmanagedInstancesCommand(String instanceName) { + this.instanceName = instanceName; + } + + public String getInstanceName() { + return instanceName; + } + + public void setInstanceName(String instanceName) { + this.instanceName = instanceName; + } + + public List getManagedInstancesNames() { + return managedInstancesNames; + } + + public void setManagedInstancesNames(List managedInstancesNames) { + this.managedInstancesNames = managedInstancesNames; + } + + public boolean hasManagedInstance(String name) { + if (managedInstancesNames!=null && !managedInstancesNames.isEmpty()) { + return managedInstancesNames.contains(name); + } + return false; + } + + @Override + public boolean executeInSequence() { + return false; + } + + public String getString() { + return "GetUnmanagedInstancesCommand [instanceName=" + instanceName + "]"; + } +} diff --git a/debian/cloudstack-common.install b/debian/cloudstack-common.install index accc6fadfa22..9a9cf3bbc09f 100644 --- a/debian/cloudstack-common.install +++ b/debian/cloudstack-common.install @@ -26,6 +26,7 @@ /usr/share/cloudstack-common/scripts/vm/hypervisor/kvm/* /usr/share/cloudstack-common/scripts/vm/hypervisor/update_host_passwd.sh /usr/share/cloudstack-common/scripts/vm/hypervisor/versions.sh +/usr/share/cloudstack-common/scripts/vm/hypervisor/vmware/* /usr/share/cloudstack-common/scripts/vm/hypervisor/xenserver/* /usr/share/cloudstack-common/lib/* /usr/bin/cloudstack-set-guest-password diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java index 94a4259a6897..b111a86c930b 100644 --- a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java +++ b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java @@ -23,6 +23,7 @@ import org.apache.cloudstack.acl.ControlledEntity.ACLType; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.ConfigKey.Scope; + import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; @@ -313,4 +314,6 @@ void implementNetworkElementsAndResources(DeployDestination dest, ReservationCon * Remove entry from /etc/dhcphosts and /etc/hosts on virtual routers */ void cleanupNicDhcpDnsEntry(Network network, VirtualMachineProfile vmProfile, NicProfile nicProfile); + + Pair importNic(final String macAddress, int deviceId, final Network network, final Boolean isDefaultNic, final VirtualMachine vm, final Network.IpAddresses ipAddresses) throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException; } diff --git a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java index fa6f2c6fb9d4..a769a3428b5e 100644 --- a/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java +++ b/engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/VolumeOrchestrationService.java @@ -88,6 +88,8 @@ VolumeInfo moveVolume(VolumeInfo volume, long destPoolDcId, Long destPoolPodId, Volume migrateVolume(Volume volume, StoragePool destPool) throws StorageUnavailableException; + Volume liveMigrateVolume(Volume volume, StoragePool destPool); + void cleanupStorageJobs(); void destroyVolume(Volume volume); @@ -127,4 +129,24 @@ DiskProfile allocateTemplatedVolume(Type type, String name, DiskOffering offerin StoragePool findStoragePool(DiskProfile dskCh, DataCenter dc, Pod pod, Long clusterId, Long hostId, VirtualMachine vm, Set avoid); void updateVolumeDiskChain(long volumeId, String path, String chainInfo); + + /** + * Imports an existing volume for a VM into database. Useful while ingesting an unmanaged VM. + * @param type Type of the volume - ROOT, DATADISK, etc + * @param name Name of the volume + * @param offering DiskOffering for the volume + * @param size DiskOffering for the volume + * @param minIops minimum IOPS for the disk, if not passed DiskOffering value will be used + * @param maxIops maximum IOPS for the disk, if not passed DiskOffering value will be used + * @param vm VirtualMachine this volume is attached to + * @param template Template of the VM of the volume + * @param owner owner Account for the volume + * @param deviceId device ID of the virtual disk + * @param poolId ID of pool in which volume is stored + * @param path image path of the volume + * @param chainInfo chain info for the volume. Hypervisor specific. + * @return DiskProfile of imported volume + */ + DiskProfile importVolume(Type type, String name, DiskOffering offering, Long size, Long minIops, Long maxIops, VirtualMachine vm, VirtualMachineTemplate template, + Account owner, Long deviceId, Long poolId, String path, String chainInfo); } diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index 80ee71eef9bf..acbdde2cd729 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -3950,6 +3950,71 @@ public NicVO savePlaceholderNic(final Network network, final String ip4Address, return _nicDao.persist(nic); } + @DB + @Override + public Pair importNic(final String macAddress, int deviceId, final Network network, final Boolean isDefaultNic, final VirtualMachine vm, final Network.IpAddresses ipAddresses) + throws ConcurrentOperationException, InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { + s_logger.debug("Allocating nic for vm " + vm.getUuid() + " in network " + network + " during import"); + String guestIp = null; + if (ipAddresses != null && !Strings.isNullOrEmpty(ipAddresses.getIp4Address())) { + if (ipAddresses.getIp4Address().equals("auto")) { + ipAddresses.setIp4Address(null); + } + if (network.getGuestType() != GuestType.L2) { + guestIp = _ipAddrMgr.acquireGuestIpAddress(network, ipAddresses.getIp4Address()); + } else { + guestIp = null; + } + if (guestIp == null && network.getGuestType() != GuestType.L2 && !_networkModel.listNetworkOfferingServices(network.getNetworkOfferingId()).isEmpty()) { + throw new InsufficientVirtualNetworkCapacityException("Unable to acquire Guest IP address for network " + network, DataCenter.class, + network.getDataCenterId()); + } + } + final String finalGuestIp = guestIp; + final NicVO vo = Transaction.execute(new TransactionCallback() { + @Override + public NicVO doInTransaction(TransactionStatus status) { + NicVO vo = new NicVO(network.getGuruName(), vm.getId(), network.getId(), vm.getType()); + vo.setMacAddress(macAddress); + vo.setAddressFormat(Networks.AddressFormat.Ip4); + if (NetUtils.isValidIp4(finalGuestIp) && !Strings.isNullOrEmpty(network.getGateway())) { + vo.setIPv4Address(finalGuestIp); + vo.setIPv4Gateway(network.getGateway()); + if (!Strings.isNullOrEmpty(network.getCidr())) { + vo.setIPv4Netmask(NetUtils.cidr2Netmask(network.getCidr())); + } + } + vo.setBroadcastUri(network.getBroadcastUri()); + vo.setMode(network.getMode()); + vo.setState(Nic.State.Reserved); + vo.setReservationStrategy(ReservationStrategy.Start); + vo.setReservationId(UUID.randomUUID().toString()); + vo.setIsolationUri(network.getBroadcastUri()); + vo.setDeviceId(deviceId); + vo.setDefaultNic(isDefaultNic); + vo = _nicDao.persist(vo); + + int count = 1; + if (vo.getVmType() == VirtualMachine.Type.User) { + s_logger.debug("Changing active number of nics for network id=" + network.getUuid() + " on " + count); + _networksDao.changeActiveNicsBy(network.getId(), count); + } + if (vo.getVmType() == VirtualMachine.Type.User + || vo.getVmType() == VirtualMachine.Type.DomainRouter && _networksDao.findById(network.getId()).getTrafficType() == TrafficType.Guest) { + _networksDao.setCheckForGc(network.getId()); + } + + return vo; + } + }); + + final Integer networkRate = _networkModel.getNetworkRate(network.getId(), vm.getId()); + final NicProfile vmNic = new NicProfile(vo, network, vo.getBroadcastUri(), vo.getIsolationUri(), networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network), + _networkModel.getNetworkTag(vm.getHypervisorType(), network)); + + return new Pair(vmNic, Integer.valueOf(deviceId)); + } + @Override public String getConfigComponentName() { return NetworkOrchestrationService.class.getSimpleName(); diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java index 6e71864c4473..593891ea068d 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/VolumeOrchestrator.java @@ -30,7 +30,6 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; -import com.cloud.storage.VolumeApiService; import org.apache.cloudstack.api.command.admin.vm.MigrateVMCmd; import org.apache.cloudstack.api.command.admin.volume.MigrateVolumeCmdByAdmin; import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd; @@ -106,6 +105,7 @@ import com.cloud.storage.VMTemplateStorageResourceAssoc; import com.cloud.storage.Volume; import com.cloud.storage.Volume.Type; +import com.cloud.storage.VolumeApiService; import com.cloud.storage.VolumeVO; import com.cloud.storage.dao.SnapshotDao; import com.cloud.storage.dao.VolumeDao; @@ -1005,10 +1005,12 @@ public Volume migrateVolume(Volume volume, StoragePool destPool) throws StorageU } } + @Override @DB - protected Volume liveMigrateVolume(Volume volume, StoragePool destPool) { + public Volume liveMigrateVolume(Volume volume, StoragePool destPool) { VolumeInfo vol = volFactory.getVolume(volume.getId()); - AsyncCallFuture future = volService.migrateVolume(vol, (DataStore)destPool); + DataStore dataStoreTarget = dataStoreMgr.getDataStore(destPool.getId(), DataStoreRole.Primary); + AsyncCallFuture future = volService.migrateVolume(vol, dataStoreTarget); try { VolumeApiResult result = future.get(); if (result.isFailed()) { @@ -1626,4 +1628,56 @@ public void updateVolumeDiskChain(long volumeId, String path, String chainInfo) _volsDao.update(volumeId, vol); } } + + @Override + public DiskProfile importVolume(Type type, String name, DiskOffering offering, Long size, Long minIops, Long maxIops, + VirtualMachine vm, VirtualMachineTemplate template, Account owner, + Long deviceId, Long poolId, String path, String chainInfo) { + if (size == null) { + size = offering.getDiskSize(); + } else { + size = (size * 1024 * 1024 * 1024); + } + + minIops = minIops != null ? minIops : offering.getMinIops(); + maxIops = maxIops != null ? maxIops : offering.getMaxIops(); + + VolumeVO vol = new VolumeVO(type, name, vm.getDataCenterId(), owner.getDomainId(), owner.getId(), offering.getId(), offering.getProvisioningType(), size, minIops, maxIops, null); + if (vm != null) { + vol.setInstanceId(vm.getId()); + } + + if (deviceId != null) { + vol.setDeviceId(deviceId); + } else if (type.equals(Type.ROOT)) { + vol.setDeviceId(0l); + } else { + vol.setDeviceId(1l); + } + + if (template != null) { + if (ImageFormat.ISO.equals(template.getFormat())) { + vol.setIsoId(template.getId()); + } else if (Storage.TemplateType.DATADISK.equals(template.getTemplateType())) { + vol.setTemplateId(template.getId()); + } + if (type == Type.ROOT) { + vol.setTemplateId(template.getId()); + } + } + + // display flag matters only for the User vms + if (VirtualMachine.Type.User.equals(vm.getType())) { + UserVmVO userVm = _userVmDao.findById(vm.getId()); + vol.setDisplayVolume(userVm.isDisplayVm()); + } + + vol.setFormat(getSupportedImageFormatForCluster(vm.getHypervisorType())); + vol.setPoolId(poolId); + vol.setPath(path); + vol.setChainInfo(chainInfo); + vol.setState(Volume.State.Ready); + vol = _volsDao.persist(vol); + return toDiskProfile(vol, offering); + } } diff --git a/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDao.java b/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDao.java index 74728f826ce5..8ac44b99c1d5 100644 --- a/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDao.java +++ b/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDao.java @@ -48,7 +48,7 @@ List createSystemServiceOfferings(String name, String uniqueN boolean isDynamic(long serviceOfferingId); - ServiceOfferingVO getcomputeOffering(ServiceOfferingVO serviceOffering, Map customParameters); + ServiceOfferingVO getComputeOffering(ServiceOfferingVO serviceOffering, Map customParameters); ServiceOfferingVO findDefaultSystemOffering(String offeringName, Boolean useLocalStorage); } diff --git a/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDaoImpl.java b/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDaoImpl.java index 96b0c350a741..76e867b8f538 100644 --- a/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/service/dao/ServiceOfferingDaoImpl.java @@ -161,7 +161,7 @@ public ServiceOfferingVO findById(Long vmId, long serviceOfferingId) { throw new CloudRuntimeException("missing argument vmId"); } Map dynamicOffering = userVmDetailsDao.listDetailsKeyPairs(vmId); - return getcomputeOffering(offering, dynamicOffering); + return getComputeOffering(offering, dynamicOffering); } return offering; } @@ -175,7 +175,7 @@ public ServiceOfferingVO findByIdIncludingRemoved(Long vmId, long serviceOfferin throw new CloudRuntimeException("missing argument vmId"); } Map dynamicOffering = userVmDetailsDao.listDetailsKeyPairs(vmId); - return getcomputeOffering(offering, dynamicOffering); + return getComputeOffering(offering, dynamicOffering); } return offering; } @@ -187,7 +187,7 @@ public boolean isDynamic(long serviceOfferingId) { } @Override - public ServiceOfferingVO getcomputeOffering(ServiceOfferingVO serviceOffering, Map customParameters) { + public ServiceOfferingVO getComputeOffering(ServiceOfferingVO serviceOffering, Map customParameters) { ServiceOfferingVO dummyoffering = new ServiceOfferingVO(serviceOffering); dummyoffering.setDynamicFlag(true); if (customParameters.containsKey(UsageEventVO.DynamicParameters.cpuNumber.name())) { diff --git a/engine/schema/src/main/java/com/cloud/storage/VMTemplateVO.java b/engine/schema/src/main/java/com/cloud/storage/VMTemplateVO.java index 30440d3dc745..af04099f9a2a 100644 --- a/engine/schema/src/main/java/com/cloud/storage/VMTemplateVO.java +++ b/engine/schema/src/main/java/com/cloud/storage/VMTemplateVO.java @@ -230,6 +230,13 @@ public static VMTemplateVO createPreHostIso(Long id, String uniqueName, String n return template; } + public static VMTemplateVO createSystemIso(Long id, String uniqueName, String name, boolean isPublic, + String url, boolean requiresHvm, int bits, long accountId, String cksum, + String displayText, boolean enablePassword, long guestOSId) { + return new VMTemplateVO(id, uniqueName, name, ImageFormat.ISO, isPublic, false, TemplateType.SYSTEM, url, null, requiresHvm, bits, accountId, cksum, displayText, enablePassword, + guestOSId, false, null); + } + public VMTemplateVO(Long id, String uniqueName, String name, ImageFormat format, boolean isPublic, boolean featured, TemplateType type, String url, Date created, boolean requiresHvm, int bits, long accountId, String cksum, String displayText, boolean enablePassword, long guestOSId, boolean bootable, HypervisorType hyperType) { diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSHypervisorDao.java b/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSHypervisorDao.java index a7775165265f..cd00703ce13e 100644 --- a/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSHypervisorDao.java +++ b/engine/schema/src/main/java/com/cloud/storage/dao/GuestOSHypervisorDao.java @@ -29,4 +29,6 @@ public interface GuestOSHypervisorDao extends GenericDao guestOsSearch; protected final SearchBuilder mappingSearch; protected final SearchBuilder userDefinedMappingSearch; + protected final SearchBuilder guestOsNameSearch; protected GuestOSHypervisorDaoImpl() { guestOsSearch = createSearchBuilder(); @@ -51,6 +54,12 @@ protected GuestOSHypervisorDaoImpl() { userDefinedMappingSearch.and("hypervisor_version", userDefinedMappingSearch.entity().getHypervisorVersion(), SearchCriteria.Op.EQ); userDefinedMappingSearch.and("is_user_defined", userDefinedMappingSearch.entity().getIsUserDefined(), SearchCriteria.Op.EQ); userDefinedMappingSearch.done(); + + guestOsNameSearch = createSearchBuilder(); + guestOsNameSearch.and("guest_os_name", guestOsNameSearch.entity().getGuestOsName(), SearchCriteria.Op.EQ); + guestOsNameSearch.and("hypervisor_type", guestOsNameSearch.entity().getHypervisorType(), SearchCriteria.Op.EQ); + guestOsNameSearch.and("hypervisor_version", guestOsNameSearch.entity().getHypervisorVersion(), SearchCriteria.Op.EQ); + guestOsNameSearch.done(); } @Override @@ -97,4 +106,19 @@ public boolean removeGuestOsMapping(Long id) { return super.remove(id); } + @Override + public GuestOSHypervisorVO findByOsNameAndHypervisor(String guestOsName, String hypervisorType, String hypervisorVersion) { + SearchCriteria sc = guestOsNameSearch.create(); + String version = "default"; + if (!(hypervisorVersion == null || hypervisorVersion.isEmpty())) { + version = hypervisorVersion; + } + sc.setParameters("guest_os_name", guestOsName); + sc.setParameters("hypervisor_type", hypervisorType); + sc.setParameters("hypervisor_version", version); + final Filter filter = new Filter(GuestOSHypervisorVO.class, "guestOsId", true, null, null); + List results = listIncludingRemovedBy(sc, filter); + return CollectionUtils.isNotEmpty(results) ? results.get(0) : null; + } + } diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDao.java b/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDao.java index 14f48ea06a86..2741307c0546 100644 --- a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDao.java +++ b/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDao.java @@ -96,6 +96,8 @@ public interface VolumeDao extends GenericDao, StateDao listZoneWidePoolIdsByVolumeCount(long dcId, long accountId); + List findIncludingRemovedByZone(long zoneId); + /** * Gets the Total Primary Storage space allocated for an account * diff --git a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java b/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java index e8ed3343831b..974d8e6f9cef 100644 --- a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java @@ -598,6 +598,13 @@ public List listZoneWidePoolIdsByVolumeCount(long dcId, long accountId) { } } + @Override + public List findIncludingRemovedByZone(long zoneId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("dcId", zoneId); + return searchIncludingRemoved(sc, null, null, false); + } + @Override @DB() public Pair getNonDestroyedCountAndTotalByPool(long poolId) { diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java index a7ed92252542..fad97478dc57 100755 --- a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java +++ b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java @@ -100,6 +100,8 @@ public interface VMInstanceDao extends GenericDao, StateDao< List listByLastHostId(Long hostId); + List listByLastHostIdAndStates(Long hostId, State... states); + List listByTypeAndState(VirtualMachine.Type type, State state); List listByAccountId(long accountId); diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java index 1945969f543a..9dac8fffc2e9 100755 --- a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java @@ -94,6 +94,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase implem protected SearchBuilder HostAndStateSearch; protected SearchBuilder StartingWithNoHostSearch; protected SearchBuilder NotMigratingSearch; + protected SearchBuilder LastHostAndStatesSearch; @Inject ResourceTagDao _tagsDao; @@ -286,6 +287,11 @@ protected void init() { NotMigratingSearch.and("lastHost", NotMigratingSearch.entity().getLastHostId(), Op.EQ); NotMigratingSearch.and("state", NotMigratingSearch.entity().getState(), Op.NEQ); NotMigratingSearch.done(); + + LastHostAndStatesSearch = createSearchBuilder(); + LastHostAndStatesSearch.and("lastHost", LastHostAndStatesSearch.entity().getLastHostId(), Op.EQ); + LastHostAndStatesSearch.and("states", LastHostAndStatesSearch.entity().getState(), Op.IN); + LastHostAndStatesSearch.done(); } @Override @@ -560,6 +566,14 @@ public List listByLastHostId(Long hostId) { return listBy(sc); } + @Override + public List listByLastHostIdAndStates(Long hostId, State... states) { + SearchCriteria sc = LastHostAndStatesSearch.create(); + sc.setParameters("lastHost", hostId); + sc.setParameters("states", (Object[])states); + return listBy(sc); + } + @Override public List findIdsOfAllocatedVirtualRoutersForAccount(long accountId) { SearchCriteria sc = FindIdsOfVirtualRoutersByAccount.create(); diff --git a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java index b5a1260a7230..7624f954e9db 100644 --- a/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java +++ b/plugins/hypervisors/vmware/src/main/java/com/cloud/hypervisor/vmware/resource/VmwareResource.java @@ -44,19 +44,6 @@ import javax.naming.ConfigurationException; import javax.xml.datatype.XMLGregorianCalendar; -import com.cloud.agent.api.storage.OVFPropertyTO; -import com.cloud.utils.crypt.DBEncryptionUtil; -import com.vmware.vim25.ArrayUpdateOperation; -import com.vmware.vim25.VAppOvfSectionInfo; -import com.vmware.vim25.VAppOvfSectionSpec; -import com.vmware.vim25.VAppProductInfo; -import com.vmware.vim25.VAppProductSpec; -import com.vmware.vim25.VAppPropertyInfo; -import com.vmware.vim25.VAppPropertySpec; -import com.vmware.vim25.VmConfigInfo; -import com.vmware.vim25.VmConfigSpec; -import org.apache.commons.collections.CollectionUtils; - import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.storage.command.CopyCommand; import org.apache.cloudstack.storage.command.StorageSubSystemCommand; @@ -66,6 +53,8 @@ import org.apache.cloudstack.storage.to.TemplateObjectTO; import org.apache.cloudstack.storage.to.VolumeObjectTO; import org.apache.cloudstack.utils.volume.VirtualMachineDiskInfo; +import org.apache.cloudstack.vm.UnmanagedInstanceTO; +import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang.math.NumberUtils; import org.apache.log4j.Logger; @@ -101,6 +90,8 @@ import com.cloud.agent.api.GetHostStatsCommand; import com.cloud.agent.api.GetStorageStatsAnswer; import com.cloud.agent.api.GetStorageStatsCommand; +import com.cloud.agent.api.GetUnmanagedInstancesAnswer; +import com.cloud.agent.api.GetUnmanagedInstancesCommand; import com.cloud.agent.api.GetVmDiskStatsAnswer; import com.cloud.agent.api.GetVmDiskStatsCommand; import com.cloud.agent.api.GetVmIpAddressCommand; @@ -184,6 +175,7 @@ import com.cloud.agent.api.storage.DestroyCommand; import com.cloud.agent.api.storage.MigrateVolumeAnswer; import com.cloud.agent.api.storage.MigrateVolumeCommand; +import com.cloud.agent.api.storage.OVFPropertyTO; import com.cloud.agent.api.storage.PrimaryStorageDownloadAnswer; import com.cloud.agent.api.storage.PrimaryStorageDownloadCommand; import com.cloud.agent.api.storage.ResizeVolumeAnswer; @@ -217,6 +209,7 @@ import com.cloud.hypervisor.vmware.mo.DatastoreFile; import com.cloud.hypervisor.vmware.mo.DatastoreMO; import com.cloud.hypervisor.vmware.mo.DiskControllerType; +import com.cloud.hypervisor.vmware.mo.DistributedVirtualSwitchMO; import com.cloud.hypervisor.vmware.mo.FeatureKeyConstants; import com.cloud.hypervisor.vmware.mo.HostDatastoreSystemMO; import com.cloud.hypervisor.vmware.mo.HostMO; @@ -255,6 +248,7 @@ import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; import com.cloud.utils.Ternary; +import com.cloud.utils.crypt.DBEncryptionUtil; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.ExceptionUtil; @@ -268,24 +262,30 @@ import com.cloud.vm.VirtualMachine.PowerState; import com.cloud.vm.VirtualMachineName; import com.cloud.vm.VmDetailConstants; +import com.google.common.base.Strings; import com.google.gson.Gson; import com.vmware.vim25.AboutInfo; +import com.vmware.vim25.ArrayUpdateOperation; import com.vmware.vim25.BoolPolicy; import com.vmware.vim25.ComputeResourceSummary; import com.vmware.vim25.CustomFieldStringValue; import com.vmware.vim25.DVPortConfigInfo; import com.vmware.vim25.DVPortConfigSpec; import com.vmware.vim25.DasVmPriority; +import com.vmware.vim25.DatastoreInfo; import com.vmware.vim25.DatastoreSummary; import com.vmware.vim25.DistributedVirtualPort; import com.vmware.vim25.DistributedVirtualSwitchPortConnection; import com.vmware.vim25.DistributedVirtualSwitchPortCriteria; import com.vmware.vim25.DynamicProperty; import com.vmware.vim25.GuestInfo; +import com.vmware.vim25.GuestNicInfo; import com.vmware.vim25.HostCapability; import com.vmware.vim25.HostHostBusAdapter; import com.vmware.vim25.HostInternetScsiHba; +import com.vmware.vim25.HostPortGroupSpec; import com.vmware.vim25.ManagedObjectReference; +import com.vmware.vim25.NasDatastoreInfo; import com.vmware.vim25.ObjectContent; import com.vmware.vim25.OptionValue; import com.vmware.vim25.PerfCounterInfo; @@ -297,18 +297,26 @@ import com.vmware.vim25.PerfQuerySpec; import com.vmware.vim25.RuntimeFaultFaultMsg; import com.vmware.vim25.ToolsUnavailableFaultMsg; +import com.vmware.vim25.VAppOvfSectionInfo; +import com.vmware.vim25.VAppOvfSectionSpec; +import com.vmware.vim25.VAppProductInfo; +import com.vmware.vim25.VAppProductSpec; +import com.vmware.vim25.VAppPropertyInfo; +import com.vmware.vim25.VAppPropertySpec; import com.vmware.vim25.VMwareDVSPortSetting; import com.vmware.vim25.VimPortType; import com.vmware.vim25.VirtualDevice; import com.vmware.vim25.VirtualDeviceBackingInfo; import com.vmware.vim25.VirtualDeviceConfigSpec; import com.vmware.vim25.VirtualDeviceConfigSpecOperation; +import com.vmware.vim25.VirtualDeviceFileBackingInfo; import com.vmware.vim25.VirtualDisk; import com.vmware.vim25.VirtualDiskFlatVer2BackingInfo; import com.vmware.vim25.VirtualEthernetCard; import com.vmware.vim25.VirtualEthernetCardDistributedVirtualPortBackingInfo; import com.vmware.vim25.VirtualEthernetCardNetworkBackingInfo; import com.vmware.vim25.VirtualEthernetCardOpaqueNetworkBackingInfo; +import com.vmware.vim25.VirtualIDEController; import com.vmware.vim25.VirtualMachineConfigSpec; import com.vmware.vim25.VirtualMachineFileInfo; import com.vmware.vim25.VirtualMachineFileLayoutEx; @@ -320,7 +328,15 @@ import com.vmware.vim25.VirtualMachineRuntimeInfo; import com.vmware.vim25.VirtualMachineToolsStatus; import com.vmware.vim25.VirtualMachineVideoCard; +import com.vmware.vim25.VirtualPCNet32; +import com.vmware.vim25.VirtualSCSIController; import com.vmware.vim25.VirtualUSBController; +import com.vmware.vim25.VirtualVmxnet2; +import com.vmware.vim25.VirtualVmxnet3; +import com.vmware.vim25.VmConfigInfo; +import com.vmware.vim25.VmConfigSpec; +import com.vmware.vim25.VmfsDatastoreInfo; +import com.vmware.vim25.VmwareDistributedVirtualSwitchPvlanSpec; import com.vmware.vim25.VmwareDistributedVirtualSwitchVlanIdSpec; public class VmwareResource implements StoragePoolResource, ServerResource, VmwareHostService, VirtualRouterDeployer { @@ -378,6 +394,7 @@ public class VmwareResource implements StoragePoolResource, ServerResource, Vmwa protected VirtualRoutingResource _vrResource; protected final static HashMap s_powerStatesTable = new HashMap(); + static { s_powerStatesTable.put(VirtualMachinePowerState.POWERED_ON, PowerState.PowerOn); s_powerStatesTable.put(VirtualMachinePowerState.POWERED_OFF, PowerState.PowerOff); @@ -430,118 +447,120 @@ public Answer executeRequest(Command cmd) { Class clz = cmd.getClass(); if (cmd instanceof NetworkElementCommand) { - return _vrResource.executeRequest((NetworkElementCommand)cmd); + return _vrResource.executeRequest((NetworkElementCommand) cmd); } else if (clz == ReadyCommand.class) { - answer = execute((ReadyCommand)cmd); + answer = execute((ReadyCommand) cmd); } else if (clz == GetHostStatsCommand.class) { - answer = execute((GetHostStatsCommand)cmd); + answer = execute((GetHostStatsCommand) cmd); } else if (clz == GetVmStatsCommand.class) { - answer = execute((GetVmStatsCommand)cmd); + answer = execute((GetVmStatsCommand) cmd); } else if (clz == GetVmNetworkStatsCommand.class) { answer = execute((GetVmNetworkStatsCommand) cmd); } else if (clz == GetVmDiskStatsCommand.class) { - answer = execute((GetVmDiskStatsCommand)cmd); + answer = execute((GetVmDiskStatsCommand) cmd); } else if (cmd instanceof GetVolumeStatsCommand) { - return execute((GetVolumeStatsCommand)cmd); + return execute((GetVolumeStatsCommand) cmd); } else if (clz == CheckHealthCommand.class) { - answer = execute((CheckHealthCommand)cmd); + answer = execute((CheckHealthCommand) cmd); } else if (clz == StopCommand.class) { - answer = execute((StopCommand)cmd); + answer = execute((StopCommand) cmd); } else if (clz == RebootRouterCommand.class) { - answer = execute((RebootRouterCommand)cmd); + answer = execute((RebootRouterCommand) cmd); } else if (clz == RebootCommand.class) { - answer = execute((RebootCommand)cmd); + answer = execute((RebootCommand) cmd); } else if (clz == CheckVirtualMachineCommand.class) { - answer = execute((CheckVirtualMachineCommand)cmd); + answer = execute((CheckVirtualMachineCommand) cmd); } else if (clz == PrepareForMigrationCommand.class) { - answer = execute((PrepareForMigrationCommand)cmd); + answer = execute((PrepareForMigrationCommand) cmd); } else if (clz == MigrateCommand.class) { - answer = execute((MigrateCommand)cmd); + answer = execute((MigrateCommand) cmd); } else if (clz == MigrateVmToPoolCommand.class) { - answer = execute((MigrateVmToPoolCommand)cmd); + answer = execute((MigrateVmToPoolCommand) cmd); } else if (clz == MigrateWithStorageCommand.class) { - answer = execute((MigrateWithStorageCommand)cmd); + answer = execute((MigrateWithStorageCommand) cmd); } else if (clz == MigrateVolumeCommand.class) { - answer = execute((MigrateVolumeCommand)cmd); + answer = execute((MigrateVolumeCommand) cmd); } else if (clz == DestroyCommand.class) { - answer = execute((DestroyCommand)cmd); + answer = execute((DestroyCommand) cmd); } else if (clz == CreateStoragePoolCommand.class) { - return execute((CreateStoragePoolCommand)cmd); + return execute((CreateStoragePoolCommand) cmd); } else if (clz == ModifyTargetsCommand.class) { - answer = execute((ModifyTargetsCommand)cmd); + answer = execute((ModifyTargetsCommand) cmd); } else if (clz == ModifyStoragePoolCommand.class) { - answer = execute((ModifyStoragePoolCommand)cmd); + answer = execute((ModifyStoragePoolCommand) cmd); } else if (clz == DeleteStoragePoolCommand.class) { - answer = execute((DeleteStoragePoolCommand)cmd); + answer = execute((DeleteStoragePoolCommand) cmd); } else if (clz == CopyVolumeCommand.class) { - answer = execute((CopyVolumeCommand)cmd); + answer = execute((CopyVolumeCommand) cmd); } else if (clz == AttachIsoCommand.class) { - answer = execute((AttachIsoCommand)cmd); + answer = execute((AttachIsoCommand) cmd); } else if (clz == ValidateSnapshotCommand.class) { - answer = execute((ValidateSnapshotCommand)cmd); + answer = execute((ValidateSnapshotCommand) cmd); } else if (clz == ManageSnapshotCommand.class) { - answer = execute((ManageSnapshotCommand)cmd); + answer = execute((ManageSnapshotCommand) cmd); } else if (clz == BackupSnapshotCommand.class) { - answer = execute((BackupSnapshotCommand)cmd); + answer = execute((BackupSnapshotCommand) cmd); } else if (clz == CreateVolumeFromSnapshotCommand.class) { - answer = execute((CreateVolumeFromSnapshotCommand)cmd); + answer = execute((CreateVolumeFromSnapshotCommand) cmd); } else if (clz == CreatePrivateTemplateFromVolumeCommand.class) { - answer = execute((CreatePrivateTemplateFromVolumeCommand)cmd); + answer = execute((CreatePrivateTemplateFromVolumeCommand) cmd); } else if (clz == CreatePrivateTemplateFromSnapshotCommand.class) { - answer = execute((CreatePrivateTemplateFromSnapshotCommand)cmd); + answer = execute((CreatePrivateTemplateFromSnapshotCommand) cmd); } else if (clz == UpgradeSnapshotCommand.class) { - answer = execute((UpgradeSnapshotCommand)cmd); + answer = execute((UpgradeSnapshotCommand) cmd); } else if (clz == GetStorageStatsCommand.class) { - answer = execute((GetStorageStatsCommand)cmd); + answer = execute((GetStorageStatsCommand) cmd); } else if (clz == PrimaryStorageDownloadCommand.class) { - answer = execute((PrimaryStorageDownloadCommand)cmd); + answer = execute((PrimaryStorageDownloadCommand) cmd); } else if (clz == GetVncPortCommand.class) { - answer = execute((GetVncPortCommand)cmd); + answer = execute((GetVncPortCommand) cmd); } else if (clz == SetupCommand.class) { - answer = execute((SetupCommand)cmd); + answer = execute((SetupCommand) cmd); } else if (clz == MaintainCommand.class) { - answer = execute((MaintainCommand)cmd); + answer = execute((MaintainCommand) cmd); } else if (clz == PingTestCommand.class) { - answer = execute((PingTestCommand)cmd); + answer = execute((PingTestCommand) cmd); } else if (clz == CheckOnHostCommand.class) { - answer = execute((CheckOnHostCommand)cmd); + answer = execute((CheckOnHostCommand) cmd); } else if (clz == ModifySshKeysCommand.class) { - answer = execute((ModifySshKeysCommand)cmd); + answer = execute((ModifySshKeysCommand) cmd); } else if (clz == NetworkUsageCommand.class) { - answer = execute((NetworkUsageCommand)cmd); + answer = execute((NetworkUsageCommand) cmd); } else if (clz == StartCommand.class) { - answer = execute((StartCommand)cmd); + answer = execute((StartCommand) cmd); } else if (clz == CheckSshCommand.class) { - answer = execute((CheckSshCommand)cmd); + answer = execute((CheckSshCommand) cmd); } else if (clz == CheckNetworkCommand.class) { - answer = execute((CheckNetworkCommand)cmd); + answer = execute((CheckNetworkCommand) cmd); } else if (clz == PlugNicCommand.class) { - answer = execute((PlugNicCommand)cmd); + answer = execute((PlugNicCommand) cmd); } else if (clz == ReplugNicCommand.class) { - answer = execute((ReplugNicCommand)cmd); + answer = execute((ReplugNicCommand) cmd); } else if (clz == UnPlugNicCommand.class) { - answer = execute((UnPlugNicCommand)cmd); + answer = execute((UnPlugNicCommand) cmd); } else if (cmd instanceof CreateVMSnapshotCommand) { - return execute((CreateVMSnapshotCommand)cmd); + return execute((CreateVMSnapshotCommand) cmd); } else if (cmd instanceof DeleteVMSnapshotCommand) { - return execute((DeleteVMSnapshotCommand)cmd); + return execute((DeleteVMSnapshotCommand) cmd); } else if (cmd instanceof RevertToVMSnapshotCommand) { - return execute((RevertToVMSnapshotCommand)cmd); + return execute((RevertToVMSnapshotCommand) cmd); } else if (clz == ResizeVolumeCommand.class) { - return execute((ResizeVolumeCommand)cmd); + return execute((ResizeVolumeCommand) cmd); } else if (clz == UnregisterVMCommand.class) { - return execute((UnregisterVMCommand)cmd); + return execute((UnregisterVMCommand) cmd); } else if (cmd instanceof StorageSubSystemCommand) { - checkStorageProcessorAndHandlerNfsVersionAttribute((StorageSubSystemCommand)cmd); - return storageHandler.handleStorageCommands((StorageSubSystemCommand)cmd); + checkStorageProcessorAndHandlerNfsVersionAttribute((StorageSubSystemCommand) cmd); + return storageHandler.handleStorageCommands((StorageSubSystemCommand) cmd); } else if (clz == ScaleVmCommand.class) { - return execute((ScaleVmCommand)cmd); + return execute((ScaleVmCommand) cmd); } else if (clz == PvlanSetupCommand.class) { - return execute((PvlanSetupCommand)cmd); + return execute((PvlanSetupCommand) cmd); } else if (clz == GetVmIpAddressCommand.class) { - return execute((GetVmIpAddressCommand)cmd); + return execute((GetVmIpAddressCommand) cmd); } else if (clz == UnregisterNicCommand.class) { - answer = execute((UnregisterNicCommand)cmd); + answer = execute((UnregisterNicCommand) cmd); + } else if (clz == GetUnmanagedInstancesCommand.class) { + answer = execute((GetUnmanagedInstancesCommand) cmd); } else { answer = Answer.createUnsupportedCommandAnswer(cmd); } @@ -587,6 +606,7 @@ public Answer executeRequest(Command cmd) { * If _storageNfsVersion is not null -> nothing to do, version already set.
* If _storageNfsVersion is null -> examine StorageSubSystemCommand to get NFS version and set it * to the storage processor and storage handler. + * * @param cmd command to execute */ protected void checkStorageProcessorAndHandlerNfsVersionAttribute(StorageSubSystemCommand cmd) { @@ -595,18 +615,19 @@ protected void checkStorageProcessorAndHandlerNfsVersionAttribute(StorageSubSyst if (cmd instanceof CopyCommand) { EnumMap params = new EnumMap( VmwareStorageProcessorConfigurableFields.class); - examineStorageSubSystemCommandNfsVersion((CopyCommand)cmd, params); - params = examineStorageSubSystemCommandFullCloneFlagForVmware((CopyCommand)cmd, params); + examineStorageSubSystemCommandNfsVersion((CopyCommand) cmd, params); + params = examineStorageSubSystemCommandFullCloneFlagForVmware((CopyCommand) cmd, params); reconfigureProcessorByHandler(params); } } /** * Reconfigure processor by handler + * * @param params params */ protected void reconfigureProcessorByHandler(EnumMap params) { - VmwareStorageSubsystemCommandHandler handler = (VmwareStorageSubsystemCommandHandler)storageHandler; + VmwareStorageSubsystemCommandHandler handler = (VmwareStorageSubsystemCommandHandler) storageHandler; boolean success = handler.reconfigureStorageProcessor(params); if (success) { s_logger.info("VmwareStorageProcessor and VmwareStorageSubsystemCommandHandler successfully reconfigured"); @@ -617,7 +638,8 @@ protected void reconfigureProcessorByHandler(EnumMap examineStora if (hypervisor != null && hypervisor.equals(HypervisorType.VMware)) { DataStoreTO destDataStore = cmd.getDestTO().getDataStore(); if (destDataStore instanceof PrimaryDataStoreTO) { - PrimaryDataStoreTO dest = (PrimaryDataStoreTO)destDataStore; + PrimaryDataStoreTO dest = (PrimaryDataStoreTO) destDataStore; if (dest.isFullCloneFlag() != null) { paramsCopy.put(VmwareStorageProcessorConfigurableFields.FULL_CLONE_FLAG, dest.isFullCloneFlag().booleanValue()); } @@ -639,7 +661,8 @@ protected EnumMap examineStora /** * Examine StorageSubSystem command to get storage NFS version, if provided - * @param cmd command to execute + * + * @param cmd command to execute * @param params params */ protected void examineStorageSubSystemCommandNfsVersion(CopyCommand cmd, EnumMap params) { @@ -647,7 +670,7 @@ protected void examineStorageSubSystemCommandNfsVersion(CopyCommand cmd, EnumMap boolean nfsVersionFound = false; if (srcDataStore instanceof NfsTO) { - nfsVersionFound = getStorageNfsVersionFromNfsTO((NfsTO)srcDataStore); + nfsVersionFound = getStorageNfsVersionFromNfsTO((NfsTO) srcDataStore); } if (nfsVersionFound) { @@ -657,6 +680,7 @@ protected void examineStorageSubSystemCommandNfsVersion(CopyCommand cmd, EnumMap /** * Get storage NFS version from NfsTO + * * @param nfsTO nfsTO * @return true if NFS version was found and not null, false in other case */ @@ -743,7 +767,7 @@ private Answer execute(ResizeVolumeCommand cmd) { // OfflineVmwareMigration: 3. attach the disk to the worker vmdkDataStorePath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo, path + VMDK_EXTENSION); - vmMo.attachDisk(new String[] { vmdkDataStorePath }, morDS); + vmMo.attachDisk(new String[]{vmdkDataStorePath}, morDS); } } @@ -773,7 +797,7 @@ private Answer execute(ResizeVolumeCommand cmd) { // IDE virtual disk cannot be re-sized if VM is running if (vdisk.second() != null && vdisk.second().contains("ide")) { throw new Exception("Re-sizing a virtual disk over an IDE controller is not supported in the VMware hypervisor. " + - "Please re-try when virtual disk is attached to a VM using a SCSI controller."); + "Please re-try when virtual disk is attached to a VM using a SCSI controller."); } if (cmd.isManaged()) { @@ -799,16 +823,14 @@ private Answer execute(ResizeVolumeCommand cmd) { _storageProcessor.expandDatastore(hostDatastoreSystem, dsMo); } - if (vdisk.second() != null && !vdisk.second().toLowerCase().startsWith("scsi")) - { - s_logger.error("Unsupported disk device bus "+ vdisk.second()); - throw new Exception("Unsupported disk device bus "+ vdisk.second()); + if (vdisk.second() != null && !vdisk.second().toLowerCase().startsWith("scsi")) { + s_logger.error("Unsupported disk device bus " + vdisk.second()); + throw new Exception("Unsupported disk device bus " + vdisk.second()); } VirtualDisk disk = vdisk.first(); - if ((VirtualDiskFlatVer2BackingInfo)disk.getBacking() != null && ((VirtualDiskFlatVer2BackingInfo)disk.getBacking()).getParent() != null) - { - s_logger.error("Resize is not supported because Disk device has Parent "+ ((VirtualDiskFlatVer2BackingInfo)disk.getBacking()).getParent().getUuid()); - throw new Exception("Resize is not supported because Disk device has Parent "+ ((VirtualDiskFlatVer2BackingInfo)disk.getBacking()).getParent().getUuid()); + if ((VirtualDiskFlatVer2BackingInfo) disk.getBacking() != null && ((VirtualDiskFlatVer2BackingInfo) disk.getBacking()).getParent() != null) { + s_logger.error("Resize is not supported because Disk device has Parent " + ((VirtualDiskFlatVer2BackingInfo) disk.getBacking()).getParent().getUuid()); + throw new Exception("Resize is not supported because Disk device has Parent " + ((VirtualDiskFlatVer2BackingInfo) disk.getBacking()).getParent().getUuid()); } String vmdkAbsFile = getAbsoluteVmdkFile(disk); @@ -946,15 +968,15 @@ public ExecutionResult prepareCommand(NetworkElementCommand cmd) { assert cmd.getRouterAccessIp() != null; if (cmd instanceof IpAssocVpcCommand) { - return prepareNetworkElementCommand((IpAssocVpcCommand)cmd); + return prepareNetworkElementCommand((IpAssocVpcCommand) cmd); } else if (cmd instanceof IpAssocCommand) { - return prepareNetworkElementCommand((IpAssocCommand)cmd); + return prepareNetworkElementCommand((IpAssocCommand) cmd); } else if (cmd instanceof SetSourceNatCommand) { - return prepareNetworkElementCommand((SetSourceNatCommand)cmd); + return prepareNetworkElementCommand((SetSourceNatCommand) cmd); } else if (cmd instanceof SetupGuestNetworkCommand) { - return prepareNetworkElementCommand((SetupGuestNetworkCommand)cmd); + return prepareNetworkElementCommand((SetupGuestNetworkCommand) cmd); } else if (cmd instanceof SetNetworkACLCommand) { - return prepareNetworkElementCommand((SetNetworkACLCommand)cmd); + return prepareNetworkElementCommand((SetNetworkACLCommand) cmd); } return new ExecutionResult(true, null); } @@ -1027,7 +1049,7 @@ private VirtualDevice findVirtualNicDevice(VirtualMachineMO vmMo, String mac) th VirtualDevice[] nics = vmMo.getNicDevices(); for (VirtualDevice nic : nics) { if (nic instanceof VirtualEthernetCard) { - if (((VirtualEthernetCard)nic).getMacAddress().equals(mac)) + if (((VirtualEthernetCard) nic).getMacAddress().equals(mac)) return nic; } } @@ -1125,7 +1147,7 @@ private PlugNicAnswer execute(PlugNicCommand cmd) { if (vmMo == null) { if (hyperHost instanceof HostMO) { - ClusterMO clusterMo = new ClusterMO(hyperHost.getContext(), ((HostMO)hyperHost).getParentMor()); + ClusterMO clusterMo = new ClusterMO(hyperHost.getContext(), ((HostMO) hyperHost).getParentMor()); vmMo = clusterMo.findVmOnHyperHost(vmName); } } @@ -1147,7 +1169,7 @@ private PlugNicAnswer execute(PlugNicCommand cmd) { VirtualEthernetCardType nicDeviceType = VirtualEthernetCardType.E1000; Map details = cmd.getDetails(); if (details != null) { - nicDeviceType = VirtualEthernetCardType.valueOf((String)details.get("nicAdapter")); + nicDeviceType = VirtualEthernetCardType.valueOf((String) details.get("nicAdapter")); } // find a usable device number in VMware environment @@ -1209,7 +1231,7 @@ private ReplugNicAnswer execute(ReplugNicCommand cmd) { if (vmMo == null) { if (hyperHost instanceof HostMO) { - ClusterMO clusterMo = new ClusterMO(hyperHost.getContext(), ((HostMO)hyperHost).getParentMor()); + ClusterMO clusterMo = new ClusterMO(hyperHost.getContext(), ((HostMO) hyperHost).getParentMor()); vmMo = clusterMo.findVmOnHyperHost(vmName); } } @@ -1288,7 +1310,7 @@ private UnPlugNicAnswer execute(UnPlugNicCommand cmd) { if (vmMo == null) { if (hyperHost instanceof HostMO) { - ClusterMO clusterMo = new ClusterMO(hyperHost.getContext(), ((HostMO)hyperHost).getParentMor()); + ClusterMO clusterMo = new ClusterMO(hyperHost.getContext(), ((HostMO) hyperHost).getParentMor()); vmMo = clusterMo.findVmOnHyperHost(vmName); } } @@ -1353,7 +1375,7 @@ private void plugPublicNic(VirtualMachineMO vmMo, final String vlanId, final IpA try { VirtualDevice[] nicDevices = vmMo.getNicDevices(); - VirtualEthernetCard device = (VirtualEthernetCard)nicDevices[nicIndex]; + VirtualEthernetCard device = (VirtualEthernetCard) nicDevices[nicIndex]; if (VirtualSwitchType.StandardVirtualSwitch == vSwitchType) { VirtualEthernetCardNetworkBackingInfo nicBacking = new VirtualEthernetCardNetworkBackingInfo(); @@ -1423,7 +1445,7 @@ private ExecutionResult prepareNetworkElementCommand(IpAssocCommand cmd) { // the check and will try to find it within cluster if (vmMo == null) { if (hyperHost instanceof HostMO) { - ClusterMO clusterMo = new ClusterMO(hyperHost.getContext(), ((HostMO)hyperHost).getParentMor()); + ClusterMO clusterMo = new ClusterMO(hyperHost.getContext(), ((HostMO) hyperHost).getParentMor()); vmMo = clusterMo.findVmOnHyperHost(routerName); } } @@ -1549,13 +1571,13 @@ private DiskTO[] validateDisks(DiskTO[] disks) { for (DiskTO vol : disks) { if (vol.getType() != Volume.Type.ISO) { - VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData(); + VolumeObjectTO volumeTO = (VolumeObjectTO) vol.getData(); DataStoreTO primaryStore = volumeTO.getDataStore(); if (primaryStore.getUuid() != null && !primaryStore.getUuid().isEmpty()) { validatedDisks.add(vol); } } else if (vol.getType() == Volume.Type.ISO) { - TemplateObjectTO templateTO = (TemplateObjectTO)vol.getData(); + TemplateObjectTO templateTO = (TemplateObjectTO) vol.getData(); if (templateTO.getPath() != null && !templateTO.getPath().isEmpty()) { validatedDisks.add(vol); } @@ -1612,7 +1634,7 @@ protected ScaleVmAnswer execute(ScaleVmCommand cmd) { // Check if license supports the feature VmwareHelper.isFeatureLicensed(hyperHost, FeatureKeyConstants.HOTPLUG); - VmwareHelper.setVmScaleUpConfig(vmConfigSpec, vmSpec.getCpus(), vmSpec.getMaxSpeed(), vmSpec.getMinSpeed(), (int)requestedMaxMemoryInMb, ramMb, + VmwareHelper.setVmScaleUpConfig(vmConfigSpec, vmSpec.getCpus(), vmSpec.getMaxSpeed(), vmSpec.getMinSpeed(), (int) requestedMaxMemoryInMb, ramMb, vmSpec.getLimitCpuUse()); if (!vmMo.configureVm(vmConfigSpec)) { @@ -1772,9 +1794,9 @@ protected StartAnswer execute(StartCommand cmd) { diskInfoBuilder = vmMo.getDiskInfoBuilder(); hasSnapshot = vmMo.hasSnapshot(); if (!hasSnapshot) - vmMo.tearDownDevices(new Class[] {VirtualDisk.class, VirtualEthernetCard.class}); + vmMo.tearDownDevices(new Class[]{VirtualDisk.class, VirtualEthernetCard.class}); else - vmMo.tearDownDevices(new Class[] {VirtualEthernetCard.class}); + vmMo.tearDownDevices(new Class[]{VirtualEthernetCard.class}); if (systemVm) { ensureScsiDiskControllers(vmMo, systemVmScsiControllerType.toString(), numScsiControllerForSystemVm, firstScsiControllerBusNum); } else { @@ -1798,9 +1820,9 @@ protected StartAnswer execute(StartCommand cmd) { diskInfoBuilder = vmMo.getDiskInfoBuilder(); hasSnapshot = vmMo.hasSnapshot(); if (!hasSnapshot) - vmMo.tearDownDevices(new Class[] {VirtualDisk.class, VirtualEthernetCard.class}); + vmMo.tearDownDevices(new Class[]{VirtualDisk.class, VirtualEthernetCard.class}); else - vmMo.tearDownDevices(new Class[] {VirtualEthernetCard.class}); + vmMo.tearDownDevices(new Class[]{VirtualEthernetCard.class}); if (systemVm) { // System volumes doesn't require more than 1 SCSI controller as there is no requirement for data volumes. @@ -1855,7 +1877,7 @@ protected StartAnswer execute(StartCommand cmd) { } tearDownVm(vmMo); } else if (!hyperHost.createBlankVm(vmNameOnVcenter, vmInternalCSName, vmSpec.getCpus(), vmSpec.getMaxSpeed().intValue(), getReservedCpuMHZ(vmSpec), - vmSpec.getLimitCpuUse(), (int)(vmSpec.getMaxRam() / ResourceType.bytesToMiB), getReservedMemoryMb(vmSpec), guestOsId, rootDiskDataStoreDetails.first(), false, + vmSpec.getLimitCpuUse(), (int) (vmSpec.getMaxRam() / ResourceType.bytesToMiB), getReservedMemoryMb(vmSpec), guestOsId, rootDiskDataStoreDetails.first(), false, controllerInfo, systemVm)) { throw new Exception("Failed to create VM. vmName: " + vmInternalCSName); } @@ -1881,7 +1903,7 @@ protected StartAnswer execute(StartCommand cmd) { VirtualMachineConfigSpec vmConfigSpec = new VirtualMachineConfigSpec(); - VmwareHelper.setBasicVmConfig(vmConfigSpec, vmSpec.getCpus(), vmSpec.getMaxSpeed(), getReservedCpuMHZ(vmSpec), (int)(vmSpec.getMaxRam() / (1024 * 1024)), + VmwareHelper.setBasicVmConfig(vmConfigSpec, vmSpec.getCpus(), vmSpec.getMaxSpeed(), getReservedCpuMHZ(vmSpec), (int) (vmSpec.getMaxRam() / (1024 * 1024)), getReservedMemoryMb(vmSpec), guestOsId, vmSpec.getLimitCpuUse()); // Check for multi-cores per socket settings @@ -1899,7 +1921,7 @@ protected StartAnswer execute(StartCommand cmd) { // Check for hotadd settings vmConfigSpec.setMemoryHotAddEnabled(vmMo.isMemoryHotAddSupported(guestOsId)); - String hostApiVersion = ((HostMO)hyperHost).getHostAboutInfo().getApiVersion(); + String hostApiVersion = ((HostMO) hyperHost).getHostAboutInfo().getApiVersion(); if (numCoresPerSocket > 1 && hostApiVersion.compareTo("5.0") < 0) { s_logger.warn("Dynamic scaling of CPU is not supported for Virtual Machines with multi-core vCPUs in case of ESXi hosts 4.1 and prior. Hence CpuHotAdd will not be" + " enabled for Virtual Machine: " + vmInternalCSName); @@ -2012,7 +2034,6 @@ protected StartAnswer execute(StartCommand cmd) { } - // // Setup ROOT/DATA disk devices // @@ -2051,7 +2072,7 @@ protected StartAnswer execute(StartCommand cmd) { if (!hasSnapshot) { deviceConfigSpecArray[i] = new VirtualDeviceConfigSpec(); - VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData(); + VolumeObjectTO volumeTO = (VolumeObjectTO) vol.getData(); DataStoreTO primaryStore = volumeTO.getDataStore(); Map details = vol.getDetails(); boolean managed = false; @@ -2097,7 +2118,7 @@ protected StartAnswer execute(StartCommand cmd) { // Setup USB devices // if (guestOsId.startsWith("darwin")) { //Mac OS - VirtualDevice[] devices = vmMo.getMatchedDevices(new Class[] {VirtualUSBController.class}); + VirtualDevice[] devices = vmMo.getMatchedDevices(new Class[]{VirtualUSBController.class}); if (devices.length == 0) { s_logger.debug("No USB Controller device on VM Start. Add USB Controller device for Mac OS VM " + vmInternalCSName); @@ -2140,7 +2161,7 @@ protected StartAnswer execute(StartCommand cmd) { for (int nicIndex = nics.length - extraPublicNics; nicIndex < nics.length; nicIndex++) { VirtualDevice nicDevice = peerVmMo.getNicDeviceByIndex(nics[nicIndex].getDeviceId()); if (nicDevice != null) { - String mac = ((VirtualEthernetCard)nicDevice).getMacAddress(); + String mac = ((VirtualEthernetCard) nicDevice).getMacAddress(); if (mac != null) { s_logger.info("Use same MAC as previous RvR, the MAC is " + mac + " for extra NIC with device id: " + nics[nicIndex].getDeviceId()); nics[nicIndex].setMac(mac); @@ -2413,8 +2434,8 @@ protected List copyVAppConfigProductSectionFromOVF(VmConfigInfo * and seting properties values from ovfProperties */ protected void copyVAppConfigsFromTemplate(VmConfigInfo vAppConfig, - List ovfProperties, - VirtualMachineConfigSpec vmConfig) throws Exception { + List ovfProperties, + VirtualMachineConfigSpec vmConfig) throws Exception { VmConfigSpec vmConfigSpec = new VmConfigSpec(); vmConfigSpec.getEula().addAll(vAppConfig.getEula()); vmConfigSpec.setInstallBootStopDelay(vAppConfig.getInstallBootStopDelay()); @@ -2437,10 +2458,10 @@ private String appendFileType(String path, String fileType) { private void resizeRootDiskOnVMStart(VirtualMachineMO vmMo, DiskTO rootDiskTO, VmwareHypervisorHost hyperHost, VmwareContext context) throws Exception { final Pair vdisk = getVirtualDiskInfo(vmMo, appendFileType(rootDiskTO.getPath(), VMDK_EXTENSION)); - assert(vdisk != null); + assert (vdisk != null); Long reqSize = 0L; - final VolumeObjectTO volumeTO = ((VolumeObjectTO)rootDiskTO.getData()); + final VolumeObjectTO volumeTO = ((VolumeObjectTO) rootDiskTO.getData()); if (volumeTO != null) { reqSize = volumeTO.getSize() / 1024; } @@ -2452,7 +2473,7 @@ private void resizeRootDiskOnVMStart(VirtualMachineMO vmMo, DiskTO rootDiskTO, V if (diskChain != null && diskChain.length > 1) { s_logger.warn("Disk chain length for the VM is greater than one, this is not supported"); - throw new CloudRuntimeException("Unsupported VM disk chain length: "+ diskChain.length); + throw new CloudRuntimeException("Unsupported VM disk chain length: " + diskChain.length); } boolean resizingSupported = false; @@ -2462,7 +2483,7 @@ private void resizeRootDiskOnVMStart(VirtualMachineMO vmMo, DiskTO rootDiskTO, V } if (!resizingSupported) { s_logger.warn("Resizing of root disk is only support for scsi device/bus, the provide VM's disk device bus name is " + diskInfo.getDiskDeviceBusName()); - throw new CloudRuntimeException("Unsupported VM root disk device bus: "+ diskInfo.getDiskDeviceBusName()); + throw new CloudRuntimeException("Unsupported VM root disk device bus: " + diskInfo.getDiskDeviceBusName()); } disk.setCapacityInKB(reqSize); @@ -2512,8 +2533,9 @@ protected String replaceNicsMacSequenceInBootArgs(String oldMacSequence, String * Sets video card memory to the one provided in detail svga.vramSize (if provided) on {@code vmConfigSpec}. * 64MB was always set before. * Size must be in KB. - * @param vmMo virtual machine mo - * @param vmSpec virtual machine specs + * + * @param vmMo virtual machine mo + * @param vmSpec virtual machine specs * @param vmConfigSpec virtual machine config spec * @throws Exception exception */ @@ -2531,14 +2553,15 @@ protected void configureVideoCard(VirtualMachineMO vmMo, VirtualMachineTO vmSpec /** * Search for vm video card iterating through vm device list - * @param vmMo virtual machine mo + * + * @param vmMo virtual machine mo * @param svgaVmramSize new svga vram size (in KB) - * @param vmConfigSpec virtual machine config spec + * @param vmConfigSpec virtual machine config spec */ protected void setNewVRamSizeVmVideoCard(VirtualMachineMO vmMo, long svgaVmramSize, VirtualMachineConfigSpec vmConfigSpec) throws Exception { for (VirtualDevice device : vmMo.getAllDeviceList()) { if (device instanceof VirtualMachineVideoCard) { - VirtualMachineVideoCard videoCard = (VirtualMachineVideoCard)device; + VirtualMachineVideoCard videoCard = (VirtualMachineVideoCard) device; modifyVmVideoCardVRamSize(videoCard, vmMo, svgaVmramSize, vmConfigSpec); } } @@ -2546,10 +2569,11 @@ protected void setNewVRamSizeVmVideoCard(VirtualMachineMO vmMo, long svgaVmramSi /** * Modifies vm vram size if it was set to a different size to the one provided in svga.vramSize (user_vm_details or template_vm_details) on {@code vmConfigSpec} - * @param videoCard vm's video card device - * @param vmMo virtual machine mo + * + * @param videoCard vm's video card device + * @param vmMo virtual machine mo * @param svgaVmramSize new svga vram size (in KB) - * @param vmConfigSpec virtual machine config spec + * @param vmConfigSpec virtual machine config spec */ protected void modifyVmVideoCardVRamSize(VirtualMachineVideoCard videoCard, VirtualMachineMO vmMo, long svgaVmramSize, VirtualMachineConfigSpec vmConfigSpec) { if (videoCard.getVideoRamSizeInKB().longValue() != svgaVmramSize) { @@ -2560,9 +2584,10 @@ protected void modifyVmVideoCardVRamSize(VirtualMachineVideoCard videoCard, Virt /** * Add edit spec on {@code vmConfigSpec} to modify svga vram size - * @param videoCard video card device to edit providing the svga vram size + * + * @param videoCard video card device to edit providing the svga vram size * @param svgaVmramSize new svga vram size (in KB) - * @param vmConfigSpec virtual machine spec + * @param vmConfigSpec virtual machine spec */ protected void configureSpecVideoCardNewVRamSize(VirtualMachineVideoCard videoCard, long svgaVmramSize, VirtualMachineConfigSpec vmConfigSpec) { videoCard.setVideoRamSizeInKB(svgaVmramSize); @@ -2583,15 +2608,15 @@ private void tearDownVm(VirtualMachineMO vmMo) throws Exception { boolean hasSnapshot = false; hasSnapshot = vmMo.hasSnapshot(); if (!hasSnapshot) - vmMo.tearDownDevices(new Class[] {VirtualDisk.class, VirtualEthernetCard.class}); + vmMo.tearDownDevices(new Class[]{VirtualDisk.class, VirtualEthernetCard.class}); else - vmMo.tearDownDevices(new Class[] {VirtualEthernetCard.class}); + vmMo.tearDownDevices(new Class[]{VirtualEthernetCard.class}); vmMo.ensureScsiDeviceController(); } int getReservedMemoryMb(VirtualMachineTO vmSpec) { if (vmSpec.getDetails().get(VMwareGuru.VmwareReserveMemory.key()).equalsIgnoreCase("true")) { - return (int)(vmSpec.getMinRam() / ResourceType.bytesToMiB); + return (int) (vmSpec.getMinRam() / ResourceType.bytesToMiB); } return 0; } @@ -2605,9 +2630,9 @@ int getReservedCpuMHZ(VirtualMachineTO vmSpec) { // return the finalized disk chain for startup, from top to bottom private String[] syncDiskChain(DatacenterMO dcMo, VirtualMachineMO vmMo, VirtualMachineTO vmSpec, DiskTO vol, VirtualMachineDiskInfo diskInfo, - HashMap> dataStoresDetails) throws Exception { + HashMap> dataStoresDetails) throws Exception { - VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData(); + VolumeObjectTO volumeTO = (VolumeObjectTO) vol.getData(); DataStoreTO primaryStore = volumeTO.getDataStore(); Map details = vol.getDetails(); boolean isManaged = false; @@ -2653,8 +2678,7 @@ private String[] syncDiskChain(DatacenterMO dcMo, VirtualMachineMO vmMo, Virtual } datastoreDiskPath = VmwareStorageLayoutHelper.syncVolumeToVmDefaultFolder(dcMo, vmMo.getName(), dsMo, vmdkPath); - } - else { + } else { if (vmdkPath == null) { vmdkPath = dsMo.getName(); } @@ -2669,7 +2693,7 @@ private String[] syncDiskChain(DatacenterMO dcMo, VirtualMachineMO vmMo, Virtual s_logger.warn("Volume " + volumeTO.getId() + " does not seem to exist on datastore, out of sync? path: " + datastoreDiskPath); } - return new String[] {datastoreDiskPath}; + return new String[]{datastoreDiskPath}; } // Pair @@ -2773,7 +2797,7 @@ private static void postNvpConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachi VirtualDeviceBackingInfo backing = nicVirtualDevice.getBacking(); if (backing instanceof VirtualEthernetCardDistributedVirtualPortBackingInfo) { // This NIC is connected to a Distributed Virtual Switch - VirtualEthernetCardDistributedVirtualPortBackingInfo portInfo = (VirtualEthernetCardDistributedVirtualPortBackingInfo)backing; + VirtualEthernetCardDistributedVirtualPortBackingInfo portInfo = (VirtualEthernetCardDistributedVirtualPortBackingInfo) backing; DistributedVirtualSwitchPortConnection port = portInfo.getPort(); String portKey = port.getPortKey(); String portGroupKey = port.getPortgroupKey(); @@ -2797,8 +2821,8 @@ private static void postNvpConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachi if (portKey.equals(dvPort.getKey())) { vmDvPort = dvPort; } - VMwareDVSPortSetting settings = (VMwareDVSPortSetting)dvPort.getConfig().getSetting(); - VmwareDistributedVirtualSwitchVlanIdSpec vlanId = (VmwareDistributedVirtualSwitchVlanIdSpec)settings.getVlan(); + VMwareDVSPortSetting settings = (VMwareDVSPortSetting) dvPort.getConfig().getSetting(); + VmwareDistributedVirtualSwitchVlanIdSpec vlanId = (VmwareDistributedVirtualSwitchVlanIdSpec) settings.getVlan(); s_logger.trace("Found port " + dvPort.getKey() + " with vlan " + vlanId.getVlanId()); if (vlanId.getVlanId() > 0 && vlanId.getVlanId() < 4095) { usedVlans.add(vlanId.getVlanId()); @@ -2810,9 +2834,9 @@ private static void postNvpConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachi } DVPortConfigInfo dvPortConfigInfo = vmDvPort.getConfig(); - VMwareDVSPortSetting settings = (VMwareDVSPortSetting)dvPortConfigInfo.getSetting(); + VMwareDVSPortSetting settings = (VMwareDVSPortSetting) dvPortConfigInfo.getSetting(); - VmwareDistributedVirtualSwitchVlanIdSpec vlanId = (VmwareDistributedVirtualSwitchVlanIdSpec)settings.getVlan(); + VmwareDistributedVirtualSwitchVlanIdSpec vlanId = (VmwareDistributedVirtualSwitchVlanIdSpec) settings.getVlan(); BoolPolicy blocked = settings.getBlocked(); if (blocked.isValue() == Boolean.TRUE) { s_logger.trace("Port is blocked, set a vlanid and unblock"); @@ -2864,7 +2888,7 @@ private static void postNvpConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachi private VirtualMachineDiskInfo getMatchingExistingDisk(VirtualMachineDiskInfoBuilder diskInfoBuilder, DiskTO vol, VmwareHypervisorHost hyperHost, VmwareContext context) throws Exception { if (diskInfoBuilder != null) { - VolumeObjectTO volume = (VolumeObjectTO)vol.getData(); + VolumeObjectTO volume = (VolumeObjectTO) vol.getData(); String dsName = null; String diskBackingFileBaseName = null; @@ -2993,14 +3017,14 @@ private String getDiskController(VirtualMachineMO vmMo, VirtualMachineDiskInfo m } private void postDiskConfigBeforeStart(VirtualMachineMO vmMo, VirtualMachineTO vmSpec, DiskTO[] sortedDisks, int ideControllerKey, - int scsiControllerKey, Map> iqnToData, VmwareHypervisorHost hyperHost, VmwareContext context) throws Exception { + int scsiControllerKey, Map> iqnToData, VmwareHypervisorHost hyperHost, VmwareContext context) throws Exception { VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder(); for (DiskTO vol : sortedDisks) { if (vol.getType() == Volume.Type.ISO) continue; - VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData(); + VolumeObjectTO volumeTO = (VolumeObjectTO) vol.getData(); VirtualMachineDiskInfo diskInfo = getMatchingExistingDisk(diskInfoBuilder, vol, hyperHost, context); assert (diskInfo != null); @@ -3185,14 +3209,14 @@ public String getVmdkPath(String path) { } private HashMap> inferDatastoreDetailsFromDiskInfo(VmwareHypervisorHost hyperHost, VmwareContext context, - DiskTO[] disks, Command cmd) throws Exception { + DiskTO[] disks, Command cmd) throws Exception { HashMap> mapIdToMors = new HashMap<>(); assert (hyperHost != null) && (context != null); for (DiskTO vol : disks) { if (vol.getType() != Volume.Type.ISO) { - VolumeObjectTO volumeTO = (VolumeObjectTO)vol.getData(); + VolumeObjectTO volumeTO = (VolumeObjectTO) vol.getData(); DataStoreTO primaryStore = volumeTO.getDataStore(); String poolUuid = primaryStore.getUuid(); @@ -3227,8 +3251,7 @@ private HashMap> inferDatastor if (vmdkPath != null) { datastoreVolumePath = dsMo.getDatastorePath(vmdkPath + VMDK_EXTENSION); - } - else { + } else { datastoreVolumePath = dsMo.getDatastorePath(dsMo.getName() + VMDK_EXTENSION); } @@ -3237,8 +3260,7 @@ private HashMap> inferDatastor } mapIdToMors.put(datastoreName, new Pair<>(morDatastore, new DatastoreMO(context, morDatastore))); - } - else { + } else { ManagedObjectReference morDatastore = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, poolUuid); if (morDatastore == null) { @@ -3350,8 +3372,7 @@ private Pair prepareNetworkFromNicInfo(HostMO ho networkInfo = HypervisorHostHelper.prepareNetwork(switchName, namePrefix, hostMo, getVlanInfo(nicTo, vlanToken), nicTo.getNetworkRateMbps(), nicTo.getNetworkRateMulticastMbps(), _opsTimeout, true, nicTo.getBroadcastType(), nicTo.getUuid(), nicTo.getDetails()); - } - else { + } else { String vlanId = getVlanInfo(nicTo, vlanToken); String svlanId = null; boolean pvlannetwork = (getPvlanInfo(nicTo) == null) ? false : true; @@ -3372,7 +3393,7 @@ private Pair prepareNetworkFromNicInfo(HostMO ho // return Ternary private Ternary getTargetSwitch(NicTO nicTo) throws CloudException { - TrafficType[] supportedTrafficTypes = new TrafficType[] {TrafficType.Guest, TrafficType.Public, TrafficType.Control, TrafficType.Management, TrafficType.Storage}; + TrafficType[] supportedTrafficTypes = new TrafficType[]{TrafficType.Guest, TrafficType.Public, TrafficType.Control, TrafficType.Management, TrafficType.Storage}; TrafficType trafficType = nicTo.getType(); if (!Arrays.asList(supportedTrafficTypes).contains(trafficType)) { @@ -3471,7 +3492,7 @@ private Pair getIsoDatastoreInfo(VmwareHyperviso int templateRootPos = isoUrl.indexOf("template/tmpl"); templateRootPos = (templateRootPos < 0 ? isoUrl.indexOf(ConfigDrive.CONFIGDRIVEDIR) : templateRootPos); - if (templateRootPos < 0 ) { + if (templateRootPos < 0) { throw new Exception("Invalid ISO path info"); } @@ -3653,7 +3674,7 @@ protected Answer execute(GetVmDiskStatsCommand cmd) { if (!(perfValue instanceof PerfEntityMetric)) { continue; } - final List values = ((PerfEntityMetric)perfValue).getValue(); + final List values = ((PerfEntityMetric) perfValue).getValue(); if (values == null || values.isEmpty()) { continue; } @@ -3661,7 +3682,7 @@ protected Answer execute(GetVmDiskStatsCommand cmd) { if (!(value instanceof PerfMetricIntSeries) || !value.getId().getInstance().equals(diskBusName)) { continue; } - final List perfStats = ((PerfMetricIntSeries)value).getValue(); + final List perfStats = ((PerfMetricIntSeries) value).getValue(); if (perfStats.size() > 0) { long sum = 0; for (long val : perfStats) { @@ -3711,7 +3732,7 @@ protected GetVolumeStatsAnswer execute(GetVolumeStatsCommand cmd) { DatacenterMO dcMo = new DatacenterMO(getServiceContext(), dcMor); HashMap statEntry = new HashMap(); - for (String chainInfo : cmd.getVolumeUuids()){ + for (String chainInfo : cmd.getVolumeUuids()) { if (chainInfo != null) { VirtualMachineDiskInfo infoInChain = _gson.fromJson(chainInfo, VirtualMachineDiskInfo.class); if (infoInChain != null) { @@ -3838,7 +3859,7 @@ protected Answer execute(RebootRouterCommand cmd) { s_logger.info("Executing resource RebootRouterCommand: " + _gson.toJson(cmd)); } - RebootAnswer answer = (RebootAnswer)execute((RebootCommand)cmd); + RebootAnswer answer = (RebootAnswer) execute((RebootCommand) cmd); if (answer.getResult()) { String connectResult = connect(cmd.getVmName(), cmd.getPrivateIpAddress()); @@ -4037,7 +4058,7 @@ protected Answer execute(MigrateVmToPoolCommand cmd) { return new Answer(cmd, (Exception) e); } if (s_logger.isDebugEnabled()) { - s_logger.debug("problem" , e); + s_logger.debug("problem", e); } s_logger.error(e.getLocalizedMessage()); return new Answer(cmd, false, "unknown problem: " + e.getLocalizedMessage()); @@ -4051,7 +4072,7 @@ private Answer migrateAndAnswer(VirtualMachineMO vmMo, String poolUuid, VmwareHy // OfflineVmwareMigration: getVolumesFromCommand(cmd); Map volumeDeviceKey = getVolumesFromCommand(vmMo, cmd); if (s_logger.isTraceEnabled()) { - for (Integer diskId: volumeDeviceKey.keySet()) { + for (Integer diskId : volumeDeviceKey.keySet()) { s_logger.trace(String.format("disk to migrate has disk id %d and volumeId %d", diskId, volumeDeviceKey.get(diskId))); } } @@ -4071,12 +4092,12 @@ private Answer migrateAndAnswer(VirtualMachineMO vmMo, String poolUuid, VmwareHy } catch (Exception e) { String msg = "change data store for VM " + vmMo.getVmName() + " failed"; s_logger.error(msg + ": " + e.getLocalizedMessage()); - throw new CloudRuntimeException(msg,e); + throw new CloudRuntimeException(msg, e); } } Answer createAnswerForCmd(VirtualMachineMO vmMo, String poolUuid, Command cmd, Map volumeDeviceKey) throws Exception { - List volumeToList = new ArrayList<>(); + List volumeToList = new ArrayList<>(); VirtualMachineDiskInfoBuilder diskInfoBuilder = vmMo.getDiskInfoBuilder(); VirtualDisk[] disks = vmMo.getAllDiskDevice(); Answer answer; @@ -4099,7 +4120,7 @@ Answer createAnswerForCmd(VirtualMachineMO vmMo, String poolUuid, Command cmd, M newVol.setChainInfo(_gson.toJson(diskInfo)); volumeToList.add(newVol); } - return new MigrateVmToPoolAnswer((MigrateVmToPoolCommand)cmd, volumeToList); + return new MigrateVmToPoolAnswer((MigrateVmToPoolCommand) cmd, volumeToList); } return new Answer(cmd, false, null); } @@ -4107,12 +4128,12 @@ Answer createAnswerForCmd(VirtualMachineMO vmMo, String poolUuid, Command cmd, M private Map getVolumesFromCommand(VirtualMachineMO vmMo, Command cmd) throws Exception { Map volumeDeviceKey = new HashMap(); if (cmd instanceof MigrateVmToPoolCommand) { - MigrateVmToPoolCommand mcmd = (MigrateVmToPoolCommand)cmd; + MigrateVmToPoolCommand mcmd = (MigrateVmToPoolCommand) cmd; for (VolumeTO volume : mcmd.getVolumes()) { addVolumeDiskmapping(vmMo, volumeDeviceKey, volume.getPath(), volume.getId()); } } else if (cmd instanceof MigrateVolumeCommand) { - MigrateVolumeCommand mcmd = (MigrateVolumeCommand)cmd; + MigrateVolumeCommand mcmd = (MigrateVolumeCommand) cmd; addVolumeDiskmapping(vmMo, volumeDeviceKey, mcmd.getVolumePath(), mcmd.getVolumeId()); } return volumeDeviceKey; @@ -4134,7 +4155,7 @@ private void addVolumeDiskmapping(VirtualMachineMO vmMo, Map volu private ManagedObjectReference getTargetDatastoreMOReference(String destinationPool, VmwareHypervisorHost hyperHost) { ManagedObjectReference morDs; try { - if(s_logger.isDebugEnabled()) { + if (s_logger.isDebugEnabled()) { s_logger.debug(String.format("finding datastore %s", destinationPool)); } morDs = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, destinationPool); @@ -4262,7 +4283,7 @@ protected Answer execute(MigrateWithStorageCommand cmd) { throw new CloudRuntimeException(msg); } VmwareManager mgr = tgtHyperHost.getContext().getStockObject(VmwareManager.CONTEXT_STOCK_NAME); - String srcHostApiVersion = ((HostMO)srcHyperHost).getHostAboutInfo().getApiVersion(); + String srcHostApiVersion = ((HostMO) srcHyperHost).getHostAboutInfo().getApiVersion(); // find VM through datacenter (VM is not at the target host yet) vmMo = srcHyperHost.findVmOnPeerHyperHost(vmName); @@ -4449,7 +4470,7 @@ protected Answer execute(MigrateWithStorageCommand cmd) { String msg = "MigrationCommand failed due to " + VmwareHelper.getExceptionMessage(e); s_logger.warn(msg, e); - return new MigrateWithStorageAnswer(cmd, (Exception)e); + return new MigrateWithStorageAnswer(cmd, (Exception) e); } finally { // Cleanup datastores mounted on source host for (String mountedDatastore : mountedDatastoresAtSource) { @@ -4482,15 +4503,15 @@ private Answer migrateVolume(MigrateVolumeCommand cmd) { // we need to spawn a worker VM to attach the volume to and move it vmName = getWorkerName(getServiceContext(), cmd, 0); - // OfflineVmwareMigration: refactor for re-use - // OfflineVmwareMigration: 1. find data(store) + // OfflineVmwareMigration: refactor for re-use + // OfflineVmwareMigration: 1. find data(store) // OfflineVmwareMigration: more robust would be to find the store given the volume as it might have been moved out of band or due to error // example: DatastoreMO existingVmDsMo = new DatastoreMO(dcMo.getContext(), dcMo.findDatastore(fileInDatastore.getDatastoreName())); morSourceDS = HypervisorHostHelper.findDatastoreWithBackwardsCompatibility(hyperHost, cmd.getSourcePool().getUuid()); dsMo = new DatastoreMO(hyperHost.getContext(), morSourceDS); s_logger.info("Create worker VM " + vmName); - // OfflineVmwareMigration: 2. create the worker with access to the data(store) + // OfflineVmwareMigration: 2. create the worker with access to the data(store) vmMo = HypervisorHostHelper.createWorkerVM(hyperHost, dsMo, vmName); if (vmMo == null) { // OfflineVmwareMigration: don't throw a general Exception but think of a specific one @@ -4502,21 +4523,21 @@ private Answer migrateVolume(MigrateVolumeCommand cmd) { String vmdkFileName = path + VMDK_EXTENSION; vmdkDataStorePath = VmwareStorageLayoutHelper.getLegacyDatastorePathFromVmdkFileName(dsMo, vmdkFileName); if (!dsMo.fileExists(vmdkDataStorePath)) { - if(s_logger.isDebugEnabled()) { + if (s_logger.isDebugEnabled()) { s_logger.debug(String.format("path not found (%s), trying under '%s'", vmdkFileName, path)); } vmdkDataStorePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, path, vmdkFileName); } if (!dsMo.fileExists(vmdkDataStorePath)) { - if(s_logger.isDebugEnabled()) { + if (s_logger.isDebugEnabled()) { s_logger.debug(String.format("path not found (%s), trying under '%s'", vmdkFileName, vmName)); } vmdkDataStorePath = VmwareStorageLayoutHelper.getVmwareDatastorePathFromVmdkFileName(dsMo, vmName, vmdkFileName); } - if(s_logger.isDebugEnabled()) { + if (s_logger.isDebugEnabled()) { s_logger.debug(String.format("attaching %s to %s for migration", vmdkDataStorePath, vmMo.getVmName())); } - vmMo.attachDisk(new String[] { vmdkDataStorePath }, morSourceDS); + vmMo.attachDisk(new String[]{vmdkDataStorePath}, morSourceDS); } // OfflineVmwareMigration: 4. find the (worker-) VM @@ -4532,7 +4553,7 @@ private Answer migrateVolume(MigrateVolumeCommand cmd) { VirtualDisk[] disks = vmMo.getAllDiskDevice(); String format = "disk %d is attached as %s"; for (VirtualDisk disk : disks) { - s_logger.trace(String.format(format,disk.getKey(),vmMo.getVmdkFileBaseName(disk))); + s_logger.trace(String.format(format, disk.getKey(), vmMo.getVmdkFileBaseName(disk))); } } @@ -4579,7 +4600,7 @@ private Answer migrateVolume(MigrateVolumeCommand cmd) { } } if (answer instanceof MigrateVolumeAnswer) { - String newPath = ((MigrateVolumeAnswer)answer).getVolumePath(); + String newPath = ((MigrateVolumeAnswer) answer).getVolumePath(); String vmdkFileName = newPath + VMDK_EXTENSION; try { VmwareStorageLayoutHelper.syncVolumeToRootFolder(dsMo.getOwnerDatacenter().first(), dsMo, newPath, vmName); @@ -4726,7 +4747,7 @@ private VmwareHypervisorHost getTargetHyperHost(DatacenterMO dcMo, String destIp VmwareManager mgr = dcMo.getContext().getStockObject(VmwareManager.CONTEXT_STOCK_NAME); - List ocs = dcMo.getHostPropertiesOnDatacenterHostFolder(new String[] {"name", "parent"}); + List ocs = dcMo.getHostPropertiesOnDatacenterHostFolder(new String[]{"name", "parent"}); if (ocs != null && ocs.size() > 0) { for (ObjectContent oc : ocs) { HostMO hostMo = new HostMO(dcMo.getContext(), oc.getObj()); @@ -4774,15 +4795,13 @@ protected Answer execute(ModifyTargetsCommand cmd) { hostMOs.add(hostMO); } - } - catch (Exception ex) { + } catch (Exception ex) { s_logger.error(ex.getMessage(), ex); throw new CloudRuntimeException(ex.getMessage(), ex); } - } - else { - hostMOs.add((HostMO)hyperHost); + } else { + hostMOs.add((HostMO) hyperHost); } handleTargets(cmd.getAdd(), cmd.getTargetTypeToRemove(), cmd.isRemoveAsync(), cmd.getTargets(), hostMOs); @@ -4844,8 +4863,7 @@ private void handleTargets(boolean add, ModifyTargetsCommand.TargetTypeToRemove if (targets != null && targets.size() > 0) { try { _storageProcessor.handleTargets(add, targetTypeToRemove, isRemoveAsync, targets, hosts); - } - catch (Exception ex) { + } catch (Exception ex) { s_logger.warn(ex.getMessage()); } } @@ -5262,7 +5280,7 @@ protected Answer execute(GetVncPortCommand cmd) { } } - Pair portInfo = vmMo.getVncPort(mgr.getManagementPortGroupByHost((HostMO)hyperHost)); + Pair portInfo = vmMo.getVncPort(mgr.getManagementPortGroupByHost((HostMO) hyperHost)); if (s_logger.isTraceEnabled()) { s_logger.trace("Found vnc port info. vm: " + cmd.getName() + " host: " + portInfo.first() + ", vnc port: " + portInfo.second()); @@ -5317,7 +5335,7 @@ protected Answer execute(PingTestCommand cmd) { VmwareHypervisorHost hyperHost = getHyperHost(context); try { - HostMO hostMo = (HostMO)hyperHost; + HostMO hostMo = (HostMO) hyperHost; ClusterMO clusterMo = new ClusterMO(context, hostMo.getHyperHostCluster()); VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME); @@ -5419,7 +5437,7 @@ public PrimaryStorageDownloadAnswer execute(PrimaryStorageDownloadCommand cmd) { try { VmwareContext context = getServiceContext(); VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME); - return (PrimaryStorageDownloadAnswer)mgr.getStorageManager().execute(this, cmd); + return (PrimaryStorageDownloadAnswer) mgr.getStorageManager().execute(this, cmd); } catch (Throwable e) { if (e instanceof RemoteException) { s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context"); @@ -5512,7 +5530,7 @@ protected Answer execute(UnregisterNicCommand cmd) { // Get a list of all the hosts in this cluster @SuppressWarnings("unchecked") - List hosts = (List)context.getVimClient().getDynamicProperty(clusterMO, "host"); + List hosts = (List) context.getVimClient().getDynamicProperty(clusterMO, "host"); if (hosts == null) { return new Answer(cmd, false, "No hosts in cluster, which is pretty weird"); } @@ -5557,7 +5575,7 @@ public CopyVolumeAnswer execute(CopyVolumeCommand cmd) { try { VmwareContext context = getServiceContext(); VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME); - return (CopyVolumeAnswer)mgr.getStorageManager().execute(this, cmd); + return (CopyVolumeAnswer) mgr.getStorageManager().execute(this, cmd); } catch (Throwable e) { if (e instanceof RemoteException) { s_logger.warn("Encounter remote exception to vCenter, invalidate VMware session context"); @@ -5611,13 +5629,13 @@ private void gcAndKillHungWorkerVMs() { s_logger.info("Scan hung worker VM to recycle"); - int workerKey = ((HostMO)hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_WORKER); - int workerTagKey = ((HostMO)hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_WORKER_TAG); + int workerKey = ((HostMO) hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_WORKER); + int workerTagKey = ((HostMO) hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_WORKER_TAG); String workerPropName = String.format("value[%d]", workerKey); String workerTagPropName = String.format("value[%d]", workerTagKey); // GC worker that has been running for too long - ObjectContent[] ocs = hyperHost.getVmPropertiesOnHyperHost(new String[] {"name", "config.template", workerPropName, workerTagPropName,}); + ObjectContent[] ocs = hyperHost.getVmPropertiesOnHyperHost(new String[]{"name", "config.template", workerPropName, workerTagPropName,}); if (ocs != null) { for (ObjectContent oc : ocs) { List props = oc.getPropSet(); @@ -5628,13 +5646,13 @@ private void gcAndKillHungWorkerVMs() { for (DynamicProperty prop : props) { if (prop.getName().equals("config.template")) { - template = (Boolean)prop.getVal(); + template = (Boolean) prop.getVal(); } else if (prop.getName().equals(workerPropName)) { - CustomFieldStringValue val = (CustomFieldStringValue)prop.getVal(); + CustomFieldStringValue val = (CustomFieldStringValue) prop.getVal(); if (val != null && val.getValue() != null && val.getValue().equalsIgnoreCase("true")) isWorker = true; } else if (prop.getName().equals(workerTagPropName)) { - CustomFieldStringValue val = (CustomFieldStringValue)prop.getVal(); + CustomFieldStringValue val = (CustomFieldStringValue) prop.getVal(); workerTag = val.getValue(); } } @@ -5680,14 +5698,14 @@ public StartupCommand[] initialize() { try { VmwareHypervisorHost hyperHost = getHyperHost(context); assert (hyperHost instanceof HostMO); - if (!((HostMO)hyperHost).isHyperHostConnected()) { + if (!((HostMO) hyperHost).isHyperHostConnected()) { s_logger.info("Host " + hyperHost.getHyperHostName() + " is not in connected state"); return null; } - ((HostMO)hyperHost).enableVncOnHostFirewall(); + ((HostMO) hyperHost).enableVncOnHostFirewall(); - AboutInfo aboutInfo = ((HostMO)hyperHost).getHostAboutInfo(); + AboutInfo aboutInfo = ((HostMO) hyperHost).getHostAboutInfo(); hostApiVersion = aboutInfo.getApiVersion(); } catch (Exception e) { @@ -5723,7 +5741,7 @@ private List initializeLocalStorage() { try { VmwareHypervisorHost hyperHost = getHyperHost(context); if (hyperHost instanceof HostMO) { - HostMO hostMo = (HostMO)hyperHost; + HostMO hostMo = (HostMO) hyperHost; List> dsList = hostMo.getLocalDatastoreOnHost(); for (Pair dsPair : dsList) { @@ -5804,15 +5822,15 @@ private String getIqn() { VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext()); if (hyperHost instanceof HostMO) { - HostMO host = (HostMO)hyperHost; + HostMO host = (HostMO) hyperHost; HostStorageSystemMO hostStorageSystem = host.getHostStorageSystemMO(); for (HostHostBusAdapter hba : hostStorageSystem.getStorageDeviceInfo().getHostBusAdapter()) { if (hba instanceof HostInternetScsiHba) { - HostInternetScsiHba hostInternetScsiHba = (HostInternetScsiHba)hba; + HostInternetScsiHba hostInternetScsiHba = (HostInternetScsiHba) hba; if (hostInternetScsiHba.isIsSoftwareBased()) { - return ((HostInternetScsiHba)hba).getIScsiName(); + return ((HostInternetScsiHba) hba).getIScsiName(); } } } @@ -5837,7 +5855,7 @@ private void fillHostHardwareInfo(VmwareContext serviceContext, StartupRoutingCo cmd.setDom0MinMemory(0); cmd.setSpeed(summary.getCpuSpeed()); cmd.setCpuSockets(summary.getCpuSockets()); - cmd.setCpus((int)summary.getCpuCount()); + cmd.setCpus((int) summary.getCpuCount()); cmd.setMemory(summary.getMemoryBytes()); } @@ -5849,7 +5867,7 @@ private void fillHostNetworkInfo(VmwareContext serviceContext, StartupRoutingCom assert (hyperHost instanceof HostMO); VmwareManager mgr = hyperHost.getContext().getStockObject(VmwareManager.CONTEXT_STOCK_NAME); - VmwareHypervisorHostNetworkSummary summary = hyperHost.getHyperHostNetworkSummary(mgr.getManagementPortGroupByHost((HostMO)hyperHost)); + VmwareHypervisorHostNetworkSummary summary = hyperHost.getHyperHostNetworkSummary(mgr.getManagementPortGroupByHost((HostMO) hyperHost)); if (summary == null) { throw new Exception("No ESX(i) host found"); } @@ -5994,7 +6012,7 @@ private VirtualMachineGuestOsIdentifier translateGuestOsIdentifier(String cpuArc private HashMap getHostVmStateReport() throws Exception { VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext()); - int key = ((HostMO)hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_VM_INTERNAL_NAME); + int key = ((HostMO) hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_VM_INTERNAL_NAME); if (key == 0) { s_logger.warn("Custom field " + CustomFieldConstants.CLOUD_VM_INTERNAL_NAME + " is not registered ?!"); } @@ -6002,7 +6020,7 @@ private HashMap getHostVmStateReport() throws Ex // CLOUD_VM_INTERNAL_NAME stores the internal CS generated vm name. This was earlier stored in name. Now, name can be either the hostname or // the internal CS name, but the custom field CLOUD_VM_INTERNAL_NAME always stores the internal CS name. - ObjectContent[] ocs = hyperHost.getVmPropertiesOnHyperHost(new String[] {"name", "runtime.powerState", "config.template", instanceNameCustomField}); + ObjectContent[] ocs = hyperHost.getVmPropertiesOnHyperHost(new String[]{"name", "runtime.powerState", "config.template", instanceNameCustomField}); HashMap newStates = new HashMap(); if (ocs != null && ocs.length > 0) { @@ -6020,12 +6038,12 @@ private HashMap getHostVmStateReport() throws Ex isTemplate = true; } } else if (objProp.getName().equals("runtime.powerState")) { - powerState = (VirtualMachinePowerState)objProp.getVal(); + powerState = (VirtualMachinePowerState) objProp.getVal(); } else if (objProp.getName().equals("name")) { - name = (String)objProp.getVal(); + name = (String) objProp.getVal(); } else if (objProp.getName().contains(instanceNameCustomField)) { if (objProp.getVal() != null) - VMInternalCSName = ((CustomFieldStringValue)objProp.getVal()).getValue(); + VMInternalCSName = ((CustomFieldStringValue) objProp.getVal()).getValue(); } else { assert (false); } @@ -6046,7 +6064,7 @@ private HashMap getHostVmStateReport() throws Ex private HashMap getVmStates() throws Exception { VmwareHypervisorHost hyperHost = getHyperHost(getServiceContext()); - int key = ((HostMO)hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_VM_INTERNAL_NAME); + int key = ((HostMO) hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_VM_INTERNAL_NAME); if (key == 0) { s_logger.warn("Custom field " + CustomFieldConstants.CLOUD_VM_INTERNAL_NAME + " is not registered ?!"); } @@ -6054,7 +6072,7 @@ private HashMap getVmStates() throws Exception { // CLOUD_VM_INTERNAL_NAME stores the internal CS generated vm name. This was earlier stored in name. Now, name can be either the hostname or // the internal CS name, but the custom field CLOUD_VM_INTERNAL_NAME always stores the internal CS name. - ObjectContent[] ocs = hyperHost.getVmPropertiesOnHyperHost(new String[] {"name", "runtime.powerState", "config.template", instanceNameCustomField}); + ObjectContent[] ocs = hyperHost.getVmPropertiesOnHyperHost(new String[]{"name", "runtime.powerState", "config.template", instanceNameCustomField}); HashMap newStates = new HashMap(); if (ocs != null && ocs.length > 0) { @@ -6072,12 +6090,12 @@ private HashMap getVmStates() throws Exception { isTemplate = true; } } else if (objProp.getName().equals("runtime.powerState")) { - powerState = (VirtualMachinePowerState)objProp.getVal(); + powerState = (VirtualMachinePowerState) objProp.getVal(); } else if (objProp.getName().equals("name")) { - name = (String)objProp.getVal(); + name = (String) objProp.getVal(); } else if (objProp.getName().contains(instanceNameCustomField)) { if (objProp.getVal() != null) - VMInternalCSName = ((CustomFieldStringValue)objProp.getVal()).getValue(); + VMInternalCSName = ((CustomFieldStringValue) objProp.getVal()).getValue(); } else { assert (false); } @@ -6138,7 +6156,7 @@ private HashMap getVmStats(List vmNames) throws Ex } } - int key = ((HostMO)hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_VM_INTERNAL_NAME); + int key = ((HostMO) hyperHost).getCustomFieldKey("VirtualMachine", CustomFieldConstants.CLOUD_VM_INTERNAL_NAME); if (key == 0) { s_logger.warn("Custom field " + CustomFieldConstants.CLOUD_VM_INTERNAL_NAME + " is not registered ?!"); } @@ -6151,8 +6169,8 @@ private HashMap getVmStats(List vmNames) throws Ex final String memMbStr = "config.hardware.memoryMB"; final String allocatedCpuStr = "summary.runtime.maxCpuUsage"; - ObjectContent[] ocs = hyperHost.getVmPropertiesOnHyperHost(new String[] { - "name", numCpuStr, cpuUseStr, guestMemUseStr, memLimitStr, memMbStr,allocatedCpuStr, instanceNameCustomField + ObjectContent[] ocs = hyperHost.getVmPropertiesOnHyperHost(new String[]{ + "name", numCpuStr, cpuUseStr, guestMemUseStr, memLimitStr, memMbStr, allocatedCpuStr, instanceNameCustomField }); if (ocs != null && ocs.length > 0) { @@ -6173,7 +6191,7 @@ private HashMap getVmStats(List vmNames) throws Ex vmNameOnVcenter = objProp.getVal().toString(); } else if (objProp.getName().contains(instanceNameCustomField)) { if (objProp.getVal() != null) - vmInternalCSName = ((CustomFieldStringValue)objProp.getVal()).getValue(); + vmInternalCSName = ((CustomFieldStringValue) objProp.getVal()).getValue(); } else if (objProp.getName().equals(guestMemUseStr)) { guestMemusage = objProp.getVal().toString(); } else if (objProp.getName().equals(numCpuStr)) { @@ -6184,12 +6202,12 @@ private HashMap getVmStats(List vmNames) throws Ex memlimit = objProp.getVal().toString(); } else if (objProp.getName().equals(memMbStr)) { memkb = objProp.getVal().toString(); - } else if (objProp.getName().equals(allocatedCpuStr)){ - allocatedCpu = NumberUtils.toDouble(objProp.getVal().toString()); + } else if (objProp.getName().equals(allocatedCpuStr)) { + allocatedCpu = NumberUtils.toDouble(objProp.getVal().toString()); } } - maxCpuUsage = (maxCpuUsage/allocatedCpu)*100; + maxCpuUsage = (maxCpuUsage / allocatedCpu) * 100; if (vmInternalCSName != null) { name = vmInternalCSName; } else { @@ -6276,7 +6294,7 @@ private HashMap getVmStats(List vmNames) throws Ex } } - final VmStatsEntry vmStats = new VmStatsEntry( NumberUtils.toDouble(memkb)*1024,NumberUtils.toDouble(guestMemusage)*1024,NumberUtils.toDouble(memlimit)*1024, + final VmStatsEntry vmStats = new VmStatsEntry(NumberUtils.toDouble(memkb) * 1024, NumberUtils.toDouble(guestMemusage) * 1024, NumberUtils.toDouble(memlimit) * 1024, maxCpuUsage, networkReadKBs, networkWriteKBs, NumberUtils.toInt(numberCPUs), "vm"); vmStats.setDiskReadIOs(diskReadIops); vmStats.setDiskWriteIOs(diskWriteIops); @@ -6401,7 +6419,7 @@ private static HostStatsEntry getHyperHostStats(VmwareHypervisorHost hyperHost) HostStatsEntry entry = new HostStatsEntry(); entry.setEntityType("host"); - double cpuUtilization = ((double)(hardwareSummary.getTotalCpu() - hardwareSummary.getEffectiveCpu()) / (double)hardwareSummary.getTotalCpu() * 100); + double cpuUtilization = ((double) (hardwareSummary.getTotalCpu() - hardwareSummary.getEffectiveCpu()) / (double) hardwareSummary.getTotalCpu() * 100); entry.setCpuUtilization(cpuUtilization); entry.setTotalMemoryKBs(hardwareSummary.getTotalMemory() / 1024); entry.setFreeMemoryKBs(hardwareSummary.getEffectiveMemory() * 1024); @@ -6435,14 +6453,14 @@ public boolean configure(String name, Map params) throws Configu try { _name = name; - _url = (String)params.get("url"); - _username = (String)params.get("username"); - _password = (String)params.get("password"); - _dcId = (String)params.get("zone"); - _pod = (String)params.get("pod"); - _cluster = (String)params.get("cluster"); + _url = (String) params.get("url"); + _username = (String) params.get("username"); + _password = (String) params.get("password"); + _dcId = (String) params.get("zone"); + _pod = (String) params.get("pod"); + _cluster = (String) params.get("cluster"); - _guid = (String)params.get("guid"); + _guid = (String) params.get("guid"); String[] tokens = _guid.split("@"); _vCenterAddress = tokens[1]; _morHyperHost = new ManagedObjectReference(); @@ -6450,8 +6468,8 @@ public boolean configure(String name, Map params) throws Configu _morHyperHost.setType(hostTokens[0]); _morHyperHost.setValue(hostTokens[1]); - _guestTrafficInfo = (VmwareTrafficLabel)params.get("guestTrafficInfo"); - _publicTrafficInfo = (VmwareTrafficLabel)params.get("publicTrafficInfo"); + _guestTrafficInfo = (VmwareTrafficLabel) params.get("guestTrafficInfo"); + _publicTrafficInfo = (VmwareTrafficLabel) params.get("publicTrafficInfo"); VmwareContext context = getServiceContext(); VmwareManager mgr = context.getStockObject(VmwareManager.CONTEXT_STOCK_NAME); if (mgr == null) { @@ -6482,14 +6500,14 @@ public boolean configure(String name, Map params) throws Configu } if (_privateNetworkVSwitchName == null) { - _privateNetworkVSwitchName = (String)params.get("private.network.vswitch.name"); + _privateNetworkVSwitchName = (String) params.get("private.network.vswitch.name"); } - String value = (String)params.get("vmware.recycle.hung.wokervm"); + String value = (String) params.get("vmware.recycle.hung.wokervm"); if (value != null && value.equalsIgnoreCase("true")) _recycleHungWorker = true; - value = (String)params.get("vmware.root.disk.controller"); + value = (String) params.get("vmware.root.disk.controller"); if (value != null && value.equalsIgnoreCase("scsi")) _rootDiskController = DiskControllerType.scsi; else if (value != null && value.equalsIgnoreCase("ide")) @@ -6497,7 +6515,7 @@ else if (value != null && value.equalsIgnoreCase("ide")) else _rootDiskController = DiskControllerType.osdefault; - Integer intObj = (Integer)params.get("ports.per.dvportgroup"); + Integer intObj = (Integer) params.get("ports.per.dvportgroup"); if (intObj != null) _portsPerDvPortGroup = intObj.intValue(); @@ -6505,25 +6523,25 @@ else if (value != null && value.equalsIgnoreCase("ide")) + _publicTrafficInfo.getVirtualSwitchType() + " : " + _publicTrafficInfo.getVirtualSwitchName() + ", guest traffic over " + _guestTrafficInfo.getVirtualSwitchType() + " : " + _guestTrafficInfo.getVirtualSwitchName()); - Boolean boolObj = (Boolean)params.get("vmware.create.full.clone"); + Boolean boolObj = (Boolean) params.get("vmware.create.full.clone"); if (boolObj != null && boolObj.booleanValue()) { _fullCloneFlag = true; } else { _fullCloneFlag = false; } - boolObj = (Boolean)params.get("vm.instancename.flag"); + boolObj = (Boolean) params.get("vm.instancename.flag"); if (boolObj != null && boolObj.booleanValue()) { _instanceNameFlag = true; } else { _instanceNameFlag = false; } - value = (String)params.get("scripts.timeout"); + value = (String) params.get("scripts.timeout"); int timeout = NumbersUtil.parseInt(value, 1440) * 1000; storageNfsVersion = NfsSecondaryStorageResource.retrieveNfsVersionFromParams(params); - _storageProcessor = new VmwareStorageProcessor((VmwareHostService)this, _fullCloneFlag, (VmwareStorageMount)mgr, timeout, this, _shutdownWaitMs, null, + _storageProcessor = new VmwareStorageProcessor((VmwareHostService) this, _fullCloneFlag, (VmwareStorageMount) mgr, timeout, this, _shutdownWaitMs, null, storageNfsVersion); storageHandler = new VmwareStorageSubsystemCommandHandler(_storageProcessor, storageNfsVersion); @@ -6717,11 +6735,12 @@ public Answer execute(DestroyCommand cmd) { /** * Use data center to look for vm, instead of randomly picking up a cluster
* (in multiple cluster environments vm could not be found if wrong cluster was chosen) - * @param context vmware context + * + * @param context vmware context * @param hyperHost vmware hv host - * @param vol volume + * @param vol volume * @return a virtualmachinemo if could be found on datacenter. - * @throws Exception if there is an error while finding vm + * @throws Exception if there is an error while finding vm * @throws CloudRuntimeException if datacenter cannot be found */ protected VirtualMachineMO findVmOnDatacenter(VmwareContext context, VmwareHypervisorHost hyperHost, VolumeTO vol) throws Exception { @@ -6738,7 +6757,7 @@ public String getAbsoluteVmdkFile(VirtualDisk disk) { String vmdkAbsFile = null; VirtualDeviceBackingInfo backingInfo = disk.getBacking(); if (backingInfo instanceof VirtualDiskFlatVer2BackingInfo) { - VirtualDiskFlatVer2BackingInfo diskBackingInfo = (VirtualDiskFlatVer2BackingInfo)backingInfo; + VirtualDiskFlatVer2BackingInfo diskBackingInfo = (VirtualDiskFlatVer2BackingInfo) backingInfo; vmdkAbsFile = diskBackingInfo.getFileName(); } return vmdkAbsFile; @@ -6777,4 +6796,298 @@ private static File fetchSystemVmKeyFile() { } return keyFile; } + + private List getUnmanageInstanceDisks(VirtualMachineMO vmMo) { + List instanceDisks = new ArrayList<>(); + VirtualDisk[] disks = null; + try { + disks = vmMo.getAllDiskDevice(); + } catch (Exception e) { + s_logger.info("Unable to retrieve unmanaged instance disks. " + e.getMessage()); + } + if (disks != null) { + for (VirtualDevice diskDevice : disks) { + try { + if (diskDevice instanceof VirtualDisk) { + UnmanagedInstanceTO.Disk instanceDisk = new UnmanagedInstanceTO.Disk(); + VirtualDisk disk = (VirtualDisk) diskDevice; + instanceDisk.setDiskId(disk.getDiskObjectId()); + instanceDisk.setLabel(disk.getDeviceInfo() != null ? disk.getDeviceInfo().getLabel() : ""); + instanceDisk.setFileBaseName(vmMo.getVmdkFileBaseName(disk)); + instanceDisk.setImagePath(getAbsoluteVmdkFile(disk)); + instanceDisk.setCapacity(disk.getCapacityInBytes()); + instanceDisk.setPosition(diskDevice.getUnitNumber()); + DatastoreFile file = new DatastoreFile(getAbsoluteVmdkFile(disk)); + if (!Strings.isNullOrEmpty(file.getFileBaseName()) && !Strings.isNullOrEmpty(file.getDatastoreName())) { + VirtualMachineDiskInfo diskInfo = vmMo.getDiskInfoBuilder().getDiskInfoByBackingFileBaseName(file.getFileBaseName(), file.getDatastoreName()); + instanceDisk.setChainInfo(getGson().toJson(diskInfo)); + } + for (VirtualDevice device : vmMo.getAllDeviceList()) { + if (diskDevice.getControllerKey() == device.getKey()) { + if (device instanceof VirtualIDEController) { + instanceDisk.setController(DiskControllerType.getType(device.getClass().getSimpleName()).toString()); + instanceDisk.setControllerUnit(((VirtualIDEController) device).getBusNumber()); + } else if (device instanceof VirtualSCSIController) { + instanceDisk.setController(DiskControllerType.getType(device.getClass().getSimpleName()).toString()); + instanceDisk.setControllerUnit(((VirtualSCSIController) device).getBusNumber()); + } else { + instanceDisk.setController(DiskControllerType.none.toString()); + } + break; + } + } + if (disk.getBacking() instanceof VirtualDeviceFileBackingInfo) { + VirtualDeviceFileBackingInfo diskBacking = (VirtualDeviceFileBackingInfo) disk.getBacking(); + ManagedObjectReference morDs = diskBacking.getDatastore(); + DatastoreInfo info = (DatastoreInfo)vmMo.getContext().getVimClient().getDynamicProperty(diskBacking.getDatastore(), "info"); + if (info instanceof NasDatastoreInfo) { + NasDatastoreInfo dsInfo = (NasDatastoreInfo) info; + instanceDisk.setDatastoreName(dsInfo.getName()); + if (dsInfo.getNas() != null) { + instanceDisk.setDatastoreHost(dsInfo.getNas().getRemoteHost()); + instanceDisk.setDatastorePath(dsInfo.getNas().getRemotePath()); + instanceDisk.setDatastoreType(dsInfo.getNas().getType()); + } + } else if (info instanceof VmfsDatastoreInfo) { + VmfsDatastoreInfo dsInfo = (VmfsDatastoreInfo) info; + instanceDisk.setDatastoreName(dsInfo.getVmfs().getName()); + instanceDisk.setDatastoreType(dsInfo.getVmfs().getType()); + } else { + String msg = String.format("Unmanaged instance disk: %s is on unsupported datastore %s", instanceDisk.getDiskId(), info.getClass().getSimpleName()); + s_logger.error(msg); + throw new Exception(msg); + } + } + s_logger.info(vmMo.getName() + " " + disk.getDeviceInfo().getLabel() + " " + disk.getDeviceInfo().getSummary() + " " + disk.getDiskObjectId() + " " + disk.getCapacityInKB() + " " + instanceDisk.getController()); + instanceDisks.add(instanceDisk); + } + } catch (Exception e) { + s_logger.info("Unable to retrieve unmanaged instance disk info. " + e.getMessage()); + } + } + Collections.sort(instanceDisks, new Comparator() { + @Override + public int compare(final UnmanagedInstanceTO.Disk disk1, final UnmanagedInstanceTO.Disk disk2) { + return extractInt(disk1) - extractInt(disk2); + } + + int extractInt(UnmanagedInstanceTO.Disk disk) { + String num = disk.getLabel().replaceAll("\\D", ""); + // return 0 if no digits found + return num.isEmpty() ? 0 : Integer.parseInt(num); + } + }); + } + return instanceDisks; + } + + private List getUnmanageInstanceNics(VmwareHypervisorHost hyperHost, VirtualMachineMO vmMo) { + List instanceNics = new ArrayList<>(); + + HashMap> guestNicMacIPAddressMap = new HashMap<>(); + try { + GuestInfo guestInfo = vmMo.getGuestInfo(); + if (guestInfo.getToolsStatus() == VirtualMachineToolsStatus.TOOLS_OK) { + for (GuestNicInfo nicInfo: guestInfo.getNet()) { + if (CollectionUtils.isNotEmpty(nicInfo.getIpAddress())) { + List ipAddresses = new ArrayList<>(); + for (String ipAddress : nicInfo.getIpAddress()) { + if (NetUtils.isValidIp4(ipAddress)) { + ipAddresses.add(ipAddress); + } + } + guestNicMacIPAddressMap.put(nicInfo.getMacAddress(), ipAddresses); + } + } + } else { + s_logger.info(String.format("Unable to retrieve guest nics for instance: %s from VMware tools as tools status: %s", vmMo.getName(), guestInfo.getToolsStatus().toString())); + } + } catch (Exception e) { + s_logger.info("Unable to retrieve guest nics for instance from VMware tools. " + e.getMessage()); + } + VirtualDevice[] nics = null; + try { + nics = vmMo.getNicDevices(); + } catch (Exception e) { + s_logger.info("Unable to retrieve unmanaged instance nics. " + e.getMessage()); + } + if (nics != null) { + for (VirtualDevice nic : nics) { + try { + VirtualEthernetCard ethCardDevice = (VirtualEthernetCard) nic; + s_logger.error(nic.getClass().getCanonicalName() + " " + nic.getBacking().getClass().getCanonicalName() + " " + ethCardDevice.getMacAddress()); + UnmanagedInstanceTO.Nic instanceNic = new UnmanagedInstanceTO.Nic(); + instanceNic.setNicId(ethCardDevice.getDeviceInfo().getLabel()); + if (ethCardDevice instanceof VirtualPCNet32) { + instanceNic.setAdapterType(VirtualEthernetCardType.PCNet32.toString()); + } else if (ethCardDevice instanceof VirtualVmxnet2) { + instanceNic.setAdapterType(VirtualEthernetCardType.Vmxnet2.toString()); + } else if (ethCardDevice instanceof VirtualVmxnet3) { + instanceNic.setAdapterType(VirtualEthernetCardType.Vmxnet3.toString()); + } else { + instanceNic.setAdapterType(VirtualEthernetCardType.E1000.toString()); + } + instanceNic.setMacAddress(ethCardDevice.getMacAddress()); + if (guestNicMacIPAddressMap.containsKey(instanceNic.getMacAddress())) { + instanceNic.setIpAddress(guestNicMacIPAddressMap.get(instanceNic.getMacAddress())); + } + if (ethCardDevice.getSlotInfo() != null) { + instanceNic.setPciSlot(ethCardDevice.getSlotInfo().toString()); + } + VirtualDeviceBackingInfo backing = ethCardDevice.getBacking(); + if (backing instanceof VirtualEthernetCardDistributedVirtualPortBackingInfo) { + VirtualEthernetCardDistributedVirtualPortBackingInfo backingInfo = (VirtualEthernetCardDistributedVirtualPortBackingInfo) backing; + DistributedVirtualSwitchPortConnection port = backingInfo.getPort(); + String portKey = port.getPortKey(); + String portGroupKey = port.getPortgroupKey(); + String dvSwitchUuid = port.getSwitchUuid(); + + s_logger.debug("NIC " + nic.toString() + " is connected to dvSwitch " + dvSwitchUuid + " pg " + portGroupKey + " port " + portKey); + + ManagedObjectReference dvSwitchManager = vmMo.getContext().getVimClient().getServiceContent().getDvSwitchManager(); + ManagedObjectReference dvSwitch = vmMo.getContext().getVimClient().getService().queryDvsByUuid(dvSwitchManager, dvSwitchUuid); + + // Get all ports + DistributedVirtualSwitchPortCriteria criteria = new DistributedVirtualSwitchPortCriteria(); + criteria.setInside(true); + criteria.getPortgroupKey().add(portGroupKey); + List dvPorts = vmMo.getContext().getVimClient().getService().fetchDVPorts(dvSwitch, criteria); + + for (DistributedVirtualPort dvPort : dvPorts) { + // Find the port for this NIC by portkey + if (portKey.equals(dvPort.getKey())) { + VMwareDVSPortSetting settings = (VMwareDVSPortSetting) dvPort.getConfig().getSetting(); + if (settings.getVlan() instanceof VmwareDistributedVirtualSwitchVlanIdSpec) { + VmwareDistributedVirtualSwitchVlanIdSpec vlanId = (VmwareDistributedVirtualSwitchVlanIdSpec) settings.getVlan(); + s_logger.trace("Found port " + dvPort.getKey() + " with vlan " + vlanId.getVlanId()); + if (vlanId.getVlanId() > 0 && vlanId.getVlanId() < 4095) { + instanceNic.setVlan(vlanId.getVlanId()); + } + } else if (settings.getVlan() instanceof VmwareDistributedVirtualSwitchPvlanSpec) { + VmwareDistributedVirtualSwitchPvlanSpec pvlanSpec = (VmwareDistributedVirtualSwitchPvlanSpec) settings.getVlan(); + s_logger.trace("Found port " + dvPort.getKey() + " with pvlan " + pvlanSpec.getPvlanId()); + if (pvlanSpec.getPvlanId() > 0 && pvlanSpec.getPvlanId() < 4095) { + DistributedVirtualSwitchMO dvSwitchMo = new DistributedVirtualSwitchMO(vmMo.getContext(), dvSwitch); + Pair vlanDetails = dvSwitchMo.retrieveVlanFromPvlan(pvlanSpec.getPvlanId(), dvSwitch); + if (vlanDetails != null && vlanDetails.first() != null && vlanDetails.second() != null) { + instanceNic.setVlan(vlanDetails.first()); + instanceNic.setPvlan(pvlanSpec.getPvlanId()); + instanceNic.setPvlanType(vlanDetails.second().toString()); + } + } + } + break; + } + } + } else if (backing instanceof VirtualEthernetCardNetworkBackingInfo) { + VirtualEthernetCardNetworkBackingInfo backingInfo = (VirtualEthernetCardNetworkBackingInfo) backing; + instanceNic.setNetwork(backingInfo.getDeviceName()); + if (hyperHost instanceof HostMO) { + HostMO hostMo = (HostMO) hyperHost; + HostPortGroupSpec portGroupSpec = hostMo.getHostPortGroupSpec(backingInfo.getDeviceName()); + instanceNic.setVlan(portGroupSpec.getVlanId()); + } + } + instanceNics.add(instanceNic); + } catch (Exception e) { + s_logger.info("Unable to retrieve unmanaged instance nic info. " + e.getMessage()); + } + } + Collections.sort(instanceNics, new Comparator() { + @Override + public int compare(final UnmanagedInstanceTO.Nic nic1, final UnmanagedInstanceTO.Nic nic2) { + return extractInt(nic1) - extractInt(nic2); + } + + int extractInt(UnmanagedInstanceTO.Nic nic) { + String num = nic.getNicId().replaceAll("\\D", ""); + // return 0 if no digits found + return num.isEmpty() ? 0 : Integer.parseInt(num); + } + }); + } + return instanceNics; + } + + private UnmanagedInstanceTO getUnmanagedInstance(VmwareHypervisorHost hyperHost, VirtualMachineMO vmMo) { + UnmanagedInstanceTO instance = null; + try { + instance = new UnmanagedInstanceTO(); + instance.setName(vmMo.getVmName()); + instance.setCpuCores(vmMo.getConfigSummary().getNumCpu()); + instance.setCpuCoresPerSocket(vmMo.getCoresPerSocket()); + instance.setCpuSpeed(vmMo.getConfigSummary().getCpuReservation()); + instance.setMemory(vmMo.getConfigSummary().getMemorySizeMB()); + instance.setOperatingSystemId(vmMo.getVmGuestInfo().getGuestId()); + if (Strings.isNullOrEmpty(instance.getOperatingSystemId())) { + instance.setOperatingSystemId(vmMo.getConfigSummary().getGuestId()); + } + VirtualMachineGuestOsIdentifier osIdentifier = VirtualMachineGuestOsIdentifier.OTHER_GUEST; + try { + osIdentifier = VirtualMachineGuestOsIdentifier.fromValue(instance.getOperatingSystemId()); + } catch (IllegalArgumentException iae) { + if (!Strings.isNullOrEmpty(instance.getOperatingSystemId()) && instance.getOperatingSystemId().contains("64")) { + osIdentifier = VirtualMachineGuestOsIdentifier.OTHER_GUEST_64; + } + } + instance.setOperatingSystem(vmMo.getGuestInfo().getGuestFullName()); + if (Strings.isNullOrEmpty(instance.getOperatingSystem())) { + instance.setOperatingSystem(vmMo.getConfigSummary().getGuestFullName()); + } + UnmanagedInstanceTO.PowerState powerState = UnmanagedInstanceTO.PowerState.PowerUnknown; + if (vmMo.getPowerState().toString().equalsIgnoreCase("POWERED_ON")) { + powerState = UnmanagedInstanceTO.PowerState.PowerOn; + } + if (vmMo.getPowerState().toString().equalsIgnoreCase("POWERED_OFF")) { + powerState = UnmanagedInstanceTO.PowerState.PowerOff; + } + instance.setPowerState(powerState); + instance.setDisks(getUnmanageInstanceDisks(vmMo)); + instance.setNics(getUnmanageInstanceNics(hyperHost, vmMo)); + } catch (Exception e) { + s_logger.info("Unable to retrieve unmanaged instance info. " + e.getMessage()); + } + + return instance; + } + + private Answer execute(GetUnmanagedInstancesCommand cmd) { + if (s_logger.isInfoEnabled()) { + s_logger.info("Executing resource GetUnmanagedInstancesCommand " + _gson.toJson(cmd)); + } + + VmwareContext context = getServiceContext(); + HashMap unmanagedInstances = new HashMap<>(); + try { + VmwareHypervisorHost hyperHost = getHyperHost(context); + + String vmName = cmd.getInstanceName(); + List vmMos = hyperHost.listVmsOnHyperHost(vmName); + + for (VirtualMachineMO vmMo : vmMos) { + if (vmMo == null) { + continue; + } + if (vmMo.isTemplate()) { + continue; + } + // Filter managed instances + if (cmd.hasManagedInstance(vmMo.getName())) { + continue; + } + // Filter instance if answer is requested for a particular instance name + if (!Strings.isNullOrEmpty(cmd.getInstanceName()) && + !cmd.getInstanceName().equals(vmMo.getVmName())) { + continue; + } + UnmanagedInstanceTO instance = getUnmanagedInstance(hyperHost, vmMo); + if (instance != null) { + unmanagedInstances.put(instance.getName(), instance); + } + } + } catch (Exception e) { + s_logger.info("GetUnmanagedInstancesCommand failed due to " + VmwareHelper.getExceptionMessage(e)); + } + return new GetUnmanagedInstancesAnswer(cmd, "", unmanagedInstances); + } } diff --git a/scripts/vm/hypervisor/vmware/discover_networks.py b/scripts/vm/hypervisor/vmware/discover_networks.py new file mode 100755 index 000000000000..d19e7847a41c --- /dev/null +++ b/scripts/vm/hypervisor/vmware/discover_networks.py @@ -0,0 +1,288 @@ +#!/usr/bin/env python3 +# 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. + +from __future__ import print_function +from pyVim.connect import SmartConnect, SmartConnectNoSSL, Disconnect +from pyVmomi import vim +import atexit +import sys +import argparse +import json + +isDebugLogs = False +hostClusterNameDict = {} +pgHostNameDict = {} +networksDict = {} + +def log_message(msg): + if isDebugLogs == True: + print(msg) + +def get_clusters(content, cluster=None): + if cluster is not None: + log_message("Getting clusters (name=" + cluster + ") ...") + else: + log_message("Getting clusters ...") + cluster_view = content.viewManager.CreateContainerView(content.rootFolder, + [vim.ClusterComputeResource], + True) + clusters = [] + if cluster is not None: + for c in cluster_view.view: + if c.name == cluster: + clusters.append(c) + hosts = c.host + for host in hosts: + hostClusterNameDict[host.name] = c.name + break + else: + for c in cluster_view.view: + clusters.append(c) + hosts = c.host + for host in hosts: + hostClusterNameDict[host.name] = c.name + cluster_view.Destroy() + log_message('\t{} cluster(s) found'.format(len(clusters))) + for c in clusters: + log_message('\t' + c.name) + return clusters + + +def get_vm_hosts(clusters): + log_message("Getting ESX hosts ...") + hosts = [] + for cluster in clusters: + hosts.extend(cluster.host) + log_message('\t{} host(s) found'.format(len(hosts))) + for host in hosts: + log_message('\t' + host.name) + return hosts + + +def get_vms(content): + log_message("Getting VMs ...") + vm_view = content.viewManager.CreateContainerView(content.rootFolder, + [vim.VirtualMachine], + True) + obj = [vm for vm in vm_view.view] + vm_view.Destroy() + return obj + + +def get_hosts_port_groups(hosts): + log_message("Collecting portGroups on hosts. This may take a while ...") + hostPgDict = {} + for host in hosts: + pgs = host.config.network.portgroup + hostPgDict[host] = pgs + for pg in pgs: + pgHostNameDict[pg.spec.name] = host.name + log_message("\tHost {} done.".format(host.name)) + log_message("\tPortgroup collection complete.") + return hostPgDict + + +def get_vm_info(vm, hostPgDict): + vmPowerState = vm.runtime.powerState + log_message('\tVM: ' + vm.name + '(' + vmPowerState + ')') + get_vm_nics(vm, hostPgDict) + + +def get_vm_nics(vm, hostPgDict): + try: + for dev in vm.config.hardware.device: + if isinstance(dev, vim.vm.device.VirtualEthernetCard): + dev_backing = dev.backing + portGroup = None + vlanId = None + isolatedPvlan = None + isolatedPvlanType = None + vSwitch = None + if hasattr(dev_backing, 'port'): + portGroupKey = dev.backing.port.portgroupKey + dvsUuid = dev.backing.port.switchUuid + try: + dvs = content.dvSwitchManager.QueryDvsByUuid(dvsUuid) + except: + log_message('\tError: Unable retrieve details for distributed vSwitch ' + dvsUuid) + portGroup = '' + vlanId = '' + vSwitch = '' + else: + pgObj = dvs.LookupDvPortGroup(portGroupKey) + portGroup = pgObj.config.name + try: + if isinstance(pgObj.config.defaultPortConfig.vlan, vim.dvs.VmwareDistributedVirtualSwitch.PvlanSpec): + for pvlanConfig in dvs.config.pvlanConfig: + if pvlanConfig.secondaryVlanId == pgObj.config.defaultPortConfig.vlan.pvlanId: + vlanId = str(pvlanConfig.primaryVlanId) + isolatedPvlanType = pvlanConfig.pvlanType + isolatedPvlan = str(pgObj.config.defaultPortConfig.vlan.pvlanId) + break + else: + vlanId = str(pgObj.config.defaultPortConfig.vlan.vlanId) + except AttributeError: + log_message('\tError: Unable retrieve details for portgroup ' + portGroup) + vlanId = '' + vSwitch = str(dvs.name) + else: + portGroup = dev.backing.network.name + vmHost = vm.runtime.host + # global variable hostPgDict stores portGroups per host + pgs = hostPgDict[vmHost] + for p in pgs: + if portGroup in p.key: + vlanId = str(p.spec.vlanId) + vSwitch = str(p.spec.vswitchName) + if portGroup is None: + portGroup = '' + if vlanId is None: + vlanId = '' + vmHostName = None + vmClusterName = None + try: + vmHostName = vm.runtime.host.name + except AttributeError: + vmHostName = '' + try: + vmClusterName = vm.runtime.host.parent.name + except AttributeError: + vmClusterName = '' + add_network(portGroup, vlanId, isolatedPvlanType, isolatedPvlan, vSwitch, vm.name, dev.deviceInfo.label, dev.macAddress, vmClusterName, vmHostName) + log_message('\t\t' + dev.deviceInfo.label + '->' + dev.macAddress + + ' @ ' + vSwitch + '->' + portGroup + + ' (VLAN ' + vlanId + ')') + except AttributeError: + log_message('\tError: Unable retrieve details for ' + vm.name) + +def add_network(portGroup, vlanId, isolatedPvlanType, isolatedPvlan, vSwitch, vmName, vmDeviceLabel, vmMacAddress, vmClusterName, vmHostName): + key = vSwitch + '->' + portGroup + ' (VLAN ' + vlanId + ')' + device = {"label": vmDeviceLabel, "macaddress": vmMacAddress} + vm = {"name":vmName, "device": device} + if key in networksDict: + network = networksDict[key] + network["virtualmachines"].append(vm) + networksDict[key] = network + else: + vms = [vm] + try: + host = pgHostNameDict[portGroup] + except KeyError: + host = vmHostName + try: + cluster = hostClusterNameDict[host] + except KeyError: + cluster = vmClusterName + + network = {"portgroup": portGroup, "cluster": cluster, "host": host, "switch": vSwitch, "virtualmachines": vms} + if vlanId != '': + network["vlanid"] = vlanId + if isolatedPvlan is not None: + network["isolatedpvlan"] = isolatedPvlan + if isolatedPvlanType is not None: + network["isolatedpvlantype"] = isolatedPvlanType + networksDict[key] = network + + +def get_args(): + parser = argparse.ArgumentParser( + description='Arguments for talking to vCenter') + + parser.add_argument('-s', '--host', + required=True, + action='store', + help='vSpehre service to connect to') + + parser.add_argument('-o', '--port', + type=int, + default=443, + action='store', + help='Port to connect on') + + parser.add_argument('-u', '--user', + required=True, + action='store', + help='User name to use') + + parser.add_argument('-p', '--password', + required=False, + action='store', + help='Password to use') + + parser.add_argument('-c', '--cluster', + required=False, + action='store', + help='Cluster for which discover networks') + + parser.add_argument('-S', '--disable_ssl_verification', + required=False, + action='store_true', + help='Disable ssl host certificate verification') + + parser.add_argument('-d', '--debug', + required=False, + action='store_true', + help='Debug log messages') + + args = parser.parse_args() + return args + + +def main(): + global content, isDebugLogs, hostClusterNameDict, pgHostNameDict, networksDict + args = get_args() + if args.password: + password = args.password + else: + password = getpass.getpass(prompt='Enter password for host %s and ' + 'user %s: ' % (args.host, args.user)) + if args.debug: + isDebugLogs = True + if args.disable_ssl_verification: + serviceInstance = SmartConnectNoSSL(host=args.host, + user=args.user, + pwd=password, + port=int(args.port)) + else: + serviceInstance = SmartConnect(host=args.host, + user=args.user, + pwd=password, + port=int(args.port)) + + atexit.register(Disconnect, serviceInstance) + content = serviceInstance.RetrieveContent() + if args.cluster: + clusters = get_clusters(content, args.cluster) + else: + clusters = get_clusters(content) + hosts = [] + if len(clusters) > 0: + hosts = get_vm_hosts(clusters) + if len(hosts) > 0: + hostPgDict = get_hosts_port_groups(hosts) + vms = get_vms(content) + log_message('\t{} VM(s) found'.format(len(vms))) + for vm in vms: + get_vm_info(vm, hostPgDict) + networks = list(networksDict.values()) + response = {"count": len(networks), "networks": networks} + print(json.dumps(response, indent=2, sort_keys=True)) + +# Main section +if __name__ == "__main__": + sys.exit(main()) diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index 147c527b2739..ec2dedc31f09 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -4080,7 +4080,7 @@ private VirtualMachine upgradeStoppedSystemVm(final Long systemVmId, final Long if (newServiceOffering.isDynamic()) { newServiceOffering.setDynamicFlag(true); _userVmMgr.validateCustomParameters(newServiceOffering, customparameters); - newServiceOffering = _offeringDao.getcomputeOffering(newServiceOffering, customparameters); + newServiceOffering = _offeringDao.getComputeOffering(newServiceOffering, customparameters); } _itMgr.checkIfCanUpgrade(systemVm, newServiceOffering); diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 8a84db82bcb5..f016341ab4ec 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -1006,7 +1006,7 @@ public UserVm upgradeVirtualMachine(UpgradeVMCmd cmd) throws ResourceAllocationE if (newServiceOffering.isDynamic()) { newServiceOffering.setDynamicFlag(true); validateCustomParameters(newServiceOffering, cmd.getDetails()); - newServiceOffering = _offeringDao.getcomputeOffering(newServiceOffering, customParameters); + newServiceOffering = _offeringDao.getComputeOffering(newServiceOffering, customParameters); } ServiceOfferingVO currentServiceOffering = _offeringDao.findByIdIncludingRemoved(vmInstance.getId(), vmInstance.getServiceOfferingId()); @@ -1112,7 +1112,7 @@ private UserVm upgradeStoppedVirtualMachine(Long vmId, Long svcOffId, Map networkNicMap, - final long id, final String instanceName, final String uuidName, final HypervisorType hypervisorType, final Map customParameters, final Map> extraDhcpOptionMap, final Map dataDiskTemplateToDiskOfferingMap, - Map userVmOVFPropertiesMap) throws InsufficientCapacityException { + private UserVmVO commitUserVm(final boolean isImport, final DataCenter zone, final Host host, final Host lastHost, final VirtualMachineTemplate template, final String hostName, final String displayName, final Account owner, + final Long diskOfferingId, final Long diskSize, final String userData, final Account caller, final Boolean isDisplayVm, final String keyboard, + final long accountId, final long userId, final ServiceOffering offering, final boolean isIso, final String sshPublicKey, final LinkedHashMap networkNicMap, + final long id, final String instanceName, final String uuidName, final HypervisorType hypervisorType, final Map customParameters, + final Map> extraDhcpOptionMap, final Map dataDiskTemplateToDiskOfferingMap, + final Map userVmOVFPropertiesMap, final VirtualMachine.PowerState powerState) throws InsufficientCapacityException { return Transaction.execute(new TransactionCallbackWithException() { @Override public UserVmVO doInTransaction(TransactionStatus status) throws InsufficientCapacityException { @@ -3877,7 +3877,7 @@ public UserVmVO doInTransaction(TransactionStatus status) throws InsufficientCap vm.setDetail(VmDetailConstants.KEYBOARD, keyboard); } - if (isIso) { + if (!isImport && isIso) { vm.setIsoId(template.getId()); } Long rootDiskSize = null; @@ -3929,9 +3929,21 @@ public UserVmVO doInTransaction(TransactionStatus status) throws InsufficientCap } } + if (isImport) { + vm.setDataCenterId(zone.getId()); + vm.setHostId(host.getId()); + if (lastHost != null) { + vm.setLastHostId(lastHost.getId()); + } + vm.setPowerState(powerState); + if (powerState == VirtualMachine.PowerState.PowerOn) { + vm.setState(State.Running); + } + } + _vmDao.persist(vm); for (String key : customParameters.keySet()) { - if( key.equalsIgnoreCase(VmDetailConstants.CPU_NUMBER) || + if (key.equalsIgnoreCase(VmDetailConstants.CPU_NUMBER) || key.equalsIgnoreCase(VmDetailConstants.CPU_SPEED) || key.equalsIgnoreCase(VmDetailConstants.MEMORY)) { // handle double byte strings. @@ -3965,45 +3977,62 @@ public UserVmVO doInTransaction(TransactionStatus status) throws InsufficientCap } _vmDao.saveDetails(vm); + if (!isImport) { + s_logger.debug("Allocating in the DB for vm"); + DataCenterDeployment plan = new DataCenterDeployment(zone.getId()); - s_logger.debug("Allocating in the DB for vm"); - DataCenterDeployment plan = new DataCenterDeployment(zone.getId()); - - List computeTags = new ArrayList(); - computeTags.add(offering.getHostTag()); + List computeTags = new ArrayList(); + computeTags.add(offering.getHostTag()); - List rootDiskTags = new ArrayList(); - rootDiskTags.add(offering.getTags()); + List rootDiskTags = new ArrayList(); + rootDiskTags.add(offering.getTags()); - if (isIso) { - _orchSrvc.createVirtualMachineFromScratch(vm.getUuid(), Long.toString(owner.getAccountId()), vm.getIsoId().toString(), hostName, displayName, - hypervisorType.name(), guestOSCategory.getName(), offering.getCpu(), offering.getSpeed(), offering.getRamSize(), diskSize, computeTags, rootDiskTags, - networkNicMap, plan, extraDhcpOptionMap); - } else { - _orchSrvc.createVirtualMachine(vm.getUuid(), Long.toString(owner.getAccountId()), Long.toString(template.getId()), hostName, displayName, hypervisorType.name(), - offering.getCpu(), offering.getSpeed(), offering.getRamSize(), diskSize, computeTags, rootDiskTags, networkNicMap, plan, rootDiskSize, extraDhcpOptionMap, dataDiskTemplateToDiskOfferingMap); - } + if (isIso) { + _orchSrvc.createVirtualMachineFromScratch(vm.getUuid(), Long.toString(owner.getAccountId()), vm.getIsoId().toString(), hostName, displayName, + hypervisorType.name(), guestOSCategory.getName(), offering.getCpu(), offering.getSpeed(), offering.getRamSize(), diskSize, computeTags, rootDiskTags, + networkNicMap, plan, extraDhcpOptionMap); + } else { + _orchSrvc.createVirtualMachine(vm.getUuid(), Long.toString(owner.getAccountId()), Long.toString(template.getId()), hostName, displayName, hypervisorType.name(), + offering.getCpu(), offering.getSpeed(), offering.getRamSize(), diskSize, computeTags, rootDiskTags, networkNicMap, plan, rootDiskSize, extraDhcpOptionMap, dataDiskTemplateToDiskOfferingMap); + } - if (s_logger.isDebugEnabled()) { - s_logger.debug("Successfully allocated DB entry for " + vm); + if (s_logger.isDebugEnabled()) { + s_logger.debug("Successfully allocated DB entry for " + vm); + } } CallContext.current().setEventDetails("Vm Id: " + vm.getUuid()); - if (!offering.isDynamic()) { - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_CREATE, accountId, zone.getId(), vm.getId(), vm.getHostName(), offering.getId(), template.getId(), - hypervisorType.toString(), VirtualMachine.class.getName(), vm.getUuid(), vm.isDisplayVm()); - } else { - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_CREATE, accountId, zone.getId(), vm.getId(), vm.getHostName(), offering.getId(), template.getId(), - hypervisorType.toString(), VirtualMachine.class.getName(), vm.getUuid(), customParameters, vm.isDisplayVm()); - } + if (!isImport) { + if (!offering.isDynamic()) { + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_CREATE, accountId, zone.getId(), vm.getId(), vm.getHostName(), offering.getId(), template.getId(), + hypervisorType.toString(), VirtualMachine.class.getName(), vm.getUuid(), vm.isDisplayVm()); + } else { + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VM_CREATE, accountId, zone.getId(), vm.getId(), vm.getHostName(), offering.getId(), template.getId(), + hypervisorType.toString(), VirtualMachine.class.getName(), vm.getUuid(), customParameters, vm.isDisplayVm()); + } - //Update Resource Count for the given account - resourceCountIncrement(accountId, isDisplayVm, new Long(offering.getCpu()), new Long(offering.getRamSize())); + //Update Resource Count for the given account + resourceCountIncrement(accountId, isDisplayVm, new Long(offering.getCpu()), new Long(offering.getRamSize())); + } return vm; } }); } + private UserVmVO commitUserVm(final DataCenter zone, final VirtualMachineTemplate template, final String hostName, final String displayName, final Account owner, + final Long diskOfferingId, final Long diskSize, final String userData, final Account caller, final Boolean isDisplayVm, final String keyboard, + final long accountId, final long userId, final ServiceOfferingVO offering, final boolean isIso, final String sshPublicKey, final LinkedHashMap networkNicMap, + final long id, final String instanceName, final String uuidName, final HypervisorType hypervisorType, final Map customParameters, final Map> extraDhcpOptionMap, final Map dataDiskTemplateToDiskOfferingMap, + Map userVmOVFPropertiesMap) throws InsufficientCapacityException { + return commitUserVm(false, zone, null, null, template, hostName, displayName, owner, + diskOfferingId, diskSize, userData, caller, isDisplayVm, keyboard, + accountId, userId, offering, isIso, sshPublicKey, networkNicMap, + id, instanceName, uuidName, hypervisorType, customParameters, + extraDhcpOptionMap, dataDiskTemplateToDiskOfferingMap, + userVmOVFPropertiesMap, null); + } + public void validateRootDiskResize(final HypervisorType hypervisorType, Long rootDiskSize, VMTemplateVO templateVO, UserVmVO vm, final Map customParameters) throws InvalidParameterValueException { // rootdisksize must be larger than template. @@ -6133,7 +6162,10 @@ public UserVm moveVMToUser(final AssignVMCmd cmd) throws ResourceAllocationExcep _resourceLimitMgr.checkResourceLimit(newAccount, ResourceType.primary_storage, totalVolumesSize); // VV 4: Check if new owner can use the vm template - VirtualMachineTemplate template = _templateDao.findById(vm.getTemplateId()); + VirtualMachineTemplate template = _templateDao.findByIdIncludingRemoved(vm.getTemplateId()); + if (template == null) { + throw new InvalidParameterValueException(String.format("Template for VM: %s cannot be found", vm.getUuid())); + } if (!template.isPublicTemplate()) { Account templateOwner = _accountMgr.getAccount(template.getAccountId()); _accountMgr.checkAccess(newAccount, null, true, templateOwner); @@ -7017,4 +7049,32 @@ private void deleteVolumesFromVm(List volumes) { } } } -} + + @Override + public UserVm importVM(final DataCenter zone, final Host host, final VirtualMachineTemplate template, final String instanceName, final String displayName, + final Account owner, final String userData, final Account caller, final Boolean isDisplayVm, final String keyboard, + final long accountId, final long userId, final ServiceOffering serviceOffering, final String sshPublicKey, + final String hostName, final HypervisorType hypervisorType, final Map customParameters, final VirtualMachine.PowerState powerState) throws InsufficientCapacityException { + if (zone == null) { + throw new InvalidParameterValueException("Unable to import virtual machine with invalid zone"); + } + if (host == null) { + throw new InvalidParameterValueException("Unable to import virtual machine with invalid host"); + } + + final long id = _vmDao.getNextInSequence(Long.class, "id"); + + if (hostName != null) { + // Check is hostName is RFC compliant + checkNameForRFCCompliance(hostName); + } + + final String uuidName = _uuidMgr.generateUuid(UserVm.class, null); + final Host lastHost = powerState != VirtualMachine.PowerState.PowerOn ? host : null; + return commitUserVm(true, zone, host, lastHost, template, hostName, displayName, owner, + null, null, userData, caller, isDisplayVm, keyboard, + accountId, userId, serviceOffering, template.getFormat().equals(ImageFormat.ISO), sshPublicKey, null, + id, instanceName, uuidName, hypervisorType, customParameters, + null, null, null, powerState); + } +} \ No newline at end of file diff --git a/server/src/main/java/org/apache/cloudstack/vm/VmImportManagerImpl.java b/server/src/main/java/org/apache/cloudstack/vm/VmImportManagerImpl.java new file mode 100644 index 000000000000..1856a125661e --- /dev/null +++ b/server/src/main/java/org/apache/cloudstack/vm/VmImportManagerImpl.java @@ -0,0 +1,1216 @@ +// 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.exception.CloudRuntimeException; +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(UnmanagedInstanceTO 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"); + + if (instance.getDisks() != null) { + for (UnmanagedInstanceTO.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 (UnmanagedInstanceTO.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()); + nicResponse.setIsolatedPvlanId(nic.getPvlan()); + nicResponse.setIsolatedPvlanType(nic.getPvlanType()); + response.addNic(nicResponse); + } + } + return response; + } + + private List getAdditionalNameFilters(Cluster cluster) { + List 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 templates = templatePoolDao.listAll(); + for (VMTemplateStoragePoolVO template : templates) { + additionalNameFilter.add(template.getInstallPath()); + } + + // VMWare considers some removed volumes as VM + List volumes = volumeDao.findIncludingRemovedByZone(cluster.getDataCenterId()); + for (VolumeVO volumeVO : volumes) { + if (volumeVO.getRemoved() == null) { + continue; + } + if (Strings.isNullOrEmpty(volumeVO.getChainInfo())) { + continue; + } + List 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) { + LOGGER.warn(String.format("Unable to find volume file name for volume ID: %s while adding filters unmanaged VMs", volumeVO.getUuid()), e); + } + if (!volumeFileNames.isEmpty()) { + additionalNameFilter.addAll(volumeFileNames); + } + } + } + return additionalNameFilter; + } + + private List getHostManagedVms(Host host) { + List managedVms = new ArrayList<>(); + List 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.Shutdown); + 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 UnmanagedInstanceTO instance, ServiceOfferingVO serviceOffering, final Account owner, final DataCenter zone, final Map 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 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(UnmanagedInstanceTO.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(UnmanagedInstanceTO.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(UnmanagedInstanceTO.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 getNicIpAddresses(final List nics, final Map callerNicIpAddressMap) { + Map nicIpAddresses = new HashMap<>(); + for (UnmanagedInstanceTO.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 UnmanagedInstanceTO.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 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 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(UnmanagedInstanceTO.Disk disk, DiskOffering diskOffering, ServiceOffering serviceOffering, final Account owner, final DataCenter zone, final Cluster cluster, final boolean migrateAllowed) + throws ServerApiException, PermissionDeniedException, ResourceAllocationException { + if (serviceOffering == null && diskOffering == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Disk offering for disk ID: %s not found during VM import", disk.getDiskId())); + } + if (diskOffering != null) { + 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 != null && !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 != null && !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 (diskOffering != null && !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", serviceOffering.getUuid(), storagePool.getUuid(), disk.getDiskId())); + } + } + + private void checkUnmanagedDiskAndOfferingForImport(List disks, final Map diskOfferingMap, final Account owner, final DataCenter zone, final Cluster cluster, final boolean migrateAllowed) + throws ServerApiException, PermissionDeniedException, ResourceAllocationException { + String diskController = null; + for (UnmanagedInstanceTO.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(UnmanagedInstanceTO.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; + } + + String networkBroadcastUri = network.getBroadcastUri() == null ? null : network.getBroadcastUri().toString(); + if (nic.getVlan() != null && nic.getVlan() != 0 && nic.getPvlan() == null && + (Strings.isNullOrEmpty(networkBroadcastUri) || + !networkBroadcastUri.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(), networkBroadcastUri, nic.getNicId(), nic.getVlan())); + } + if (nic.getVlan() != null && nic.getVlan() != 0 && nic.getPvlan() != null && nic.getPvlan() != 0 && + (Strings.isNullOrEmpty(network.getBroadcastUri().toString()) || + !networkBroadcastUri.equals(String.format("pvlan://%d-i%d", nic.getVlan(), nic.getPvlan())))) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("PVLAN of network(ID: %s) %s is found different from the VLAN of nic(ID: %s) pvlan://%d-i%d during VM import", network.getUuid(), networkBroadcastUri, nic.getNicId(), nic.getVlan(), nic.getPvlan())); + } + } + + private void checkUnmanagedNicAndNetworkHostnameForImport(UnmanagedInstanceTO.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 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(UnmanagedInstanceTO.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 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 getUnmanagedNicNetworkMap(List nics, final Map callerNicNetworkMap, final Map callerNicIpAddressMap, final DataCenter zone, final String hostName, final Account owner) throws ServerApiException { + Map nicNetworkMap = new HashMap<>(); + String nicAdapter = null; + for (UnmanagedInstanceTO.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 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 importDisk(UnmanagedInstanceTO.Disk disk, VirtualMachine vm, Cluster cluster, DiskOffering diskOffering, + Volume.Type type, String name, Long diskSize, Long minIops, Long maxIops, 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, + minIops, maxIops, vm, template, owner, deviceId, storagePool.getId(), path, chainInfo); + + return new Pair(profile, storagePool); + } + + private NicProfile importNic(UnmanagedInstanceTO.Nic nic, VirtualMachine vm, Network network, Network.IpAddresses ipAddresses, boolean isDefaultNic) throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { + Pair 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) { + LOGGER.error(String.format("Unable to release NICs for unsuccessful import unmanaged VM: %s", userVm.getInstanceName()), 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> 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 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> 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 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) { + String msg = ""; + if (vm.getState().equals(VirtualMachine.State.Running)) { + msg = String.format("Live migration for volume ID: %s to destination pool ID: %s failed", volumeVO.getUuid(), storagePool.getUuid()); + } else { + msg = String.format("Migration for volume ID: %s to destination pool ID: %s failed", volumeVO.getUuid(), storagePool.getUuid()); + } + LOGGER.error(msg); + throw new CloudRuntimeException(msg); + } + } 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) { + LOGGER.error(String.format("Failed to publish usage records during VM import for unmanaged vm %s", userVm.getInstanceName()), e); + cleanupFailedImportVM(userVm); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM import failed for unmanaged vm %s during publishing usage records", userVm.getInstanceName())); + } + resourceLimitService.incrementResourceCount(userVm.getAccountId(), Resource.ResourceType.user_vm, userVm.isDisplayVm()); + resourceLimitService.incrementResourceCount(userVm.getAccountId(), Resource.ResourceType.cpu, userVm.isDisplayVm(), new Long(serviceOfferingVO.getCpu())); + resourceLimitService.incrementResourceCount(userVm.getAccountId(), Resource.ResourceType.memory, userVm.isDisplayVm(), new Long(serviceOfferingVO.getRamSize())); + // Save usage event and update resource count for user vm volumes + List volumes = volumeDao.findByInstance(userVm.getId()); + for (VolumeVO volume : volumes) { + try { + UsageEventUtils.publishUsageEvent(EventTypes.EVENT_VOLUME_CREATE, volume.getAccountId(), volume.getDataCenterId(), volume.getId(), volume.getName(), volume.getDiskOfferingId(), null, volume.getSize(), + Volume.class.getName(), volume.getUuid(), volume.isDisplayVolume()); + } catch (Exception e) { + LOGGER.error(String.format("Failed to publish volume ID: %s usage records during VM import", volume.getUuid()), e); + } + resourceLimitService.incrementResourceCount(userVm.getAccountId(), Resource.ResourceType.volume, volume.isDisplayVolume()); + resourceLimitService.incrementResourceCount(userVm.getAccountId(), Resource.ResourceType.primary_storage, volume.isDisplayVolume(), volume.getSize()); + } + } + + private UserVm importVirtualMachineInternal(final UnmanagedInstanceTO unmanagedInstance, final String instanceName, final DataCenter zone, final Cluster cluster, final HostVO host, + final VirtualMachineTemplate template, final String displayName, final String hostName, final Account caller, final Account owner, final Long userId, + final ServiceOfferingVO serviceOffering, final Map dataDiskOfferingMap, + final Map nicNetworkMap, final Map callerNicIpAddressMap, + final Map details, final boolean migrateAllowed) { + UserVm userVm = null; + + ServiceOfferingVO validatedServiceOffering = null; + try { + validatedServiceOffering = getUnmanagedInstanceServiceOffering(unmanagedInstance, serviceOffering, owner, zone, details); + } catch (Exception e) { + LOGGER.error("Service offering for VM import not compatible", e); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import VM: %s. %s", unmanagedInstance.getName(), Strings.nullToEmpty(e.getMessage()))); + } + + Map allDetails = new HashMap<>(details); + if (validatedServiceOffering.isDynamic()) { + allDetails.put(VmDetailConstants.CPU_NUMBER, String.valueOf(validatedServiceOffering.getCpu())); + allDetails.put(VmDetailConstants.MEMORY, String.valueOf(validatedServiceOffering.getRamSize())); + if (serviceOffering.getSpeed() == null) { + allDetails.put(VmDetailConstants.CPU_SPEED, String.valueOf(validatedServiceOffering.getSpeed())); + } + } + + if (!migrateAllowed && !hostSupportsServiceOffering(host, validatedServiceOffering)) { + throw new InvalidParameterValueException(String.format("Service offering: %s is not compatible with host: %s of unmanaged VM: %s", serviceOffering.getUuid(), host.getUuid(), instanceName)); + } + // Check disks and supplied disk offerings + List unmanagedInstanceDisks = unmanagedInstance.getDisks(); + if (CollectionUtils.isEmpty(unmanagedInstanceDisks)) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("No attached disks found for the unmanaged VM: %s", instanceName)); + } + final UnmanagedInstanceTO.Disk rootDisk = unmanagedInstance.getDisks().get(0); + if (rootDisk == null || Strings.isNullOrEmpty(rootDisk.getController())) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM import failed. Unable to retrieve root disk details for VM: %s ", instanceName)); + } + allDetails.put(VmDetailConstants.ROOT_DISK_CONTROLLER, rootDisk.getController()); + List dataDisks = new ArrayList<>(); + try { + checkUnmanagedDiskAndOfferingForImport(rootDisk, null, validatedServiceOffering, owner, zone, cluster, migrateAllowed); + if (unmanagedInstanceDisks.size() > 1) { // Data disk(s) present + dataDisks.addAll(unmanagedInstanceDisks); + dataDisks.remove(0); + checkUnmanagedDiskAndOfferingForImport(dataDisks, dataDiskOfferingMap, owner, zone, cluster, migrateAllowed); + allDetails.put(VmDetailConstants.DATA_DISK_CONTROLLER, dataDisks.get(0).getController()); + } + resourceLimitService.checkResourceLimit(owner, Resource.ResourceType.volume, unmanagedInstanceDisks.size()); + } catch (ResourceAllocationException e) { + LOGGER.error(String.format("Volume resource allocation error for owner: %s", owner.getUuid()), e); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Volume resource allocation error for owner: %s. %s", owner.getUuid(), Strings.nullToEmpty(e.getMessage()))); + } + // Check NICs and supplied networks + Map nicIpAddressMap = getNicIpAddresses(unmanagedInstance.getNics(), callerNicIpAddressMap); + Map allNicNetworkMap = getUnmanagedNicNetworkMap(unmanagedInstance.getNics(), nicNetworkMap, nicIpAddressMap, zone, hostName, owner); + if (!CollectionUtils.isEmpty(unmanagedInstance.getNics())) { + allDetails.put(VmDetailConstants.NIC_ADAPTER, unmanagedInstance.getNics().get(0).getAdapterType()); + } + VirtualMachine.PowerState powerState = VirtualMachine.PowerState.PowerOff; + if (unmanagedInstance.getPowerState().equals(UnmanagedInstanceTO.PowerState.PowerOn)) { + powerState = VirtualMachine.PowerState.PowerOn; + } + try { + userVm = userVmManager.importVM(zone, host, template, instanceName, displayName, owner, + null, caller, true, null, owner.getAccountId(), userId, + validatedServiceOffering, null, hostName, + cluster.getHypervisorType(), allDetails, powerState); + } catch (InsufficientCapacityException ice) { + LOGGER.error(String.format("Failed to import vm name: %s", instanceName), ice); + throw new ServerApiException(ApiErrorCode.INSUFFICIENT_CAPACITY_ERROR, ice.getMessage()); + } + if (userVm == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import vm name: %s", instanceName)); + } + List> diskProfileStoragePoolList = new ArrayList<>(); + try { + if (rootDisk.getCapacity() == null || rootDisk.getCapacity() == 0) { + throw new InvalidParameterValueException(String.format("Root disk ID: %s size is invalid", rootDisk.getDiskId())); + } + Long minIops = null; + if (details.containsKey("minIops")) { + minIops = Long.parseLong(details.get("minIops")); + } + Long maxIops = null; + if (details.containsKey("maxIops")) { + maxIops = Long.parseLong(details.get("maxIops")); + } + diskProfileStoragePoolList.add(importDisk(rootDisk, userVm, cluster, serviceOffering, Volume.Type.ROOT, String.format("ROOT-%d", userVm.getId()), + (rootDisk.getCapacity() / Resource.ResourceType.bytesToGiB), minIops, maxIops, + template, owner, null)); + for (UnmanagedInstanceTO.Disk disk : dataDisks) { + if (disk.getCapacity() == null || disk.getCapacity() == 0) { + throw new InvalidParameterValueException(String.format("Disk ID: %s size is invalid", rootDisk.getDiskId())); + } + DiskOffering offering = diskOfferingDao.findById(dataDiskOfferingMap.get(disk.getDiskId())); + diskProfileStoragePoolList.add(importDisk(disk, userVm, cluster, offering, Volume.Type.DATADISK, String.format("DATA-%d-%s", userVm.getId(), disk.getDiskId()), + (disk.getCapacity() / Resource.ResourceType.bytesToGiB), offering.getMinIops(), offering.getMaxIops(), + template, owner, null)); + } + } catch (Exception e) { + LOGGER.error(String.format("Failed to import volumes while importing vm: %s", instanceName), e); + cleanupFailedImportVM(userVm); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import volumes while importing vm: %s. %s", instanceName, Strings.nullToEmpty(e.getMessage()))); + } + try { + boolean firstNic = true; + for (UnmanagedInstanceTO.Nic nic : unmanagedInstance.getNics()) { + Network network = networkDao.findById(allNicNetworkMap.get(nic.getNicId())); + Network.IpAddresses ipAddresses = nicIpAddressMap.get(nic.getNicId()); + importNic(nic, userVm, network, ipAddresses, firstNic); + firstNic = false; + } + } catch (Exception e) { + LOGGER.error(String.format("Failed to import NICs while importing vm: %s", instanceName), e); + cleanupFailedImportVM(userVm); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to import NICs while importing vm: %s. %s", instanceName, Strings.nullToEmpty(e.getMessage()))); + } + if (migrateAllowed) { + userVm = migrateImportedVM(host, template, validatedServiceOffering, userVm, owner, diskProfileStoragePoolList); + } + publishVMUsageUpdateResourceCount(userVm, validatedServiceOffering); + return userVm; + } + + @Override + public ListResponse listUnmanagedInstances(ListUnmanagedInstancesCmd cmd) { + final Account caller = CallContext.current().getCallingAccount(); + if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { + throw new PermissionDeniedException(String.format("Cannot perform this operation, Calling account is not root admin: %s", caller.getUuid())); + } + final Long clusterId = cmd.getClusterId(); + if (clusterId == null) { + throw new InvalidParameterValueException(String.format("Cluster ID cannot be null")); + } + final Cluster cluster = clusterDao.findById(clusterId); + if (cluster == null) { + throw new InvalidParameterValueException(String.format("Cluster ID: %d cannot be found", clusterId)); + } + if (cluster.getHypervisorType() != Hypervisor.HypervisorType.VMware) { + throw new InvalidParameterValueException(String.format("VM ingestion is currently not supported for hypervisor: %s", cluster.getHypervisorType().toString())); + } + List hosts = resourceManager.listHostsInClusterByStatus(clusterId, Status.Up); + List additionalNameFilters = getAdditionalNameFilters(cluster); + List responses = new ArrayList<>(); + for (HostVO host : hosts) { + if (host.isInMaintenanceStates()) { + continue; + } + List managedVms = new ArrayList<>(); + managedVms.addAll(additionalNameFilters); + managedVms.addAll(getHostManagedVms(host)); + + GetUnmanagedInstancesCommand command = new GetUnmanagedInstancesCommand(); + command.setInstanceName(cmd.getName()); + command.setManagedInstancesNames(managedVms); + Answer answer = agentManager.easySend(host.getId(), command); + if (!(answer instanceof GetUnmanagedInstancesAnswer)) { + continue; + } + GetUnmanagedInstancesAnswer unmanagedInstancesAnswer = (GetUnmanagedInstancesAnswer) answer; + HashMap unmanagedInstances = new HashMap<>(); + unmanagedInstances.putAll(unmanagedInstancesAnswer.getUnmanagedInstances()); + Set keys = unmanagedInstances.keySet(); + for (String key : keys) { + responses.add(createUnmanagedInstanceResponse(unmanagedInstances.get(key), cluster, host)); + } + } + ListResponse listResponses = new ListResponse<>(); + listResponses.setResponses(responses, responses.size()); + return listResponses; + } + + @Override + public UserVmResponse importUnmanagedInstance(ImportUnmanagedInstanceCmd cmd) { + final Account caller = CallContext.current().getCallingAccount(); + if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN) { + throw new PermissionDeniedException(String.format("Cannot perform this operation, Calling account is not root admin: %s", caller.getUuid())); + } + final Long clusterId = cmd.getClusterId(); + if (clusterId == null) { + throw new InvalidParameterValueException(String.format("Cluster ID cannot be null")); + } + final Cluster cluster = clusterDao.findById(clusterId); + if (cluster == null) { + throw new InvalidParameterValueException(String.format("Cluster ID: %d cannot be found", clusterId)); + } + if (cluster.getHypervisorType() != Hypervisor.HypervisorType.VMware) { + throw new InvalidParameterValueException(String.format("VM import is currently not supported for hypervisor: %s", cluster.getHypervisorType().toString())); + } + final DataCenter zone = dataCenterDao.findById(cluster.getDataCenterId()); + final String instanceName = cmd.getName(); + if (Strings.isNullOrEmpty(instanceName)) { + throw new InvalidParameterValueException(String.format("Instance name cannot be empty")); + } + if (cmd.getDomainId() != null && Strings.isNullOrEmpty(cmd.getAccountName())) { + throw new InvalidParameterValueException("domainid parameter must be specified with account parameter"); + } + final Account owner = accountService.getActiveAccountById(cmd.getEntityOwnerId()); + long userId = CallContext.current().getCallingUserId(); + List userVOs = userDao.listByAccount(owner.getAccountId()); + if (CollectionUtils.isNotEmpty(userVOs)) { + userId = userVOs.get(0).getId(); + } + VMTemplateVO template = null; + final Long templateId = cmd.getTemplateId(); + if (templateId == null) { + template = templateDao.findByName(VM_IMPORT_DEFAULT_TEMPLATE_NAME); + if (template == null) { + template = createDefaultDummyVmImportTemplate(); + if (template == null) { + throw new InvalidParameterValueException(String.format("Default VM import template with unique name: %s for hypervisor: %s cannot be created. Please use templateid paramter for import", VM_IMPORT_DEFAULT_TEMPLATE_NAME, cluster.getHypervisorType().toString())); + } + } + } else { + template = templateDao.findById(templateId); + } + if (template == null) { + throw new InvalidParameterValueException(String.format("Template ID: %d cannot be found", templateId)); + } + final Long serviceOfferingId = cmd.getServiceOfferingId(); + if (serviceOfferingId == null) { + throw new InvalidParameterValueException(String.format("Service offering ID cannot be null")); + } + final ServiceOfferingVO serviceOffering = serviceOfferingDao.findById(serviceOfferingId); + if (serviceOffering == null) { + throw new InvalidParameterValueException(String.format("Service offering ID: %d cannot be found", serviceOfferingId)); + } + accountService.checkAccess(owner, serviceOffering, zone); + try { + resourceLimitService.checkResourceLimit(owner, Resource.ResourceType.user_vm, 1); + } catch (ResourceAllocationException e) { + LOGGER.error(String.format("VM resource allocation error for account: %s", owner.getUuid()), e); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM resource allocation error for account: %s. %s", owner.getUuid(), Strings.nullToEmpty(e.getMessage()))); + } + String displayName = cmd.getDisplayName(); + if (Strings.isNullOrEmpty(displayName)) { + displayName = instanceName; + } + String hostName = cmd.getHostName(); + if (Strings.isNullOrEmpty(hostName)) { + if (!NetUtils.verifyDomainNameLabel(instanceName, true)) { + throw new InvalidParameterValueException(String.format("Please provide hostname for the VM. VM name contains unsupported characters for it to be used as hostname")); + } + hostName = instanceName; + } + if (!NetUtils.verifyDomainNameLabel(hostName, true)) { + throw new InvalidParameterValueException("Invalid VM hostname. VM hostname can contain ASCII letters 'a' through 'z', the digits '0' through '9', " + + "and the hyphen ('-'), must be between 1 and 63 characters long, and can't start or end with \"-\" and can't start with digit"); + } + if (cluster.getHypervisorType().equals(Hypervisor.HypervisorType.VMware) && + Boolean.parseBoolean(configurationDao.getValue(Config.SetVmInternalNameUsingDisplayName.key()))) { + // 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 = vmDao.findVMByHostNameInZone(hostName, zone.getId()); + if (vmByHostName != null && vmByHostName.getState() != VirtualMachine.State.Expunging) { + throw new InvalidParameterValueException(String.format("Failed to import VM: %s. There already exists a VM by the hostname: %s in zone: %s", instanceName, hostName, zone.getUuid())); + } + } + final Map nicNetworkMap = cmd.getNicNetworkList(); + final Map nicIpAddressMap = cmd.getNicIpAddressList(); + final Map dataDiskOfferingMap = cmd.getDataDiskToDiskOfferingList(); + final Map details = cmd.getDetails(); + List hosts = resourceManager.listHostsInClusterByStatus(clusterId, Status.Up); + UserVm userVm = null; + List additionalNameFilters = getAdditionalNameFilters(cluster); + for (HostVO host : hosts) { + if (host.isInMaintenanceStates()) { + continue; + } + List managedVms = new ArrayList<>(); + managedVms.addAll(additionalNameFilters); + managedVms.addAll(getHostManagedVms(host)); + GetUnmanagedInstancesCommand command = new GetUnmanagedInstancesCommand(instanceName); + command.setManagedInstancesNames(managedVms); + Answer answer = agentManager.easySend(host.getId(), command); + if (!(answer instanceof GetUnmanagedInstancesAnswer)) { + continue; + } + GetUnmanagedInstancesAnswer unmanagedInstancesAnswer = (GetUnmanagedInstancesAnswer) answer; + HashMap unmanagedInstances = unmanagedInstancesAnswer.getUnmanagedInstances(); + if (MapUtils.isEmpty(unmanagedInstances)) { + continue; + } + Set names = unmanagedInstances.keySet(); + for (String name : names) { + if (instanceName.equals(name)) { + UnmanagedInstanceTO unmanagedInstance = unmanagedInstances.get(name); + if (unmanagedInstance == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Unable to retrieve details for unmanaged VM: %s", name)); + } + if (template.getName().equals(VM_IMPORT_DEFAULT_TEMPLATE_NAME)) { + String osName = unmanagedInstance.getOperatingSystem(); + GuestOS guestOS = null; + if (!Strings.isNullOrEmpty(osName)) { + guestOS = guestOSDao.listByDisplayName(osName); + } + GuestOSHypervisor guestOSHypervisor = null; + if (guestOS != null) { + guestOSHypervisor = guestOSHypervisorDao.findByOsIdAndHypervisor(guestOS.getId(), host.getHypervisorType().toString(), host.getHypervisorVersion()); + } + if (guestOSHypervisor == null && !Strings.isNullOrEmpty(unmanagedInstance.getOperatingSystemId())) { + guestOSHypervisor = guestOSHypervisorDao.findByOsNameAndHypervisor(unmanagedInstance.getOperatingSystemId(), host.getHypervisorType().toString(), host.getHypervisorVersion()); + } + if (guestOSHypervisor == null) { + if (guestOS != null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Unable to find hypervisor guest OS ID: %s details for unmanaged VM: %s for hypervisor: %s version: %s. templateid parameter can be used to assign template for VM", guestOS.getUuid(), name, host.getHypervisorType().toString(), host.getHypervisorVersion())); + } + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Unable to retrieve guest OS details for unmanaged VM: %s with OS name: %s, OS ID: %s for hypervisor: %s version: %s. templateid parameter can be used to assign template for VM", name, osName, unmanagedInstance.getOperatingSystemId(), host.getHypervisorType().toString(), host.getHypervisorVersion())); + } + template.setGuestOSId(guestOSHypervisor.getGuestOsId()); + } + userVm = importVirtualMachineInternal(unmanagedInstance, instanceName, zone, cluster, host, + template, displayName, hostName, caller, owner, userId, + serviceOffering, dataDiskOfferingMap, + nicNetworkMap, nicIpAddressMap, + details, cmd.getMigrateAllowed()); + break; + } + } + if (userVm != null) { + break; + } + } + if (userVm == null) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Failed to find unmanaged vm with name: %s in cluster: %s", instanceName, cluster.getUuid())); + } + return responseGenerator.createUserVmResponse(ResponseObject.ResponseView.Full, "virtualmachine", userVm).get(0); + } + + @Override + public List> getCommands() { + final List> cmdList = new ArrayList>(); + cmdList.add(ListUnmanagedInstancesCmd.class); + cmdList.add(ImportUnmanagedInstanceCmd.class); + return cmdList; + } +} diff --git a/server/src/main/resources/META-INF/cloudstack/server-compute/spring-server-compute-context.xml b/server/src/main/resources/META-INF/cloudstack/server-compute/spring-server-compute-context.xml index 38fb61971224..ca707a03ba6d 100644 --- a/server/src/main/resources/META-INF/cloudstack/server-compute/spring-server-compute-context.xml +++ b/server/src/main/resources/META-INF/cloudstack/server-compute/spring-server-compute-context.xml @@ -35,4 +35,6 @@ + + diff --git a/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java index 09fd997f6184..5e2eaa0577fb 100644 --- a/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java +++ b/server/src/test/java/com/cloud/vpc/MockNetworkManagerImpl.java @@ -973,4 +973,9 @@ public boolean releasePodIp(ReleasePodIpCmdByAdmin ip) throws CloudRuntimeExcept public AcquirePodIpCmdResponse allocatePodIp(Account account, String zoneId, String podId) throws ResourceAllocationException, ConcurrentOperationException { return null; } + + @Override + public Pair importNic(String macAddress, int deviceId, Network network, Boolean isDefaultNic, VirtualMachine vm, IpAddresses ipAddresses) { + return null; + } } diff --git a/server/src/test/java/org/apache/cloudstack/vm/VmImportManagerImplTest.java b/server/src/test/java/org/apache/cloudstack/vm/VmImportManagerImplTest.java new file mode 100644 index 000000000000..f24c8e8a373e --- /dev/null +++ b/server/src/test/java/org/apache/cloudstack/vm/VmImportManagerImplTest.java @@ -0,0 +1,351 @@ +// 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 static org.mockito.Matchers.any; +import static org.mockito.Matchers.anyLong; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; + +import java.net.URI; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.UUID; + +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.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.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.powermock.api.mockito.PowerMockito; +import org.powermock.core.classloader.annotations.PrepareForTest; +import org.powermock.modules.junit4.PowerMockRunner; + +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.configuration.Resource; +import com.cloud.dc.ClusterVO; +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.dao.ClusterDao; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.event.UsageEventUtils; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.host.Host; +import com.cloud.host.HostVO; +import com.cloud.host.Status; +import com.cloud.hypervisor.Hypervisor; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +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.resource.ResourceManager; +import com.cloud.service.ServiceOfferingVO; +import com.cloud.service.dao.ServiceOfferingDao; +import com.cloud.storage.DiskOfferingVO; +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.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.AccountVO; +import com.cloud.user.ResourceLimitService; +import com.cloud.user.User; +import com.cloud.user.UserVO; +import com.cloud.user.dao.UserDao; +import com.cloud.uservm.UserVm; +import com.cloud.utils.Pair; +import com.cloud.vm.DiskProfile; +import com.cloud.vm.NicProfile; +import com.cloud.vm.UserVmManager; +import com.cloud.vm.UserVmVO; +import com.cloud.vm.VMInstanceVO; +import com.cloud.vm.VirtualMachine; +import com.cloud.vm.dao.VMInstanceDao; + +@RunWith(PowerMockRunner.class) +@PrepareForTest(UsageEventUtils.class) +public class VmImportManagerImplTest { + + @InjectMocks + private VmImportService vmIngestionService = new VmImportManagerImpl(); + + @Mock + private UserVmManager userVmManager; + @Mock + private ClusterDao clusterDao; + @Mock + private ResourceManager resourceManager; + @Mock + private VMTemplatePoolDao templatePoolDao; + @Mock + private AgentManager agentManager; + @Mock + private AccountService accountService; + @Mock + private UserDao userDao; + @Mock + private DataCenterDao dataCenterDao; + @Mock + private VMTemplateDao templateDao; + @Mock + private VMInstanceDao vmDao; + @Mock + private ServiceOfferingDao serviceOfferingDao; + @Mock + private DiskOfferingDao diskOfferingDao; + @Mock + private NetworkDao networkDao; + @Mock + private NetworkOrchestrationService networkOrchestrationService; + @Mock + private VolumeOrchestrationService volumeManager; + @Mock + public ResponseGenerator responseGenerator; + @Mock + private VolumeDao volumeDao; + @Mock + private ResourceLimitService resourceLimitService; + @Mock + private PrimaryDataStoreDao primaryDataStoreDao; + @Mock + private VolumeApiService volumeApiService; + @Mock + private NetworkModel networkModel; + @Mock + private ConfigurationDao configurationDao; + + @Before + public void setUp() throws Exception { + MockitoAnnotations.initMocks(this); + + AccountVO account = new AccountVO("admin", 1L, "", Account.ACCOUNT_TYPE_ADMIN, "uuid"); + UserVO user = new UserVO(1, "adminuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN); + CallContext.register(user, account); + + UnmanagedInstanceTO instance = new UnmanagedInstanceTO(); + instance.setName("TestInstance"); + instance.setCpuCores(2); + instance.setCpuCoresPerSocket(1); + instance.setCpuSpeed(1000); + instance.setMemory(1024); + instance.setOperatingSystem("CentOS 7"); + List instanceDisks = new ArrayList<>(); + UnmanagedInstanceTO.Disk instanceDisk = new UnmanagedInstanceTO.Disk(); + instanceDisk.setDiskId("1000-1"); + instanceDisk.setLabel("DiskLabel"); + instanceDisk.setController("scsi"); + instanceDisk.setImagePath("[b6ccf44a1fa13e29b3667b4954fa10ee] TestInstance/ROOT-1.vmdk"); + instanceDisk.setCapacity(5242880L); + instanceDisk.setDatastoreName("Test"); + instanceDisk.setDatastoreHost("Test"); + instanceDisk.setDatastorePath("Test"); + instanceDisk.setDatastoreType("NFS"); + instanceDisks.add(instanceDisk); + instance.setDisks(instanceDisks); + List instanceNics = new ArrayList<>(); + UnmanagedInstanceTO.Nic instanceNic = new UnmanagedInstanceTO.Nic(); + instanceNic.setNicId("NIC 1"); + instanceNic.setAdapterType("VirtualE1000E"); + instanceNic.setMacAddress("02:00:2e:0f:00:02"); + instanceNic.setVlan(1024); + instanceNics.add(instanceNic); + instance.setNics(instanceNics); + instance.setPowerState(UnmanagedInstanceTO.PowerState.PowerOn); + + ClusterVO clusterVO = new ClusterVO(1L, 1L, "Cluster"); + clusterVO.setHypervisorType(Hypervisor.HypervisorType.VMware.toString()); + when(clusterDao.findById(Mockito.anyLong())).thenReturn(clusterVO); + when(configurationDao.getValue(Mockito.anyString())).thenReturn(null); + doNothing().when(resourceLimitService).checkResourceLimit(any(Account.class), any(Resource.ResourceType.class), anyLong()); + List hosts = new ArrayList<>(); + HostVO hostVO = Mockito.mock(HostVO.class); + when(hostVO.isInMaintenanceStates()).thenReturn(false); + hosts.add(hostVO); + when(resourceManager.listHostsInClusterByStatus(Mockito.anyLong(), Mockito.any(Status.class))).thenReturn(hosts); + List templates = new ArrayList<>(); + when(templatePoolDao.listAll()).thenReturn(templates); + List volumes = new ArrayList<>(); + when(volumeDao.findIncludingRemovedByZone(Mockito.anyLong())).thenReturn(volumes); + List vms = new ArrayList<>(); + when(vmDao.listByHostId(Mockito.anyLong())).thenReturn(vms); + when(vmDao.listByLastHostIdAndStates(Mockito.anyLong())).thenReturn(vms); + GetUnmanagedInstancesCommand cmd = Mockito.mock(GetUnmanagedInstancesCommand.class); + HashMap map = new HashMap<>(); + map.put(instance.getName(), instance); + Answer answer = new GetUnmanagedInstancesAnswer(cmd, "", map); + when(agentManager.easySend(Mockito.anyLong(), Mockito.any(GetUnmanagedInstancesCommand.class))).thenReturn(answer); + DataCenterVO zone = Mockito.mock(DataCenterVO.class); + when(zone.getId()).thenReturn(1L); + when(dataCenterDao.findById(Mockito.anyLong())).thenReturn(zone); + when(accountService.getActiveAccountById(Mockito.anyLong())).thenReturn(Mockito.mock(Account.class)); + List users = new ArrayList<>(); + users.add(Mockito.mock(UserVO.class)); + when(userDao.listByAccount(Mockito.anyLong())).thenReturn(users); + VMTemplateVO template = Mockito.mock(VMTemplateVO.class); + when(template.getId()).thenReturn(1L); + when(template.getName()).thenReturn("Template"); + when(templateDao.findById(Mockito.anyLong())).thenReturn(template); + when(templateDao.findByName(Mockito.anyString())).thenReturn(template); + ServiceOfferingVO serviceOffering = Mockito.mock(ServiceOfferingVO.class); + when(serviceOffering.getId()).thenReturn(1L); + when(serviceOffering.getTags()).thenReturn(""); + when(serviceOffering.isDynamic()).thenReturn(false); + when(serviceOffering.getCpu()).thenReturn(instance.getCpuCores()); + when(serviceOffering.getRamSize()).thenReturn(instance.getMemory()); + when(serviceOffering.getSpeed()).thenReturn(instance.getCpuSpeed()); + when(serviceOfferingDao.findById(Mockito.anyLong())).thenReturn(serviceOffering); + DiskOfferingVO diskOfferingVO = Mockito.mock(DiskOfferingVO.class); + when(diskOfferingVO.isCustomized()).thenReturn(false); + when(diskOfferingVO.getDiskSize()).thenReturn(Long.MAX_VALUE); + when(diskOfferingDao.findById(Mockito.anyLong())).thenReturn(diskOfferingVO); + UserVmVO userVm = Mockito.mock(UserVmVO.class); + when(userVm.getAccountId()).thenReturn(1L); + when(userVm.getDataCenterId()).thenReturn(1L); + when(userVm.getHostName()).thenReturn(instance.getName()); + when(userVm.getTemplateId()).thenReturn(1L); + when(userVm.getHypervisorType()).thenReturn(Hypervisor.HypervisorType.VMware); + when(userVm.getUuid()).thenReturn("abcd"); + when(userVm.isDisplayVm()).thenReturn(true); + // Skip usage publishing and resource increment for test + when(userVm.getType()).thenReturn(VirtualMachine.Type.Instance); + userVm.setInstanceName(instance.getName()); + userVm.setHostName(instance.getName()); + StoragePoolVO poolVO = Mockito.mock(StoragePoolVO.class); + when(poolVO.getDataCenterId()).thenReturn(1L); + when(poolVO.getClusterId()).thenReturn(clusterVO.getId()); + List pools = new ArrayList<>(); + pools.add(poolVO); + when(primaryDataStoreDao.listPoolByHostPath(Mockito.anyString(), Mockito.anyString())).thenReturn(pools); + when(userVmManager.importVM(Mockito.any(DataCenter.class), Mockito.any(Host.class), Mockito.any(VirtualMachineTemplate.class), Mockito.anyString(), Mockito.anyString(), + Mockito.any(Account.class), Mockito.anyString(), Mockito.any(Account.class), Mockito.anyBoolean(), Mockito.anyString(), + Mockito.anyLong(), Mockito.anyLong(), Mockito.any(ServiceOffering.class), Mockito.anyString(), + Mockito.anyString(), Mockito.any(Hypervisor.HypervisorType.class), Mockito.anyMap(), Mockito.any(VirtualMachine.PowerState.class))).thenReturn(userVm); + when(volumeApiService.doesTargetStorageSupportDiskOffering(Mockito.any(StoragePool.class), Mockito.anyString())).thenReturn(true); + NetworkVO networkVO = Mockito.mock(NetworkVO.class); + when(networkVO.getGuestType()).thenReturn(Network.GuestType.L2); + when(networkVO.getBroadcastUri()).thenReturn(URI.create(String.format("vlan://%d", instanceNic.getVlan()))); + when(networkVO.getDataCenterId()).thenReturn(1L); + when(networkDao.findById(Mockito.anyLong())).thenReturn(networkVO); + List networks = new ArrayList<>(); + networks.add(networkVO); + when(networkDao.listByZone(Mockito.anyLong())).thenReturn(networks); + doNothing().when(networkModel).checkNetworkPermissions(Mockito.any(Account.class), Mockito.any(Network.class)); + doNothing().when(networkModel).checkRequestedIpAddresses(Mockito.anyLong(), Mockito.any(Network.IpAddresses.class)); + NicProfile profile = Mockito.mock(NicProfile.class); + Integer deviceId = 100; + Pair pair = new Pair(profile, deviceId); + when(networkOrchestrationService.importNic(Mockito.anyString(), Mockito.anyInt(), Mockito.any(Network.class), Mockito.anyBoolean(), Mockito.any(VirtualMachine.class), Mockito.any(Network.IpAddresses.class))).thenReturn(pair); + when(volumeManager.importVolume(Mockito.any(Volume.Type.class), Mockito.anyString(), Mockito.any(DiskOffering.class), Mockito.anyLong(), + Mockito.anyLong(), Mockito.anyLong(), Mockito.any(VirtualMachine.class), Mockito.any(VirtualMachineTemplate.class), + Mockito.any(Account.class), Mockito.anyLong(), Mockito.anyLong(), Mockito.anyString(), Mockito.anyString())).thenReturn(Mockito.mock(DiskProfile.class)); + when(volumeDao.findByInstance(Mockito.anyLong())).thenReturn(volumes); + List userVmResponses = new ArrayList<>(); + UserVmResponse userVmResponse = new UserVmResponse(); + userVmResponse.setInstanceName(instance.getName()); + userVmResponses.add(userVmResponse); + when(responseGenerator.createUserVmResponse(Mockito.any(ResponseObject.ResponseView.class), Mockito.anyString(), Mockito.any(UserVm.class))).thenReturn(userVmResponses); + } + + @After + public void tearDown() { + CallContext.unregister(); + } + + @Test + public void listUnmanagedInstancesTest() { + ListUnmanagedInstancesCmd cmd = Mockito.mock(ListUnmanagedInstancesCmd.class); + vmIngestionService.listUnmanagedInstances(cmd); + } + + @Test(expected = InvalidParameterValueException.class) + public void listUnmanagedInstancesInvalidHypervisorTest() { + ListUnmanagedInstancesCmd cmd = Mockito.mock(ListUnmanagedInstancesCmd.class); + ClusterVO cluster = new ClusterVO(1, 1, "Cluster"); + cluster.setHypervisorType(Hypervisor.HypervisorType.KVM.toString()); + when(clusterDao.findById(Mockito.anyLong())).thenReturn(cluster); + vmIngestionService.listUnmanagedInstances(cmd); + } + + @Test(expected = PermissionDeniedException.class) + public void listUnmanagedInstancesInvalidCallerTest() { + CallContext.unregister(); + AccountVO account = new AccountVO("user", 1L, "", Account.ACCOUNT_TYPE_NORMAL, "uuid"); + UserVO user = new UserVO(1, "testuser", "password", "firstname", "lastName", "email", "timezone", UUID.randomUUID().toString(), User.Source.UNKNOWN); + CallContext.register(user, account); + ListUnmanagedInstancesCmd cmd = Mockito.mock(ListUnmanagedInstancesCmd.class); + vmIngestionService.listUnmanagedInstances(cmd); + } + + @Test + public void importUnmanagedInstanceTest() { + ImportUnmanagedInstanceCmd importUnmanageInstanceCmd = Mockito.mock(ImportUnmanagedInstanceCmd.class); + when(importUnmanageInstanceCmd.getName()).thenReturn("TestInstance"); + when(importUnmanageInstanceCmd.getAccountName()).thenReturn(null); + when(importUnmanageInstanceCmd.getDomainId()).thenReturn(null); + PowerMockito.mockStatic(UsageEventUtils.class); + vmIngestionService.importUnmanagedInstance(importUnmanageInstanceCmd); + } + + @Test(expected = InvalidParameterValueException.class) + public void importUnmanagedInstanceInvalidHostnameTest() { + ImportUnmanagedInstanceCmd importUnmanageInstanceCmd = Mockito.mock(ImportUnmanagedInstanceCmd.class); + when(importUnmanageInstanceCmd.getName()).thenReturn("TestInstance"); + when(importUnmanageInstanceCmd.getName()).thenReturn("some name"); + when(importUnmanageInstanceCmd.getMigrateAllowed()).thenReturn(false); + vmIngestionService.importUnmanagedInstance(importUnmanageInstanceCmd); + } + + @Test(expected = ServerApiException.class) + public void importUnmanagedInstanceMissingInstanceTest() { + ImportUnmanagedInstanceCmd importUnmanageInstanceCmd = Mockito.mock(ImportUnmanagedInstanceCmd.class); + when(importUnmanageInstanceCmd.getName()).thenReturn("SomeInstance"); + when(importUnmanageInstanceCmd.getAccountName()).thenReturn(null); + when(importUnmanageInstanceCmd.getDomainId()).thenReturn(null); + vmIngestionService.importUnmanagedInstance(importUnmanageInstanceCmd); + } +} \ No newline at end of file diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index 1c5cf27128a5..2603552d4462 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -189,6 +189,7 @@ 'Sioc' : 'Sioc', 'Diagnostics': 'Diagnostics', 'Management': 'Management', + 'UnmanagedInstance': 'Virtual Machine' } diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java index ce9e9816280f..4b3786646220 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/ClusterMO.java @@ -216,6 +216,19 @@ public ManagedObjectReference getHyperHostCluster() throws Exception { return _mor; } + @Override + public synchronized List listVmsOnHyperHost(String vmName) throws Exception { + List vms = new ArrayList<>(); + List hosts = _context.getVimClient().getDynamicProperty(_mor, "host"); + if (hosts != null && hosts.size() > 0) { + for (ManagedObjectReference morHost : hosts) { + HostMO hostMo = new HostMO(_context, morHost); + vms.addAll(hostMo.listVmsOnHyperHost(vmName)); + } + } + return vms; + } + @Override public VirtualMachineMO findVmOnHyperHost(String name) throws Exception { diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DistributedVirtualSwitchMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DistributedVirtualSwitchMO.java index fbb4265bcfb9..40a0a64650a4 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DistributedVirtualSwitchMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/DistributedVirtualSwitchMO.java @@ -24,6 +24,8 @@ import org.apache.log4j.Logger; +import com.cloud.hypervisor.vmware.util.VmwareContext; +import com.cloud.utils.Pair; import com.vmware.vim25.DVPortgroupConfigSpec; import com.vmware.vim25.DVSConfigInfo; import com.vmware.vim25.ManagedObjectReference; @@ -32,8 +34,6 @@ import com.vmware.vim25.VMwareDVSConfigSpec; import com.vmware.vim25.VMwareDVSPvlanMapEntry; -import com.cloud.hypervisor.vmware.util.VmwareContext; - public class DistributedVirtualSwitchMO extends BaseMO { @SuppressWarnings("unused") private static final Logger s_logger = Logger.getLogger(DistributedVirtualSwitchMO.class); @@ -169,4 +169,28 @@ public Map retrieveVlanPvlan(int vlanid return result; } + public Pair retrieveVlanFromPvlan(int pvlanid, ManagedObjectReference dvSwitchMor) throws Exception { + assert (dvSwitchMor != null); + + Pair result = null; + + VMwareDVSConfigInfo configinfo = (VMwareDVSConfigInfo)_context.getVimClient().getDynamicProperty(dvSwitchMor, "config"); + List pvlanConfig = null; + pvlanConfig = configinfo.getPvlanConfig(); + + if (null == pvlanConfig || 0 == pvlanConfig.size()) { + return result; + } + + // Iterate through the pvlanMapList and check if the specified pvlan id exist. If it does, set the fields in result accordingly. + for (VMwareDVSPvlanMapEntry mapEntry : pvlanConfig) { + int entryVlanid = mapEntry.getPrimaryVlanId(); + int entryPvlanid = mapEntry.getSecondaryVlanId(); + if (pvlanid == entryPvlanid) { + result = new Pair<>(entryVlanid, HypervisorHostHelper.PvlanType.valueOf(mapEntry.getPvlanType())); + break; + } + } + return result; + } } diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java index cc50b3d5bc13..5aab3a25ce28 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/HostMO.java @@ -496,6 +496,18 @@ public String getHostName() throws Exception { return (String)_context.getVimClient().getDynamicProperty(_mor, "name"); } + @Override + public synchronized List listVmsOnHyperHost(String vmName) throws Exception { + List vms = new ArrayList<>(); + if (vmName != null && !vmName.isEmpty()) { + vms.add(findVmOnHyperHost(vmName)); + } else { + loadVmCache(); + vms.addAll(_vmCache.values()); + } + return vms; + } + @Override public synchronized VirtualMachineMO findVmOnHyperHost(String vmName) throws Exception { if (s_logger.isDebugEnabled()) diff --git a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java index 6f0cd2291b47..a9ceb5d806ec 100644 --- a/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java +++ b/vmware-base/src/main/java/com/cloud/hypervisor/vmware/mo/VmwareHypervisorHost.java @@ -16,6 +16,8 @@ // under the License. package com.cloud.hypervisor.vmware.mo; +import java.util.List; + import com.vmware.vim25.ClusterDasConfigInfo; import com.vmware.vim25.ComputeResourceSummary; import com.vmware.vim25.ManagedObjectReference; @@ -51,6 +53,8 @@ public interface VmwareHypervisorHost { String getHyperHostDefaultGateway() throws Exception; + List listVmsOnHyperHost(String name) throws Exception; + VirtualMachineMO findVmOnHyperHost(String name) throws Exception; VirtualMachineMO findVmOnPeerHyperHost(String name) throws Exception;