diff --git a/api/src/main/java/com/cloud/network/vpc/VpcService.java b/api/src/main/java/com/cloud/network/vpc/VpcService.java index 2cdc034a16e..0f0d29f4082 100644 --- a/api/src/main/java/com/cloud/network/vpc/VpcService.java +++ b/api/src/main/java/com/cloud/network/vpc/VpcService.java @@ -132,6 +132,8 @@ public interface VpcService { */ boolean startVpc(long vpcId, boolean destroyOnFailure) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException; + void startVpc(CreateVPCCmd cmd) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException; + /** * Shuts down the VPC which includes shutting down all VPC provider and rules cleanup on the backend * 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 81217b8406a..54c0227de9f 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -266,6 +266,7 @@ public class ApiConstants { public static final String IS_CLEANUP_REQUIRED = "iscleanuprequired"; public static final String IS_DYNAMIC = "isdynamic"; public static final String IS_EDGE = "isedge"; + public static final String IS_ENCRYPTED = "isencrypted"; public static final String IS_EXTRACTABLE = "isextractable"; public static final String IS_FEATURED = "isfeatured"; public static final String IS_IMPLICIT = "isimplicit"; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java index a583675da76..a1024a98898 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/volume/ListVolumesCmd.java @@ -31,6 +31,7 @@ import org.apache.cloudstack.api.response.DiskOfferingResponse; import org.apache.cloudstack.api.response.HostResponse; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.PodResponse; +import org.apache.cloudstack.api.response.ServiceOfferingResponse; import org.apache.cloudstack.api.response.StoragePoolResponse; import org.apache.cloudstack.api.response.UserVmResponse; import org.apache.cloudstack.api.response.VolumeResponse; @@ -80,6 +81,12 @@ public class ListVolumesCmd extends BaseListRetrieveOnlyResourceCountCmd impleme RoleType.Admin}) private String storageId; + @Parameter(name = ApiConstants.SERVICE_OFFERING_ID, type = CommandType.UUID, + entityType = ServiceOfferingResponse.class, + description = "list volumes by disk offering of a service offering. If both service offering and " + + "disk offering are passed, service offering is ignored", since = "4.19.1") + private Long serviceOfferingId; + @Parameter(name = ApiConstants.DISK_OFFERING_ID, type = CommandType.UUID, entityType = DiskOfferingResponse.class, description = "list volumes by disk offering", since = "4.4") private Long diskOfferingId; @@ -94,6 +101,9 @@ public class ListVolumesCmd extends BaseListRetrieveOnlyResourceCountCmd impleme @Parameter(name = ApiConstants.STATE, type = CommandType.STRING, description = "state of the volume. Possible values are: Ready, Allocated, Destroy, Expunging, Expunged.") private String state; + @Parameter(name = ApiConstants.IS_ENCRYPTED, type = CommandType.BOOLEAN, description = "list only volumes that are encrypted", since = "4.19.1", + authorized = { RoleType.Admin }) + private Boolean encrypted; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -118,6 +128,10 @@ public class ListVolumesCmd extends BaseListRetrieveOnlyResourceCountCmd impleme return podId; } + public Long getServiceOfferingId() { + return serviceOfferingId; + } + public Long getDiskOfferingId() { return diskOfferingId; } @@ -151,6 +165,10 @@ public class ListVolumesCmd extends BaseListRetrieveOnlyResourceCountCmd impleme return state; } + public Boolean isEncrypted() { + return encrypted; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java index 94f05f707a0..89a65f8c27c 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmd.java @@ -208,11 +208,7 @@ public class CreateVPCCmd extends BaseAsyncCreateCmd implements UserCmd { public void execute() { Vpc vpc = null; try { - if (isStart()) { - _vpcService.startVpc(getEntityId(), true); - } else { - logger.debug("Not starting VPC as " + ApiConstants.START + "=false was passed to the API"); - } + _vpcService.startVpc(this); vpc = _entityMgr.findById(Vpc.class, getEntityId()); } catch (ResourceUnavailableException ex) { logger.warn("Exception: ", ex); diff --git a/api/src/main/java/org/apache/cloudstack/api/response/VolumeResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/VolumeResponse.java index 0d502a6d7a7..726c9adf8a3 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/VolumeResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/VolumeResponse.java @@ -290,13 +290,17 @@ public class VolumeResponse extends BaseResponseWithTagInformation implements Co private String externalUuid; @SerializedName(ApiConstants.VOLUME_CHECK_RESULT) - @Param(description = "details for the volume check result, they may vary for different hypervisors, since = 4.19.1") + @Param(description = "details for the volume check result, they may vary for different hypervisors", since = "4.19.1") private Map volumeCheckResult; @SerializedName(ApiConstants.VOLUME_REPAIR_RESULT) - @Param(description = "details for the volume repair result, they may vary for different hypervisors, since = 4.19.1") + @Param(description = "details for the volume repair result, they may vary for different hypervisors", since = "4.19.1") private Map volumeRepairResult; + @SerializedName(ApiConstants.ENCRYPT_FORMAT) + @Param(description = "the format of the disk encryption if applicable", since = "4.19.1") + private String encryptionFormat; + public String getPath() { return path; } @@ -842,4 +846,8 @@ public class VolumeResponse extends BaseResponseWithTagInformation implements Co public void setVolumeRepairResult(Map volumeRepairResult) { this.volumeRepairResult = volumeRepairResult; } + + public void setEncryptionFormat(String encryptionFormat) { + this.encryptionFormat = encryptionFormat; + } } diff --git a/api/src/test/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmdTest.java b/api/src/test/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmdTest.java index 79f27fd6687..a28e9e9fd04 100644 --- a/api/src/test/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmdTest.java +++ b/api/src/test/java/org/apache/cloudstack/api/command/user/vpc/CreateVPCCmdTest.java @@ -167,17 +167,16 @@ public class CreateVPCCmdTest extends TestCase { @Test public void testExecute() throws ResourceUnavailableException, InsufficientCapacityException { - ReflectionTestUtils.setField(cmd, "start", true); Vpc vpc = Mockito.mock(Vpc.class); VpcResponse response = Mockito.mock(VpcResponse.class); ReflectionTestUtils.setField(cmd, "id", 1L); responseGenerator = Mockito.mock(ResponseGenerator.class); - Mockito.when(_vpcService.startVpc(1L, true)).thenReturn(true); + Mockito.doNothing().when(_vpcService).startVpc(cmd); Mockito.when(_entityMgr.findById(Mockito.eq(Vpc.class), Mockito.any(Long.class))).thenReturn(vpc); cmd._responseGenerator = responseGenerator; Mockito.when(responseGenerator.createVpcResponse(ResponseObject.ResponseView.Restricted, vpc)).thenReturn(response); cmd.execute(); - Mockito.verify(_vpcService, Mockito.times(1)).startVpc(Mockito.anyLong(), Mockito.anyBoolean()); + Mockito.verify(_vpcService, Mockito.times(1)).startVpc(cmd); } } diff --git a/core/src/main/java/com/cloud/agent/api/GetVolumeStatAnswer.java b/core/src/main/java/com/cloud/agent/api/GetVolumeStatAnswer.java new file mode 100644 index 00000000000..8352c97c108 --- /dev/null +++ b/core/src/main/java/com/cloud/agent/api/GetVolumeStatAnswer.java @@ -0,0 +1,85 @@ +// +// 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 com.cloud.agent.api.LogLevel.Log4jLevel; +import com.cloud.storage.Storage.StoragePoolType; + +@LogLevel(Log4jLevel.Trace) +public class GetVolumeStatAnswer extends Answer { + String poolUuid; + StoragePoolType poolType; + String volumePath; + long size = 0; + long virtualSize = 0; + + public GetVolumeStatAnswer(GetVolumeStatCommand cmd, long size, long virtualSize) { + super(cmd, true, ""); + this.poolUuid = cmd.getPoolUuid(); + this.poolType = cmd.getPoolType(); + this.volumePath = cmd.getVolumePath(); + this.size = size; + this.virtualSize = virtualSize; + } + + public GetVolumeStatAnswer(GetVolumeStatCommand cmd, boolean success, String details) { + super(cmd, success, details); + } + + protected GetVolumeStatAnswer() { + //no-args constructor for json serialization-deserialization + } + + public String getPoolUuid() { + return poolUuid; + } + + public void setPoolUuid(String poolUuid) { + this.poolUuid = poolUuid; + } + + public StoragePoolType getPoolType() { + return poolType; + } + + public void setPoolType(StoragePoolType poolType) { + this.poolType = poolType; + } + + public long getSize() { + return size; + } + + public void setSize(long size) { + this.size = size; + } + + public long getVirtualSize() { + return virtualSize; + } + + public void setVirtualSize(long virtualSize) { + this.virtualSize = virtualSize; + } + + public String getString() { + return "GetVolumeStatAnswer [poolUuid=" + poolUuid + ", poolType=" + poolType + ", volumePath=" + volumePath + ", size=" + size + ", virtualSize=" + virtualSize + "]"; + } +} diff --git a/core/src/main/java/com/cloud/agent/api/GetVolumeStatCommand.java b/core/src/main/java/com/cloud/agent/api/GetVolumeStatCommand.java new file mode 100644 index 00000000000..1be3d6a0419 --- /dev/null +++ b/core/src/main/java/com/cloud/agent/api/GetVolumeStatCommand.java @@ -0,0 +1,72 @@ +// +// 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 com.cloud.agent.api.LogLevel.Log4jLevel; +import com.cloud.storage.Storage.StoragePoolType; + +@LogLevel(Log4jLevel.Trace) +public class GetVolumeStatCommand extends Command { + String volumePath; + StoragePoolType poolType; + String poolUuid; + + protected GetVolumeStatCommand() { + } + + public GetVolumeStatCommand(String volumePath, StoragePoolType poolType, String poolUuid) { + this.volumePath = volumePath; + this.poolType = poolType; + this.poolUuid = poolUuid; + } + + public String getVolumePath() { + return volumePath; + } + + public void setVolumePath(String volumePath) { + this.volumePath = volumePath; + } + + public StoragePoolType getPoolType() { + return poolType; + } + + public void setPoolType(StoragePoolType poolType) { + this.poolType = poolType; + } + + public String getPoolUuid() { + return poolUuid; + } + + public void setPoolUuid(String storeUuid) { + this.poolUuid = storeUuid; + } + + @Override + public boolean executeInSequence() { + return false; + } + + public String getString() { + return "GetVolumeStatCommand [volumePath=" + volumePath + ", poolType=" + poolType + ", poolUuid=" + poolUuid + "]"; + } +} diff --git a/core/src/main/java/org/apache/cloudstack/storage/to/VolumeObjectTO.java b/core/src/main/java/org/apache/cloudstack/storage/to/VolumeObjectTO.java index 2bb67c80ce4..6514038ac62 100644 --- a/core/src/main/java/org/apache/cloudstack/storage/to/VolumeObjectTO.java +++ b/core/src/main/java/org/apache/cloudstack/storage/to/VolumeObjectTO.java @@ -39,6 +39,7 @@ public class VolumeObjectTO extends DownloadableObjectTO implements DataTO { private DataStoreTO dataStore; private String name; private Long size; + private Long usableSize; private String path; private Long volumeId; private String vmName; @@ -161,6 +162,10 @@ public class VolumeObjectTO extends DownloadableObjectTO implements DataTO { return size; } + public Long getUsableSize() { + return usableSize; + } + @Override public DataObjectType getObjectType() { return DataObjectType.VOLUME; @@ -178,6 +183,10 @@ public class VolumeObjectTO extends DownloadableObjectTO implements DataTO { this.size = size; } + public void setUsableSize(Long usableSize) { + this.usableSize = usableSize; + } + public void setPath(String path) { this.path = path; } 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 4e9c63699ca..7ef7fd44b24 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 @@ -112,7 +112,8 @@ public interface VolumeDao extends GenericDao, StateDao virtualRouters); 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 31d64daf147..2e68dcae3c5 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 @@ -81,7 +81,6 @@ public class VolumeDaoImpl extends GenericDaoBase implements Vol @Inject ResourceTagDao _tagsDao; - protected static final String SELECT_VM_SQL = "SELECT DISTINCT instance_id from volumes v where v.host_id = ? and v.mirror_state = ?"; // need to account for zone-wide primary storage where storage_pool has // null-value pod and cluster, where hypervisor information is stored in // storage_pool diff --git a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ImageStoreDaoImpl.java b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ImageStoreDaoImpl.java index 84b88c215ca..21c5dc76d96 100644 --- a/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ImageStoreDaoImpl.java +++ b/engine/schema/src/main/java/org/apache/cloudstack/storage/datastore/db/ImageStoreDaoImpl.java @@ -130,7 +130,7 @@ public class ImageStoreDaoImpl extends GenericDaoBase implem } if (scope.getScopeId() != null) { SearchCriteria scc = createSearchCriteria(); - scc.addOr("scope", SearchCriteria.Op.EQ, ScopeType.REGION); + scc.addOr("scope", SearchCriteria.Op.EQ, ScopeType.ZONE); scc.addOr("dcId", SearchCriteria.Op.EQ, scope.getScopeId()); sc.addAnd("scope", SearchCriteria.Op.SC, scc); } diff --git a/engine/schema/src/main/resources/META-INF/db/views/cloud.volume_view.sql b/engine/schema/src/main/resources/META-INF/db/views/cloud.volume_view.sql index fd21fff1494..950dcddf4c7 100644 --- a/engine/schema/src/main/resources/META-INF/db/views/cloud.volume_view.sql +++ b/engine/schema/src/main/resources/META-INF/db/views/cloud.volume_view.sql @@ -39,6 +39,7 @@ SELECT `volumes`.`path` AS `path`, `volumes`.`chain_info` AS `chain_info`, `volumes`.`external_uuid` AS `external_uuid`, + `volumes`.`encrypt_format` AS `encrypt_format`, `account`.`id` AS `account_id`, `account`.`uuid` AS `account_uuid`, `account`.`account_name` AS `account_name`, diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetRemoteVmsCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetRemoteVmsCommandWrapper.java index ead294ad05f..a9da4a50452 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetRemoteVmsCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetRemoteVmsCommandWrapper.java @@ -47,9 +47,7 @@ public final class LibvirtGetRemoteVmsCommandWrapper extends CommandWrapper unmanagedInstances = new HashMap<>(); try { Connect conn = LibvirtConnection.getConnection(hypervisorURI); @@ -58,26 +56,28 @@ public final class LibvirtGetRemoteVmsCommandWrapper extends CommandWrapper sourceHostPath = getSourceHostPath(libvirtComputingResource, diskDef.getSourcePath()); if (sourceHostPath != null) { disk.setDatastoreHost(sourceHostPath.first()); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVolumeStatCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVolumeStatCommandWrapper.java new file mode 100644 index 00000000000..2a9c886f449 --- /dev/null +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtGetVolumeStatCommandWrapper.java @@ -0,0 +1,66 @@ +// +//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.hypervisor.kvm.resource.wrapper; + +import org.apache.log4j.Logger; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.GetVolumeStatAnswer; +import com.cloud.agent.api.GetVolumeStatCommand; +import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource; +import com.cloud.hypervisor.kvm.storage.KVMPhysicalDisk; +import com.cloud.hypervisor.kvm.storage.KVMStoragePool; +import com.cloud.hypervisor.kvm.storage.KVMStoragePoolManager; +import com.cloud.resource.CommandWrapper; +import com.cloud.resource.ResourceWrapper; +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.utils.exception.CloudRuntimeException; + +@ResourceWrapper(handles = GetVolumeStatCommand.class) +public final class LibvirtGetVolumeStatCommandWrapper extends CommandWrapper { + private static final Logger s_logger = Logger.getLogger(LibvirtGetVolumeStatCommandWrapper.class); + + @Override + public Answer execute(final GetVolumeStatCommand cmd, final LibvirtComputingResource libvirtComputingResource) { + try { + String volumePath = cmd.getVolumePath(); + StoragePoolType poolType = cmd.getPoolType(); + String poolUuid = cmd.getPoolUuid(); + + KVMStoragePoolManager storagePoolMgr = libvirtComputingResource.getStoragePoolMgr(); + KVMStoragePool primaryPool = storagePoolMgr.getStoragePool(poolType, poolUuid); + if (primaryPool == null) { + String msg = "Can't get volume stats as pool details unavailable for volume: " + volumePath + " on the storage pool: " + poolUuid; + return new GetVolumeStatAnswer(cmd, false, msg); + } + + KVMPhysicalDisk disk = primaryPool.getPhysicalDisk(volumePath); + if (disk == null) { + String msg = "Can't get volume stats as disk details unavailable for volume: " + volumePath + " on the storage pool: " + poolUuid; + return new GetVolumeStatAnswer(cmd, false, msg); + } + + return new GetVolumeStatAnswer(cmd, disk.getSize(), disk.getVirtualSize()); + } catch (CloudRuntimeException e) { + s_logger.error("Can't get volume stats, due to: " + e.getMessage(), e); + return new GetVolumeStatAnswer(cmd, false, "Can't get volume stats, due to: " + e.getMessage()); + } + } +} diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java index b97cb666de0..e15a3287692 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java @@ -67,6 +67,7 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.MigrateAnswer; import com.cloud.agent.api.MigrateCommand; import com.cloud.agent.api.MigrateCommand.MigrateDiskInfo; +import com.cloud.agent.api.to.DataTO; import com.cloud.agent.api.to.DiskTO; import com.cloud.agent.api.to.DpdkTO; import com.cloud.agent.api.to.VirtualMachineTO; @@ -90,6 +91,7 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper disks, String vmName) { + String oldIsoVolumePath = null; + for (DiskDef disk : disks) { + if (DiskDef.DeviceType.CDROM.equals(disk.getDeviceType()) + && CDROM_LABEL.equals(disk.getDiskLabel()) + && disk.getDiskPath() != null) { + oldIsoVolumePath = disk.getDiskPath(); + break; + } + } + return oldIsoVolumePath; + } + + private String getNewVolumePathForCdrom(LibvirtComputingResource libvirtComputingResource, Connect conn, VirtualMachineTO to) throws LibvirtException, URISyntaxException { + DiskTO newDisk = null; + for (DiskTO disk : to.getDisks()) { + DataTO data = disk.getData(); + if (disk.getDiskSeq() == 3 && data != null && data.getPath() != null) { + newDisk = disk; + break; + } + } + + String newIsoVolumePath = null; + if (newDisk != null) { + newIsoVolumePath = libvirtComputingResource.getVolumePath(conn, newDisk); + } + return newIsoVolumePath; + } + + protected String replaceCdromIsoPath(String xmlDesc, String vmName, String oldIsoVolumePath, String newIsoVolumePath) throws IOException, ParserConfigurationException, TransformerException, SAXException { + InputStream in = IOUtils.toInputStream(xmlDesc); + + DocumentBuilderFactory docFactory = ParserUtils.getSaferDocumentBuilderFactory(); + DocumentBuilder docBuilder = docFactory.newDocumentBuilder(); + Document doc = docBuilder.parse(in); + + // Get the root element + Node domainNode = doc.getFirstChild(); + + NodeList domainChildNodes = domainNode.getChildNodes(); + + for (int i = 0; i < domainChildNodes.getLength(); i++) { + Node domainChildNode = domainChildNodes.item(i); + if ("devices".equals(domainChildNode.getNodeName())) { + NodeList devicesChildNodes = domainChildNode.getChildNodes(); + for (int x = 0; x < devicesChildNodes.getLength(); x++) { + Node deviceChildNode = devicesChildNodes.item(x); + if ("disk".equals(deviceChildNode.getNodeName())) { + Node diskNode = deviceChildNode; + NodeList diskChildNodes = diskNode.getChildNodes(); + for (int z = 0; z < diskChildNodes.getLength(); z++) { + Node diskChildNode = diskChildNodes.item(z); + if ("source".equals(diskChildNode.getNodeName())) { + NamedNodeMap sourceNodeAttributes = diskChildNode.getAttributes(); + Node sourceNodeAttribute = sourceNodeAttributes.getNamedItem("file"); + if (oldIsoVolumePath != null && sourceNodeAttribute != null + && oldIsoVolumePath.equals(sourceNodeAttribute.getNodeValue())) { + diskNode.removeChild(diskChildNode); + Element newChildSourceNode = doc.createElement("source"); + newChildSourceNode.setAttribute("file", newIsoVolumePath); + diskNode.appendChild(newChildSourceNode); + logger.debug(String.format("Replaced ISO path [%s] with [%s] in VM [%s] XML configuration.", oldIsoVolumePath, newIsoVolumePath, vmName)); + return getXml(doc); + } + } + } + } + } + } + } + + return getXml(doc); + } + private String getPathFromSourceText(Set paths, String sourceText) { if (paths != null && StringUtils.isNotBlank(sourceText)) { for (String path : paths) { diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateVolumeCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateVolumeCommandWrapper.java index 00f627d0528..cd5ce031e64 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateVolumeCommandWrapper.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateVolumeCommandWrapper.java @@ -140,7 +140,6 @@ public class LibvirtMigrateVolumeCommandWrapper extends CommandWrapper 0) { DomainBlockJobInfo blockJobInfo = dm.getBlockJobInfo(diskLabel, 0); if (blockJobInfo != null) { - logger.debug(String.format("Volume %s : %s block copy progress: %s%% current value:%s end value:%s", diskLabel, srcPath, (blockJobInfo.end == 0)? 0 : 100*(blockJobInfo.cur / (double) blockJobInfo.end), blockJobInfo.cur, blockJobInfo.end)); + blockCopyProgress = (blockJobInfo.end == 0)? blockCopyProgress : 100 * (blockJobInfo.cur / (double) blockJobInfo.end); + logger.debug(String.format("Volume %s : %s, block copy progress: %s%%, current value: %s end value: %s, job info - type: %s, bandwidth: %s", + diskLabel, srcPath, blockCopyProgress, blockJobInfo.cur, blockJobInfo.end, blockJobInfo.type, blockJobInfo.bandwidth)); if (blockJobInfo.cur == blockJobInfo.end) { - logger.info(String.format("Block copy completed for the volume %s : %s", diskLabel, srcPath)); - dm.blockJobAbort(diskLabel, Domain.BlockJobAbortFlags.PIVOT); - if (StringUtils.isNotEmpty(srcSecretUUID)) { - libvirtComputingResource.removeLibvirtVolumeSecret(conn, srcSecretUUID); + if (blockJobInfo.end > 0) { + logger.info(String.format("Block copy completed for the volume %s : %s", diskLabel, srcPath)); + dm.blockJobAbort(diskLabel, Domain.BlockJobAbortFlags.PIVOT); + if (StringUtils.isNotEmpty(srcSecretUUID)) { + libvirtComputingResource.removeLibvirtVolumeSecret(conn, srcSecretUUID); + } + break; + } else { + // cur = 0, end = 0 - at this point, disk does not have an active block job (so, no need to abort job) + String msg = String.format("No active block copy job for the volume %s : %s - job stopped at %s progress", diskLabel, srcPath, blockCopyProgress); + logger.warn(msg); + return new MigrateVolumeAnswer(command, false, msg, null); } - break; } } else { logger.info("Failed to get the block copy status, trying to abort the job"); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePool.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePool.java index 96a4da09686..674799c0bbe 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePool.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStoragePool.java @@ -38,6 +38,9 @@ public interface KVMStoragePool { public static final long HeartBeatUpdateRetrySleep = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.KVM_HEARTBEAT_UPDATE_RETRY_SLEEP); public static final long HeartBeatCheckerTimeout = AgentPropertiesFileHandler.getPropertyValue(AgentProperties.KVM_HEARTBEAT_CHECKER_TIMEOUT); + public default KVMPhysicalDisk createPhysicalDisk(String volumeUuid, PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size, Long usableSize, byte[] passphrase) { + return createPhysicalDisk(volumeUuid, format, provisioningType, size, passphrase); + } public KVMPhysicalDisk createPhysicalDisk(String volumeUuid, PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size, byte[] passphrase); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java index 008768f25e9..b9671c872d1 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/KVMStorageProcessor.java @@ -1633,7 +1633,7 @@ public class KVMStorageProcessor implements StorageProcessor { } } else { vol = primaryPool.createPhysicalDisk(volume.getUuid(), format, - volume.getProvisioningType(), disksize, volume.getPassphrase()); + volume.getProvisioningType(), disksize, volume.getUsableSize(), volume.getPassphrase()); } final VolumeObjectTO newVol = new VolumeObjectTO(); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStorageAdaptor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStorageAdaptor.java index 9190510c7a7..1b660671b41 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStorageAdaptor.java @@ -154,6 +154,11 @@ public class ScaleIOStorageAdaptor implements StorageAdaptor { return MapStorageUuidToStoragePool.remove(uuid) != null; } + @Override + public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, QemuImg.PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size, byte[] passphrase) { + return createPhysicalDisk(name, pool, format, provisioningType, size, null, passphrase); + } + /** * ScaleIO doesn't need to communicate with the hypervisor normally to create a volume. This is used only to prepare a ScaleIO data disk for encryption. * Thin encrypted volumes are provisioned in QCOW2 format, which insulates the guest from zeroes/unallocated blocks in the block device that would @@ -163,11 +168,12 @@ public class ScaleIOStorageAdaptor implements StorageAdaptor { * @param format disk format * @param provisioningType provisioning type * @param size disk size + * @param usableSize usage disk size * @param passphrase passphrase * @return the disk object */ @Override - public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, QemuImg.PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size, byte[] passphrase) { + public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, QemuImg.PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size, Long usableSize, byte[] passphrase) { if (passphrase == null || passphrase.length == 0) { return null; } @@ -185,7 +191,12 @@ public class ScaleIOStorageAdaptor implements StorageAdaptor { QemuImg qemuImg = new QemuImg(0, true, false); Map options = new HashMap<>(); List qemuObjects = new ArrayList<>(); - long formattedSize = getUsableBytesFromRawBytes(disk.getSize()); + long formattedSize; + if (usableSize != null && usableSize > 0) { + formattedSize = usableSize; + } else { + formattedSize = getUsableBytesFromRawBytes(disk.getSize()); + } options.put("preallocation", QemuImg.PreallocationType.Metadata.toString()); qemuObjects.add(QemuObject.prepareSecretForQemuImg(disk.getFormat(), disk.getQemuEncryptFormat(), keyFile.toString(), "sec0", options)); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePool.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePool.java index 293ff29f984..77f21910da6 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePool.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/ScaleIOStoragePool.java @@ -72,6 +72,11 @@ public class ScaleIOStoragePool implements KVMStoragePool { } } + @Override + public KVMPhysicalDisk createPhysicalDisk(String volumeUuid, QemuImg.PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size, Long usableSize, byte[] passphrase) { + return this.storageAdaptor.createPhysicalDisk(volumeUuid, this, format, provisioningType, size, usableSize, passphrase); + } + @Override public KVMPhysicalDisk createPhysicalDisk(String volumeUuid, QemuImg.PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size, byte[] passphrase) { return this.storageAdaptor.createPhysicalDisk(volumeUuid, this, format, provisioningType, size, passphrase); diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java index 34bf08f4496..6d58dccb5d1 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/storage/StorageAdaptor.java @@ -41,6 +41,11 @@ public interface StorageAdaptor { public boolean deleteStoragePool(String uuid); + public default KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, + PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size, Long usableSize, byte[] passphrase) { + return createPhysicalDisk(name, pool, format, provisioningType, size, passphrase); + } + public KVMPhysicalDisk createPhysicalDisk(String name, KVMStoragePool pool, PhysicalDiskFormat format, Storage.ProvisioningType provisioningType, long size, byte[] passphrase); @@ -52,8 +57,17 @@ public interface StorageAdaptor { public boolean disconnectPhysicalDisk(Map volumeToDisconnect); - // given local path to file/device (per Libvirt XML), 1) check that device is - // handled by your adaptor, return false if not. 2) clean up device, return true + /** + * Given local path to file/device (per Libvirt XML), + * 1) Make sure to check that device is handled by your adaptor, return false if not. + * 2) clean up device, return true + * 3) if clean up fails, then return false + * + * If the method wrongly returns true, then there are chances that disconnect will not reach the right storage adapter + * + * @param localPath path for the file/device from the disk definition per Libvirt XML. + * @return true if the operation is successful; false if the operation fails or the adapter fails to handle the path. + */ public boolean disconnectPhysicalDiskByPath(String localPath); public boolean deletePhysicalDisk(String uuid, KVMStoragePool pool, Storage.ImageFormat format); diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java index 29a5e1f934b..3c5e54e2ba8 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java @@ -132,6 +132,7 @@ public class LibvirtMigrateCommandWrapperTest { " \n" + " \n" + " \n" + +" \n" + " \n" + " \n" + " \n" + @@ -249,6 +250,7 @@ public class LibvirtMigrateCommandWrapperTest { " \n" + " \n" + " \n" + +" \n" + " \n" + " \n" + " \n" + @@ -1007,4 +1009,14 @@ public class LibvirtMigrateCommandWrapperTest { assertTrue(result.containsAll(Arrays.asList("vda", "vdb"))); } + @Test + public void replaceCdromIsoPathTest() throws ParserConfigurationException, IOException, TransformerException, + SAXException { + String oldIsoVolumePath = "/mnt/ec8dfdd8-f341-3b0a-988f-cfbc93e46fc4/251-2-2b2071a4-21c7-340e-a861-1bd30fb5cbed.iso"; + String newIsoVolumePath = "/mnt/50bf9d15-1b0f-3cc1-9e8a-55df3e17e0c4/251-2-2b2071a4-21c7-340e-a861-1bd30fb5cbed.iso"; + + String finalXml = libvirtMigrateCmdWrapper.replaceCdromIsoPath(fullfile, null, oldIsoVolumePath, newIsoVolumePath); + + Assert.assertTrue(finalXml.contains(newIsoVolumePath)); + } } diff --git a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/version/KubernetesVersionManagerImpl.java b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/version/KubernetesVersionManagerImpl.java index 4718fc4bad9..8f4e36550dc 100644 --- a/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/version/KubernetesVersionManagerImpl.java +++ b/plugins/integrations/kubernetes-service/src/main/java/com/cloud/kubernetes/version/KubernetesVersionManagerImpl.java @@ -79,6 +79,20 @@ public class KubernetesVersionManagerImpl extends ManagerBase implements Kuberne public static final String MINIMUN_AUTOSCALER_SUPPORTED_VERSION = "1.15.0"; + protected void updateTemplateDetailsInKubernetesSupportedVersionResponse( + final KubernetesSupportedVersion kubernetesSupportedVersion, KubernetesSupportedVersionResponse response) { + TemplateJoinVO template = templateJoinDao.findById(kubernetesSupportedVersion.getIsoId()); + if (template == null) { + return; + } + response.setIsoId(template.getUuid()); + response.setIsoName(template.getName()); + if (template.getState() != null) { + response.setIsoState(template.getState().toString()); + } + response.setDirectDownload(template.isDirectDownload()); + } + private KubernetesSupportedVersionResponse createKubernetesSupportedVersionResponse(final KubernetesSupportedVersion kubernetesSupportedVersion) { KubernetesSupportedVersionResponse response = new KubernetesSupportedVersionResponse(); response.setObjectName("kubernetessupportedversion"); @@ -98,15 +112,7 @@ public class KubernetesVersionManagerImpl extends ManagerBase implements Kuberne response.setSupportsHA(compareSemanticVersions(kubernetesSupportedVersion.getSemanticVersion(), KubernetesClusterService.MIN_KUBERNETES_VERSION_HA_SUPPORT)>=0); response.setSupportsAutoscaling(versionSupportsAutoscaling(kubernetesSupportedVersion)); - TemplateJoinVO template = templateJoinDao.findById(kubernetesSupportedVersion.getIsoId()); - if (template != null) { - response.setIsoId(template.getUuid()); - response.setIsoName(template.getName()); - if (template.getState() != null) { - response.setIsoState(template.getState().toString()); - } - response.setDirectDownload(template.isDirectDownload()); - } + updateTemplateDetailsInKubernetesSupportedVersionResponse(kubernetesSupportedVersion, response); response.setCreated(kubernetesSupportedVersion.getCreated()); return response; } diff --git a/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/version/KubernetesVersionManagerImplTest.java b/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/version/KubernetesVersionManagerImplTest.java new file mode 100644 index 00000000000..ee371df3b72 --- /dev/null +++ b/plugins/integrations/kubernetes-service/src/test/java/com/cloud/kubernetes/version/KubernetesVersionManagerImplTest.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.kubernetes.version; + +import java.util.UUID; + +import org.apache.cloudstack.api.response.KubernetesSupportedVersionResponse; +import org.apache.cloudstack.engine.subsystem.api.storage.ObjectInDataStoreStateMachine; +import org.junit.Assert; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.test.util.ReflectionTestUtils; + +import com.cloud.api.query.dao.TemplateJoinDao; +import com.cloud.api.query.vo.TemplateJoinVO; + +@RunWith(MockitoJUnitRunner.class) +public class KubernetesVersionManagerImplTest { + + @Mock + TemplateJoinDao templateJoinDao; + + @InjectMocks + KubernetesVersionManagerImpl kubernetesVersionManager = new KubernetesVersionManagerImpl(); + + @Test + public void testUpdateTemplateDetailsInKubernetesSupportedVersionResponseNullTemplate() { + KubernetesSupportedVersion kubernetesSupportedVersion = Mockito.mock(KubernetesSupportedVersion.class); + Mockito.when(kubernetesSupportedVersion.getIsoId()).thenReturn(1L); + KubernetesSupportedVersionResponse response = new KubernetesSupportedVersionResponse(); + kubernetesVersionManager.updateTemplateDetailsInKubernetesSupportedVersionResponse(kubernetesSupportedVersion, + response); + Assert.assertNull(ReflectionTestUtils.getField(response, "isoId")); + } + + @Test + public void testUpdateTemplateDetailsInKubernetesSupportedVersionResponseValidTemplate() { + KubernetesSupportedVersion kubernetesSupportedVersion = Mockito.mock(KubernetesSupportedVersion.class); + Mockito.when(kubernetesSupportedVersion.getIsoId()).thenReturn(1L); + KubernetesSupportedVersionResponse response = new KubernetesSupportedVersionResponse(); + TemplateJoinVO templateJoinVO = Mockito.mock(TemplateJoinVO.class); + String uuid = UUID.randomUUID().toString(); + Mockito.when(templateJoinVO.getUuid()).thenReturn(uuid); + Mockito.when(templateJoinDao.findById(1L)).thenReturn(templateJoinVO); + kubernetesVersionManager.updateTemplateDetailsInKubernetesSupportedVersionResponse(kubernetesSupportedVersion, + response); + Assert.assertEquals(uuid, ReflectionTestUtils.getField(response, "isoId")); + Assert.assertNull(ReflectionTestUtils.getField(response, "isoState")); + ObjectInDataStoreStateMachine.State state = ObjectInDataStoreStateMachine.State.Ready; + Mockito.when(templateJoinVO.getState()).thenReturn(state); + kubernetesVersionManager.updateTemplateDetailsInKubernetesSupportedVersionResponse(kubernetesSupportedVersion, + response); + Assert.assertEquals(state.toString(), ReflectionTestUtils.getField(response, "isoState")); + } +} diff --git a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/driver/ScaleIOPrimaryDataStoreDriver.java b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/driver/ScaleIOPrimaryDataStoreDriver.java index 817b263e9b4..8397334d0dd 100644 --- a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/driver/ScaleIOPrimaryDataStoreDriver.java +++ b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/driver/ScaleIOPrimaryDataStoreDriver.java @@ -66,6 +66,8 @@ import org.apache.logging.log4j.Logger; import org.apache.logging.log4j.LogManager; import com.cloud.agent.api.Answer; +import com.cloud.agent.api.GetVolumeStatAnswer; +import com.cloud.agent.api.GetVolumeStatCommand; import com.cloud.agent.api.storage.MigrateVolumeCommand; import com.cloud.agent.api.storage.ResizeVolumeCommand; import com.cloud.agent.api.to.DataObjectType; @@ -491,10 +493,10 @@ public class ScaleIOPrimaryDataStoreDriver implements PrimaryDataStoreDriver { } public CreateObjectAnswer createVolume(VolumeInfo volumeInfo, long storagePoolId) { - return createVolume(volumeInfo, storagePoolId, false); + return createVolume(volumeInfo, storagePoolId, false, null); } - public CreateObjectAnswer createVolume(VolumeInfo volumeInfo, long storagePoolId, boolean migrationInvolved) { + public CreateObjectAnswer createVolume(VolumeInfo volumeInfo, long storagePoolId, boolean migrationInvolved, Long usageSize) { logger.debug("Creating PowerFlex volume"); StoragePoolVO storagePool = storagePoolDao.findById(storagePoolId); @@ -544,6 +546,9 @@ public class ScaleIOPrimaryDataStoreDriver implements PrimaryDataStoreDriver { VolumeObjectTO prepVolume = (VolumeObjectTO) createdObject.getTO(); prepVolume.setPath(volumePath); prepVolume.setUuid(volumePath); + if (usageSize != null) { + prepVolume.setUsableSize(usageSize); + } CreateObjectCommand cmd = new CreateObjectCommand(prepVolume); EndPoint ep = selector.select(volumeInfo, true); if (ep == null) { @@ -846,7 +851,8 @@ public class ScaleIOPrimaryDataStoreDriver implements PrimaryDataStoreDriver { // Volume migration across different PowerFlex/ScaleIO clusters final long srcVolumeId = srcData.getId(); DataStore srcStore = srcData.getDataStore(); - Map srcDetails = getVolumeDetails((VolumeInfo) srcData, srcStore); + VolumeInfo srcVolumeInfo = (VolumeInfo) srcData; + Map srcDetails = getVolumeDetails(srcVolumeInfo, srcStore); DataStore destStore = destData.getDataStore(); final long destPoolId = destStore.getId(); @@ -858,8 +864,17 @@ public class ScaleIOPrimaryDataStoreDriver implements PrimaryDataStoreDriver { EndPoint ep = RemoteHostEndPoint.getHypervisorHostEndPoint(host); Answer answer = null; + Long srcVolumeUsableSize = null; try { - CreateObjectAnswer createAnswer = createVolume((VolumeInfo) destData, destStore.getId(), true); + GetVolumeStatCommand statCmd = new GetVolumeStatCommand(srcVolumeInfo.getPath(), srcVolumeInfo.getStoragePoolType(), srcStore.getUuid()); + GetVolumeStatAnswer statAnswer = (GetVolumeStatAnswer) ep.sendMessage(statCmd); + if (!statAnswer.getResult() ) { + logger.warn(String.format("Unable to get volume %s stats", srcVolumeInfo.getId())); + } else if (statAnswer.getVirtualSize() > 0) { + srcVolumeUsableSize = statAnswer.getVirtualSize(); + } + + CreateObjectAnswer createAnswer = createVolume((VolumeInfo) destData, destStore.getId(), true, srcVolumeUsableSize); destVolumePath = createAnswer.getData().getPath(); destVolTO.setPath(destVolumePath); diff --git a/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/driver/ScaleIOPrimaryDataStoreDriverTest.java b/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/driver/ScaleIOPrimaryDataStoreDriverTest.java index b8a799a4e07..4979fd1fa0a 100644 --- a/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/driver/ScaleIOPrimaryDataStoreDriverTest.java +++ b/plugins/storage/volume/scaleio/src/test/java/org/apache/cloudstack/storage/datastore/driver/ScaleIOPrimaryDataStoreDriverTest.java @@ -20,7 +20,10 @@ package org.apache.cloudstack.storage.datastore.driver; import com.cloud.agent.api.Answer; +import com.cloud.agent.api.GetVolumeStatAnswer; +import com.cloud.agent.api.GetVolumeStatCommand; import com.cloud.agent.api.storage.MigrateVolumeAnswer; +import com.cloud.agent.api.storage.MigrateVolumeCommand; import com.cloud.agent.api.to.DataTO; import com.cloud.agent.api.to.DiskTO; import com.cloud.configuration.Config; @@ -205,16 +208,23 @@ public class ScaleIOPrimaryDataStoreDriverTest { RemoteHostEndPoint ep = Mockito.mock(RemoteHostEndPoint.class); remoteHostEndPointMock.when(() -> RemoteHostEndPoint.getHypervisorHostEndPoint(host)).thenReturn(ep); + long volumeVirtualSize = 68673077248L; DataTO dataTO = Mockito.mock(DataTO.class); CreateObjectAnswer createAnswer = new CreateObjectAnswer(dataTO); - doReturn(createAnswer).when(scaleIOPrimaryDataStoreDriver).createVolume(destData, 2L, true); + doReturn(createAnswer).when(scaleIOPrimaryDataStoreDriver).createVolume(destData, 2L, true, volumeVirtualSize); when(dataTO.getPath()).thenReturn("bec0ba7700000007:vol-11-6aef-10ee"); doReturn(true).when(scaleIOPrimaryDataStoreDriver) .grantAccess(any(), any(), any()); when(configDao.getValue(Config.MigrateWait.key())).thenReturn("3600"); + + GetVolumeStatAnswer getVolumeStatAnswer = Mockito.mock(GetVolumeStatAnswer.class); + when(ep.sendMessage(any(GetVolumeStatCommand.class))).thenReturn(getVolumeStatAnswer); + when(getVolumeStatAnswer.getResult()).thenReturn(true); + when(getVolumeStatAnswer.getVirtualSize()).thenReturn(volumeVirtualSize); + MigrateVolumeAnswer migrateVolumeAnswer = Mockito.mock(MigrateVolumeAnswer.class); - when(ep.sendMessage(any())).thenReturn(migrateVolumeAnswer); + when(ep.sendMessage(any(MigrateVolumeCommand.class))).thenReturn(migrateVolumeAnswer); when(migrateVolumeAnswer.getResult()).thenReturn(true); Mockito.doNothing().when(scaleIOPrimaryDataStoreDriver) @@ -251,16 +261,21 @@ public class ScaleIOPrimaryDataStoreDriverTest { DataTO dataTO = Mockito.mock(DataTO.class); CreateObjectAnswer createAnswer = new CreateObjectAnswer(dataTO); - doReturn(createAnswer).when(scaleIOPrimaryDataStoreDriver).createVolume(destData, 2L, true); - when(dataTO.getPath()).thenReturn("bec0ba7700000007:vol-11-6aef-10ee"); - doReturn(true).when(scaleIOPrimaryDataStoreDriver) + Mockito.lenient().doReturn(createAnswer).when(scaleIOPrimaryDataStoreDriver).createVolume(destData, 2L, true, null); + Mockito.lenient().when(dataTO.getPath()).thenReturn("bec0ba7700000007:vol-11-6aef-10ee"); + Mockito.lenient().doReturn(true).when(scaleIOPrimaryDataStoreDriver) .grantAccess(any(), any(), any()); - when(configDao.getValue(Config.MigrateWait.key())).thenReturn("3600"); + Mockito.lenient().when(configDao.getValue(Config.MigrateWait.key())).thenReturn("3600"); + + GetVolumeStatAnswer getVolumeStatAnswer = Mockito.mock(GetVolumeStatAnswer.class); + Mockito.lenient().when(ep.sendMessage(any(GetVolumeStatCommand.class))).thenReturn(getVolumeStatAnswer); + Mockito.lenient().when(getVolumeStatAnswer.getResult()).thenReturn(false); + MigrateVolumeAnswer migrateVolumeAnswer = Mockito.mock(MigrateVolumeAnswer.class); when(ep.sendMessage(any())).thenReturn(migrateVolumeAnswer); - when(migrateVolumeAnswer.getResult()).thenReturn(false); - Mockito.doNothing().when(scaleIOPrimaryDataStoreDriver) + Mockito.lenient().when(migrateVolumeAnswer.getResult()).thenReturn(false); + Mockito.lenient().doNothing().when(scaleIOPrimaryDataStoreDriver) .revertBlockCopyVolumeOperations(any(), any(), any(), any()); Answer answer = scaleIOPrimaryDataStoreDriver.liveMigrateVolume(srcData, destData); diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java index 1a864167bd2..6ccf128d537 100644 --- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java @@ -2397,7 +2397,7 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q private Pair, Integer> searchForVolumeIdsAndCount(ListVolumesCmd cmd) { Account caller = CallContext.current().getCallingAccount(); - List permittedAccounts = new ArrayList(); + List permittedAccounts = new ArrayList<>(); Long id = cmd.getId(); Long vmInstanceId = cmd.getVirtualMachineId(); @@ -2407,7 +2407,8 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q Map tags = cmd.getTags(); String storageId = cmd.getStorageId(); Long clusterId = cmd.getClusterId(); - Long diskOffId = cmd.getDiskOfferingId(); + Long serviceOfferingId = cmd.getServiceOfferingId(); + Long diskOfferingId = cmd.getDiskOfferingId(); Boolean display = cmd.getDisplay(); String state = cmd.getState(); boolean shouldListSystemVms = shouldListSystemVms(cmd, caller.getId()); @@ -2417,7 +2418,14 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q List ids = getIdsListFromCmd(cmd.getId(), cmd.getIds()); - Ternary domainIdRecursiveListProject = new Ternary(cmd.getDomainId(), cmd.isRecursive(), null); + if (diskOfferingId == null && serviceOfferingId != null) { + ServiceOfferingVO serviceOffering = _srvOfferingDao.findById(serviceOfferingId); + if (serviceOffering != null) { + diskOfferingId = serviceOffering.getDiskOfferingId(); + } + } + + Ternary domainIdRecursiveListProject = new Ternary<>(cmd.getDomainId(), cmd.isRecursive(), null); accountMgr.buildACLSearchParameters(caller, id, cmd.getAccountName(), cmd.getProjectId(), permittedAccounts, domainIdRecursiveListProject, cmd.listAll(), false); Long domainId = domainIdRecursiveListProject.first(); Boolean isRecursive = domainIdRecursiveListProject.second(); @@ -2437,6 +2445,13 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q volumeSearchBuilder.and("uuid", volumeSearchBuilder.entity().getUuid(), SearchCriteria.Op.NNULL); volumeSearchBuilder.and("instanceId", volumeSearchBuilder.entity().getInstanceId(), SearchCriteria.Op.EQ); volumeSearchBuilder.and("dataCenterId", volumeSearchBuilder.entity().getDataCenterId(), SearchCriteria.Op.EQ); + if (cmd.isEncrypted() != null) { + if (cmd.isEncrypted()) { + volumeSearchBuilder.and("encryptFormat", volumeSearchBuilder.entity().getEncryptFormat(), SearchCriteria.Op.NNULL); + } else { + volumeSearchBuilder.and("encryptFormat", volumeSearchBuilder.entity().getEncryptFormat(), SearchCriteria.Op.NULL); + } + } if (keyword != null) { volumeSearchBuilder.and().op("keywordName", volumeSearchBuilder.entity().getName(), SearchCriteria.Op.LIKE); @@ -2540,8 +2555,8 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q } } - if (diskOffId != null) { - sc.setParameters("diskOfferingId", diskOffId); + if (diskOfferingId != null) { + sc.setParameters("diskOfferingId", diskOfferingId); } if (id != null) { @@ -4668,8 +4683,12 @@ public class QueryManagerImpl extends MutualExclusiveIdsManagerBase implements Q // other criteria if (keyword != null) { - sc.addAnd("name", SearchCriteria.Op.LIKE, "%" + keyword + "%"); - } else if (name != null) { + SearchCriteria scc = _templateJoinDao.createSearchCriteria(); + scc.addOr("name", SearchCriteria.Op.LIKE, "%" + keyword + "%"); + scc.addOr("displayText", SearchCriteria.Op.LIKE, "%" + keyword + "%"); + sc.addAnd("name", SearchCriteria.Op.SC, scc); + } + if (name != null) { sc.addAnd("name", SearchCriteria.Op.EQ, name); } diff --git a/server/src/main/java/com/cloud/api/query/dao/VolumeJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/VolumeJoinDaoImpl.java index d7e79ce9181..abd5eca3389 100644 --- a/server/src/main/java/com/cloud/api/query/dao/VolumeJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/VolumeJoinDaoImpl.java @@ -178,6 +178,7 @@ public class VolumeJoinDaoImpl extends GenericDaoBaseWithTagInformation getEntityType() { return Volume.class; } - } diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index 8f68af80366..e6f1eb018ce 100644 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -3280,10 +3280,9 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati DiskOfferingVO diskOffering = null; if (diskOfferingId == null) { - diskOffering = createDiskOfferingInternal(userId, isSystem, vmType, - name, cpu, ramSize, speed, displayText, typedProvisioningType, localStorageRequired, - offerHA, limitResourceUse, volatileVm, tags, domainIds, zoneIds, hostTag, - networkRate, deploymentPlanner, details, rootDiskSizeInGiB, isCustomizedIops, minIops, maxIops, + diskOffering = createDiskOfferingInternal( + name, displayText, typedProvisioningType, localStorageRequired, + tags, details, rootDiskSizeInGiB, isCustomizedIops, minIops, maxIops, bytesReadRate, bytesReadRateMax, bytesReadRateMaxLength, bytesWriteRate, bytesWriteRateMax, bytesWriteRateMaxLength, iopsReadRate, iopsReadRateMax, iopsReadRateMaxLength, @@ -3291,6 +3290,10 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati hypervisorSnapshotReserve, cacheMode, storagePolicyID, encryptRoot); } else { diskOffering = _diskOfferingDao.findById(diskOfferingId); + String diskStoragePolicyId = diskOfferingDetailsDao.getDetail(diskOfferingId, ApiConstants.STORAGE_POLICY); + if (storagePolicyID != null && diskStoragePolicyId != null) { + throw new InvalidParameterValueException("Storage policy cannot be defined on both compute and disk offering"); + } } if (diskOffering != null) { serviceOffering.setDiskOfferingId(diskOffering.getId()); @@ -3330,10 +3333,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati } } - private DiskOfferingVO createDiskOfferingInternal(final long userId, final boolean isSystem, final VirtualMachine.Type vmType, - final String name, final Integer cpu, final Integer ramSize, final Integer speed, final String displayText, final ProvisioningType typedProvisioningType, final boolean localStorageRequired, - final boolean offerHA, final boolean limitResourceUse, final boolean volatileVm, String tags, final List domainIds, List zoneIds, final String hostTag, - final Integer networkRate, final String deploymentPlanner, final Map details, Long rootDiskSizeInGiB, final Boolean isCustomizedIops, Long minIops, Long maxIops, + private DiskOfferingVO createDiskOfferingInternal(final String name, final String displayText, final ProvisioningType typedProvisioningType, final boolean localStorageRequired, + String tags, final Map details, Long rootDiskSizeInGiB, final Boolean isCustomizedIops, Long minIops, Long maxIops, Long bytesReadRate, Long bytesReadRateMax, Long bytesReadRateMaxLength, Long bytesWriteRate, Long bytesWriteRateMax, Long bytesWriteRateMaxLength, Long iopsReadRate, Long iopsReadRateMax, Long iopsReadRateMaxLength, @@ -3394,8 +3395,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati diskOffering.setHypervisorSnapshotReserve(hypervisorSnapshotReserve); if ((diskOffering = _diskOfferingDao.persist(diskOffering)) != null) { - if (details != null && !details.isEmpty()) { - List diskDetailsVO = new ArrayList(); + if ((details != null && !details.isEmpty()) || (storagePolicyID != null)) { + List diskDetailsVO = new ArrayList<>(); // Support disk offering details for below parameters if (details.containsKey(Volume.BANDWIDTH_LIMIT_IN_MBPS)) { diskDetailsVO.add(new DiskOfferingDetailVO(diskOffering.getId(), Volume.BANDWIDTH_LIMIT_IN_MBPS, details.get(Volume.BANDWIDTH_LIMIT_IN_MBPS), false)); @@ -3403,6 +3404,11 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati if (details.containsKey(Volume.IOPS_LIMIT)) { diskDetailsVO.add(new DiskOfferingDetailVO(diskOffering.getId(), Volume.IOPS_LIMIT, details.get(Volume.IOPS_LIMIT), false)); } + + if (storagePolicyID != null) { + diskDetailsVO.add(new DiskOfferingDetailVO(diskOffering.getId(), ApiConstants.STORAGE_POLICY, String.valueOf(storagePolicyID), false)); + } + if (!diskDetailsVO.isEmpty()) { diskOfferingDetailsDao.saveDetails(diskDetailsVO); } diff --git a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java index 1872f85a26f..7114bbbd90d 100644 --- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java +++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java @@ -1780,6 +1780,17 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis return result; } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_VPC_CREATE, eventDescription = "creating vpc", async = true) + public void startVpc(final CreateVPCCmd cmd) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { + if (!cmd.isStart()) { + logger.debug("Not starting VPC as " + ApiConstants.START + "=false was passed to the API"); + return; + } + startVpc(cmd.getEntityId(), true); + } + protected boolean startVpc(final Vpc vpc, final DeployDestination dest, final ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { // deploy provider diff --git a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java index 9a6f8563223..f3f0c5dc7e4 100644 --- a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java +++ b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java @@ -1921,6 +1921,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C @Override @DB + @ActionEvent(eventType = EventTypes.EVENT_MAINTENANCE_PREPARE_PRIMARY_STORAGE, + eventDescription = "preparing storage pool for maintenance", async = true) public PrimaryDataStoreInfo preparePrimaryStorageForMaintenance(Long primaryStorageId) throws ResourceUnavailableException, InsufficientCapacityException { StoragePoolVO primaryStorage = null; primaryStorage = _storagePoolDao.findById(primaryStorageId); @@ -1989,6 +1991,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C @Override @DB + @ActionEvent(eventType = EventTypes.EVENT_MAINTENANCE_CANCEL_PRIMARY_STORAGE, + eventDescription = "canceling maintenance for primary storage pool", async = true) public PrimaryDataStoreInfo cancelPrimaryStorageForMaintenance(CancelPrimaryStorageMaintenanceCmd cmd) throws ResourceUnavailableException { Long primaryStorageId = cmd.getId(); StoragePoolVO primaryStorage = null; @@ -2893,18 +2897,9 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C List> answers = new ArrayList>(); for (Pair volumeDiskProfilePair : volumes) { - String storagePolicyId = null; Volume volume = volumeDiskProfilePair.first(); DiskProfile diskProfile = volumeDiskProfilePair.second(); - if (volume.getVolumeType() == Type.ROOT) { - Long vmId = volume.getInstanceId(); - if (vmId != null) { - VMInstanceVO vm = _vmInstanceDao.findByIdIncludingRemoved(vmId); - storagePolicyId = _serviceOfferingDetailsDao.getDetail(vm.getServiceOfferingId(), ApiConstants.STORAGE_POLICY); - } - } else { - storagePolicyId = _diskOfferingDetailsDao.getDetail(diskProfile.getDiskOfferingId(), ApiConstants.STORAGE_POLICY); - } + String storagePolicyId = _diskOfferingDetailsDao.getDetail(diskProfile.getDiskOfferingId(), ApiConstants.STORAGE_POLICY); Answer answer = getCheckDatastorePolicyComplianceAnswer(storagePolicyId, pool); if (answer != null) { answers.add(new Pair<>(volume, answer)); diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java index ac6cdea7e0d..7dfc3737967 100644 --- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java +++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java @@ -157,6 +157,7 @@ import com.cloud.offering.DiskOffering; import com.cloud.org.Grouping; import com.cloud.projects.Project; import com.cloud.projects.ProjectManager; +import com.cloud.resource.ResourceManager; import com.cloud.resource.ResourceState; import com.cloud.serializer.GsonHelper; import com.cloud.server.ManagementService; @@ -256,6 +257,8 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic @Inject private ConfigurationManager _configMgr; @Inject + private ResourceManager _resourceMgr; + @Inject private VolumeDao _volsDao; @Inject private VolumeDetailsDao _volsDetailsDao; @@ -566,7 +569,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic _resourceLimitMgr.checkResourceLimit(_accountMgr.getAccount(ownerId), ResourceType.secondary_storage); } - sanitizeFormat(format); + checkFormatWithSupportedHypervisorsInZone(format, zoneId); // Check that the disk offering specified is valid if (diskOfferingId != null) { @@ -582,6 +585,15 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic return false; } + private void checkFormatWithSupportedHypervisorsInZone(String format, Long zoneId) { + ImageFormat imageformat = ImageFormat.valueOf(format); + final List supportedHypervisorTypesInZone = _resourceMgr.getSupportedHypervisorTypes(zoneId, false, null); + final HypervisorType hypervisorTypeFromFormat = ApiDBUtils.getHypervisorTypeFromFormat(zoneId, imageformat); + if (!(supportedHypervisorTypesInZone.contains(hypervisorTypeFromFormat))) { + throw new InvalidParameterValueException(String.format("The %s hypervisor supported for %s file format, is not found on the zone", hypervisorTypeFromFormat.toString(), format)); + } + } + public String getRandomVolumeName() { return UUID.randomUUID().toString(); } diff --git a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java index 4aeaaf371e2..72e9d85e25a 100644 --- a/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/main/java/com/cloud/vm/UserVmManagerImpl.java @@ -8096,7 +8096,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Vir } if (needRestart) { try { - if (vm.getDetail(VmDetailConstants.PASSWORD) != null) { + if (Objects.nonNull(password)) { params = new HashMap<>(); params.put(VirtualMachineProfile.Param.VmPassword, password); } diff --git a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java index f2b552c7c07..2a2427c9795 100644 --- a/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/vm/UnmanagedVMsManagerImpl.java @@ -2079,10 +2079,10 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { throw new InvalidParameterValueException("Username need to be provided."); } - HashMap instancesMap = getRemoteVms(zoneId, remoteUrl, cmd.getUsername(), cmd.getPassword()); + HashMap instancesMap = getRemoteVmsOnKVMHost(zoneId, remoteUrl, cmd.getUsername(), cmd.getPassword()); unmanagedInstanceTO = instancesMap.get(cmd.getName()); if (unmanagedInstanceTO == null) { - throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("Vm with name: %s not found on remote host", instanceName)); + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, String.format("VM with name: %s not found on remote host %s", instanceName, remoteUrl)); } } @@ -2493,7 +2493,7 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { } List responses = new ArrayList<>(); - HashMap vmMap = getRemoteVms(zoneId, cmd.getHost(), cmd.getUsername(), cmd.getPassword()); + HashMap vmMap = getRemoteVmsOnKVMHost(zoneId, cmd.getHost(), cmd.getUsername(), cmd.getPassword()); for (String key : vmMap.keySet()) { UnmanagedInstanceTO instance = vmMap.get(key); if (StringUtils.isNotEmpty(keyword) && @@ -2508,17 +2508,17 @@ public class UnmanagedVMsManagerImpl implements UnmanagedVMsManager { return listResponses; } - private HashMap getRemoteVms(long zoneId, String remoteUrl, String username, String password) { + private HashMap getRemoteVmsOnKVMHost(long zoneId, String remoteHostUrl, String username, String password) { //ToDo: add option to list one Vm by name List hosts = resourceManager.listAllUpAndEnabledHostsInOneZoneByHypervisor(Hypervisor.HypervisorType.KVM, zoneId); if(hosts.size() < 1) { - throw new CloudRuntimeException("No hosts available for Vm Import"); + throw new CloudRuntimeException("No hosts available for VM import"); } HostVO host = hosts.get(0); - GetRemoteVmsCommand getRemoteVmsCommand = new GetRemoteVmsCommand(remoteUrl, username, password); + GetRemoteVmsCommand getRemoteVmsCommand = new GetRemoteVmsCommand(remoteHostUrl, username, password); Answer answer = agentManager.easySend(host.getId(), getRemoteVmsCommand); if (!(answer instanceof GetRemoteVmsAnswer)) { - throw new CloudRuntimeException("Error while listing remote Vms"); + throw new CloudRuntimeException("Failed to list VMs, due to: " + answer.getDetails()); } GetRemoteVmsAnswer getRemoteVmsAnswer = (GetRemoteVmsAnswer) answer; return getRemoteVmsAnswer.getUnmanagedInstances(); diff --git a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java index 9cbd8f8de9f..2cc61dae133 100644 --- a/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java +++ b/services/secondary-storage/server/src/main/java/org/apache/cloudstack/storage/resource/HttpUploadServerHandler.java @@ -296,7 +296,8 @@ public class HttpUploadServerHandler extends SimpleChannelInboundHandler - + - + + + +