diff --git a/agent/bindir/libvirtqemuhook.in b/agent/bindir/libvirtqemuhook.in
index cf3d36410b8..e17944d8353 100755
--- a/agent/bindir/libvirtqemuhook.in
+++ b/agent/bindir/libvirtqemuhook.in
@@ -61,21 +61,23 @@ def handleMigrateBegin():
try:
domain = parse(sys.stdin)
for interface in domain.getElementsByTagName("interface"):
- source = interface.getElementsByTagName("source")[0]
- bridge = source.getAttribute("bridge")
- if isOldStyleBridge(bridge):
- vlanId = bridge.replace("cloudVirBr", "")
- phyDev = getGuestNetworkDevice()
- elif isNewStyleBridge(bridge):
- vlanId = re.sub(r"br(\w+)-", "", bridge)
- phyDev = re.sub(r"-(\d+)$", "" , re.sub(r"^br", "" ,bridge))
- netlib = networkConfig()
- if not netlib.isNetworkDev(phyDev):
+ sources = interface.getElementsByTagName("source")
+ if sources.length > 0:
+ source = interface.getElementsByTagName("source")[0]
+ bridge = source.getAttribute("bridge")
+ if isOldStyleBridge(bridge):
+ vlanId = bridge.replace("cloudVirBr", "")
phyDev = getGuestNetworkDevice()
- else:
- continue
- newBrName = "br" + phyDev + "-" + vlanId
- source.setAttribute("bridge", newBrName)
+ elif isNewStyleBridge(bridge):
+ vlanId = re.sub(r"br(\w+)-", "", bridge)
+ phyDev = re.sub(r"-(\d+)$", "" , re.sub(r"^br", "" ,bridge))
+ netlib = networkConfig()
+ if not netlib.isNetworkDev(phyDev):
+ phyDev = getGuestNetworkDevice()
+ else:
+ continue
+ newBrName = "br" + phyDev + "-" + vlanId
+ source.setAttribute("bridge", newBrName)
print(domain.toxml())
except:
pass
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/annotation/AddAnnotationCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/annotation/AddAnnotationCmd.java
index 74588337ee2..c2ded921c40 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/admin/annotation/AddAnnotationCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/annotation/AddAnnotationCmd.java
@@ -41,7 +41,7 @@ public class AddAnnotationCmd extends BaseCmd {
@Parameter(name = ApiConstants.ANNOTATION, type = CommandType.STRING, description = "the annotation text")
private String annotation;
- @Parameter(name = ApiConstants.ENTITY_TYPE, type = CommandType.STRING, description = "the entity type (only HOST is allowed atm)")
+ @Parameter(name = ApiConstants.ENTITY_TYPE, type = CommandType.STRING, description = "The following entity types are allowed VM, VOLUME, SNAPSHOT, VM_SNAPSHOT, INSTANCE_GROUP, SSH_KEYPAIR, USER_DATA, NETWORK, VPC, PUBLIC_IP_ADDRESS, VPN_CUSTOMER_GATEWAY, TEMPLATE, ISO, KUBERNETES_CLUSTER, SERVICE_OFFERING, DISK_OFFERING, NETWORK_OFFERING, ZONE, POD, CLUSTER, HOST, DOMAIN, PRIMARY_STORAGE, SECONDARY_STORAGE, VR, SYSTEM_VM, AUTOSCALE_VM_GROUP, MANAGEMENT_SERVER")
private String entityType;
@Parameter(name = ApiConstants.ENTITY_ID, type = CommandType.STRING, description = "the id of the entity to annotate")
diff --git a/core/src/main/java/com/cloud/agent/api/MigrateCommand.java b/core/src/main/java/com/cloud/agent/api/MigrateCommand.java
index a6ab45973e2..27251f4bb78 100644
--- a/core/src/main/java/com/cloud/agent/api/MigrateCommand.java
+++ b/core/src/main/java/com/cloud/agent/api/MigrateCommand.java
@@ -171,6 +171,7 @@ public class MigrateCommand extends Command {
private final DriverType driverType;
private final Source source;
private final String sourceText;
+ private final String backingStoreText;
private boolean isSourceDiskOnStorageFileSystem;
public MigrateDiskInfo(final String serialNumber, final DiskType diskType, final DriverType driverType, final Source source, final String sourceText) {
@@ -179,6 +180,16 @@ public class MigrateCommand extends Command {
this.driverType = driverType;
this.source = source;
this.sourceText = sourceText;
+ this.backingStoreText = null;
+ }
+
+ public MigrateDiskInfo(final String serialNumber, final DiskType diskType, final DriverType driverType, final Source source, final String sourceText, final String backingStoreText) {
+ this.serialNumber = serialNumber;
+ this.diskType = diskType;
+ this.driverType = driverType;
+ this.source = source;
+ this.sourceText = sourceText;
+ this.backingStoreText = backingStoreText;
}
public String getSerialNumber() {
@@ -201,6 +212,8 @@ public class MigrateCommand extends Command {
return sourceText;
}
+ public String getBackingStoreText() { return backingStoreText; }
+
public boolean isSourceDiskOnStorageFileSystem() {
return isSourceDiskOnStorageFileSystem;
}
diff --git a/core/src/main/java/org/apache/cloudstack/storage/to/TemplateObjectTO.java b/core/src/main/java/org/apache/cloudstack/storage/to/TemplateObjectTO.java
index b184a74312b..a405785bf64 100644
--- a/core/src/main/java/org/apache/cloudstack/storage/to/TemplateObjectTO.java
+++ b/core/src/main/java/org/apache/cloudstack/storage/to/TemplateObjectTO.java
@@ -86,6 +86,7 @@ public class TemplateObjectTO implements DataTO {
this.hypervisorType = template.getHypervisorType();
this.deployAsIs = template.isDeployAsIs();
this.deployAsIsConfiguration = template.getDeployAsIsConfiguration();
+ this.directDownload = template.isDirectDownload();
}
@Override
diff --git a/engine/schema/pom.xml b/engine/schema/pom.xml
index a5a7b8febd4..21066ff3c8f 100644
--- a/engine/schema/pom.xml
+++ b/engine/schema/pom.xml
@@ -57,12 +57,6 @@
ini4j
${cs.ini.version}
-
- org.junit.jupiter
- junit-jupiter
- ${cs.junit.jupiter.version}
- test
-
diff --git a/engine/schema/src/test/java/com/cloud/upgrade/DatabaseVersionHierarchyTest.java b/engine/schema/src/test/java/com/cloud/upgrade/DatabaseVersionHierarchyTest.java
index 4825f15a933..2b0dda5fa57 100644
--- a/engine/schema/src/test/java/com/cloud/upgrade/DatabaseVersionHierarchyTest.java
+++ b/engine/schema/src/test/java/com/cloud/upgrade/DatabaseVersionHierarchyTest.java
@@ -26,15 +26,15 @@ import com.cloud.upgrade.dao.Upgrade41520to41600;
import com.cloud.upgrade.dao.Upgrade41720to41800;
import com.cloud.upgrade.dao.Upgrade481to490;
import org.apache.cloudstack.utils.CloudStackVersion;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
+import org.junit.BeforeClass;
+import org.junit.Test;
import java.io.InputStream;
import java.sql.Connection;
-import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.Assert.assertEquals;
-class DatabaseVersionHierarchyTest {
+public class DatabaseVersionHierarchyTest {
private static DatabaseVersionHierarchy hierarchy;
@@ -71,8 +71,8 @@ class DatabaseVersionHierarchyTest {
}
- @BeforeAll
- static void init() {
+ @BeforeClass
+ public static void init() {
DatabaseVersionHierarchy.DatabaseVersionHierarchyBuilder builder = DatabaseVersionHierarchy.builder()
.next("0.0.5", new DummyUpgrade())
.next("1.0.0.0", new DummyUpgrade())
@@ -95,23 +95,23 @@ class DatabaseVersionHierarchyTest {
}
@Test
- void getRecentVersionMiddle() {
+ public void getRecentVersionMiddle() {
assertEquals("2.0.0", hierarchy.getRecentVersion(CloudStackVersion.parse("2.2.2")).toString());
}
@Test
- void getRecentVersionEarly() {
+ public void getRecentVersionEarly() {
assertEquals(null, hierarchy.getRecentVersion(CloudStackVersion.parse("0.0.2")));
}
@Test
- void getRecentVersionStart() {
+ public void getRecentVersionStart() {
assertEquals(null, hierarchy.getRecentVersion(CloudStackVersion.parse("0.0.5")));
}
@Test
- void getRecentVersionJust() {
+ public void getRecentVersionJust() {
assertEquals("0.0.5", hierarchy.getRecentVersion(CloudStackVersion.parse("0.0.9")).toString());
}
@Test
- void getRecentVersionExact() {
+ public void getRecentVersionExact() {
assertEquals("0.0.5", hierarchy.getRecentVersion(CloudStackVersion.parse("1.0.0.0")).toString());
}
}
diff --git a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/KvmNonManagedStorageDataMotionStrategy.java b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/KvmNonManagedStorageDataMotionStrategy.java
index 3e166ee2b4c..f2ccce75690 100644
--- a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/KvmNonManagedStorageDataMotionStrategy.java
+++ b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/KvmNonManagedStorageDataMotionStrategy.java
@@ -149,9 +149,9 @@ public class KvmNonManagedStorageDataMotionStrategy extends StorageSystemDataMot
* Configures a {@link MigrateDiskInfo} object configured for migrating a File System volume and calls rootImageProvisioning.
*/
@Override
- protected MigrateCommand.MigrateDiskInfo configureMigrateDiskInfo(VolumeInfo srcVolumeInfo, String destPath) {
- return new MigrateCommand.MigrateDiskInfo(srcVolumeInfo.getPath(), MigrateCommand.MigrateDiskInfo.DiskType.FILE, MigrateCommand.MigrateDiskInfo.DriverType.QCOW2,
- MigrateCommand.MigrateDiskInfo.Source.FILE, destPath);
+ protected MigrateCommand.MigrateDiskInfo configureMigrateDiskInfo(VolumeInfo srcVolumeInfo, String destPath, String backingPath) {
+ return new MigrateCommand.MigrateDiskInfo(srcVolumeInfo.getPath(), MigrateCommand.MigrateDiskInfo.DiskType.FILE, MigrateCommand.MigrateDiskInfo.DriverType.QCOW2,
+ MigrateCommand.MigrateDiskInfo.Source.FILE, destPath, backingPath);
}
/**
@@ -163,6 +163,15 @@ public class KvmNonManagedStorageDataMotionStrategy extends StorageSystemDataMot
return new File(destStoragePool.getPath(), destVolumeInfo.getUuid()).getAbsolutePath();
}
+ @Override
+ protected String generateBackingPath(StoragePoolVO destStoragePool, VolumeInfo destVolumeInfo) {
+ String templateInstallPath = getVolumeBackingFile(destVolumeInfo);
+ if (templateInstallPath == null) {
+ return null;
+ }
+ return new File(destStoragePool.getPath(), templateInstallPath).getAbsolutePath();
+ }
+
/**
* Returns the template UUID with the given id. If the template ID is null, it returns null.
*/
@@ -201,6 +210,12 @@ public class KvmNonManagedStorageDataMotionStrategy extends StorageSystemDataMot
return;
}
+ TemplateInfo directDownloadTemplateInfo = templateDataFactory.getReadyBypassedTemplateOnPrimaryStore(srcVolumeInfo.getTemplateId(), destDataStore.getId(), destHost.getId());
+ if (directDownloadTemplateInfo != null) {
+ LOGGER.debug(String.format("Template %s was of direct download type and successfully staged to primary store %s", directDownloadTemplateInfo.getId(), directDownloadTemplateInfo.getDataStore().getId()));
+ return;
+ }
+
VMTemplateStoragePoolVO sourceVolumeTemplateStoragePoolVO = vmTemplatePoolDao.findByPoolTemplate(destStoragePool.getId(), srcVolumeInfo.getTemplateId(), null);
if (sourceVolumeTemplateStoragePoolVO == null && (isStoragePoolTypeInList(destStoragePool.getPoolType(), StoragePoolType.Filesystem, StoragePoolType.SharedMountPoint))) {
DataStore sourceTemplateDataStore = dataStoreManagerImpl.getRandomImageStore(srcVolumeInfo.getDataCenterId());
diff --git a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java
index 64792a61018..1419ae36d25 100644
--- a/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java
+++ b/engine/storage/datamotion/src/main/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategy.java
@@ -1871,7 +1871,8 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
MigrateCommand.MigrateDiskInfo.Source.FILE,
connectHostToVolume(destHost, destVolumeInfo.getPoolId(), volumeIdentifier));
} else {
- migrateDiskInfo = configureMigrateDiskInfo(srcVolumeInfo, destPath);
+ String backingPath = generateBackingPath(destStoragePool, destVolumeInfo);
+ migrateDiskInfo = configureMigrateDiskInfo(srcVolumeInfo, destPath, backingPath);
migrateDiskInfo.setSourceDiskOnStorageFileSystem(isStoragePoolTypeOfFile(sourceStoragePool));
migrateDiskInfoList.add(migrateDiskInfo);
prepareDiskWithSecretConsumerDetail(vmTO, srcVolumeInfo, destVolumeInfo.getPath());
@@ -1994,14 +1995,18 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
return connectHostToVolume(destHost, destVolumeInfo.getPoolId(), destVolumeInfo.get_iScsiName());
}
+ protected String generateBackingPath(StoragePoolVO destStoragePool, VolumeInfo destVolumeInfo) {
+ return null;
+ }
+
/**
* Configures a {@link MigrateDiskInfo} object with disk type of BLOCK, Driver type RAW and Source DEV
*/
- protected MigrateCommand.MigrateDiskInfo configureMigrateDiskInfo(VolumeInfo srcVolumeInfo, String destPath) {
+ protected MigrateCommand.MigrateDiskInfo configureMigrateDiskInfo(VolumeInfo srcVolumeInfo, String destPath, String backingPath) {
return new MigrateCommand.MigrateDiskInfo(srcVolumeInfo.getPath(),
MigrateCommand.MigrateDiskInfo.DiskType.BLOCK,
MigrateCommand.MigrateDiskInfo.DriverType.RAW,
- MigrateCommand.MigrateDiskInfo.Source.DEV, destPath);
+ MigrateCommand.MigrateDiskInfo.Source.DEV, destPath, backingPath);
}
/**
@@ -2023,7 +2028,7 @@ public class StorageSystemDataMotionStrategy implements DataMotionStrategy {
/*
* Return backing file for volume (if any), only for KVM volumes
*/
- private String getVolumeBackingFile(VolumeInfo srcVolumeInfo) {
+ String getVolumeBackingFile(VolumeInfo srcVolumeInfo) {
if (srcVolumeInfo.getHypervisorType() == HypervisorType.KVM &&
srcVolumeInfo.getTemplateId() != null && srcVolumeInfo.getPoolId() != null) {
VMTemplateVO template = _vmTemplateDao.findById(srcVolumeInfo.getTemplateId());
diff --git a/engine/storage/datamotion/src/test/java/org/apache/cloudstack/storage/motion/KvmNonManagedStorageSystemDataMotionTest.java b/engine/storage/datamotion/src/test/java/org/apache/cloudstack/storage/motion/KvmNonManagedStorageSystemDataMotionTest.java
index 07a6a1c0c1b..8f1ada87458 100644
--- a/engine/storage/datamotion/src/test/java/org/apache/cloudstack/storage/motion/KvmNonManagedStorageSystemDataMotionTest.java
+++ b/engine/storage/datamotion/src/test/java/org/apache/cloudstack/storage/motion/KvmNonManagedStorageSystemDataMotionTest.java
@@ -240,7 +240,7 @@ public class KvmNonManagedStorageSystemDataMotionTest {
public void configureMigrateDiskInfoTest() {
VolumeObject srcVolumeInfo = Mockito.spy(new VolumeObject());
Mockito.doReturn("volume path").when(srcVolumeInfo).getPath();
- MigrateCommand.MigrateDiskInfo migrateDiskInfo = kvmNonManagedStorageDataMotionStrategy.configureMigrateDiskInfo(srcVolumeInfo, "destPath");
+ MigrateCommand.MigrateDiskInfo migrateDiskInfo = kvmNonManagedStorageDataMotionStrategy.configureMigrateDiskInfo(srcVolumeInfo, "destPath", null);
Assert.assertEquals(MigrateCommand.MigrateDiskInfo.DiskType.FILE, migrateDiskInfo.getDiskType());
Assert.assertEquals(MigrateCommand.MigrateDiskInfo.DriverType.QCOW2, migrateDiskInfo.getDriverType());
Assert.assertEquals(MigrateCommand.MigrateDiskInfo.Source.FILE, migrateDiskInfo.getSource());
@@ -248,6 +248,19 @@ public class KvmNonManagedStorageSystemDataMotionTest {
Assert.assertEquals("volume path", migrateDiskInfo.getSerialNumber());
}
+ @Test
+ public void configureMigrateDiskInfoWithBackingTest() {
+ VolumeObject srcVolumeInfo = Mockito.spy(new VolumeObject());
+ Mockito.doReturn("volume path").when(srcVolumeInfo).getPath();
+ MigrateCommand.MigrateDiskInfo migrateDiskInfo = kvmNonManagedStorageDataMotionStrategy.configureMigrateDiskInfo(srcVolumeInfo, "destPath", "backingPath");
+ Assert.assertEquals(MigrateCommand.MigrateDiskInfo.DiskType.FILE, migrateDiskInfo.getDiskType());
+ Assert.assertEquals(MigrateCommand.MigrateDiskInfo.DriverType.QCOW2, migrateDiskInfo.getDriverType());
+ Assert.assertEquals(MigrateCommand.MigrateDiskInfo.Source.FILE, migrateDiskInfo.getSource());
+ Assert.assertEquals("destPath", migrateDiskInfo.getSourceText());
+ Assert.assertEquals("volume path", migrateDiskInfo.getSerialNumber());
+ Assert.assertEquals("backingPath", migrateDiskInfo.getBackingStoreText());
+ }
+
@Test
public void shouldMigrateVolumeTest() {
StoragePoolVO sourceStoragePool = Mockito.spy(new StoragePoolVO());
diff --git a/engine/storage/datamotion/src/test/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategyTest.java b/engine/storage/datamotion/src/test/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategyTest.java
index f209fc07636..ea1a221c8c0 100644
--- a/engine/storage/datamotion/src/test/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategyTest.java
+++ b/engine/storage/datamotion/src/test/java/org/apache/cloudstack/storage/motion/StorageSystemDataMotionStrategyTest.java
@@ -192,7 +192,7 @@ public class StorageSystemDataMotionStrategyTest {
public void configureMigrateDiskInfoTest() {
VolumeObject srcVolumeInfo = Mockito.spy(new VolumeObject());
Mockito.doReturn("volume path").when(srcVolumeInfo).getPath();
- MigrateCommand.MigrateDiskInfo migrateDiskInfo = strategy.configureMigrateDiskInfo(srcVolumeInfo, "destPath");
+ MigrateCommand.MigrateDiskInfo migrateDiskInfo = strategy.configureMigrateDiskInfo(srcVolumeInfo, "destPath", null);
Assert.assertEquals(MigrateCommand.MigrateDiskInfo.DiskType.BLOCK, migrateDiskInfo.getDiskType());
Assert.assertEquals(MigrateCommand.MigrateDiskInfo.DriverType.RAW, migrateDiskInfo.getDriverType());
Assert.assertEquals(MigrateCommand.MigrateDiskInfo.Source.DEV, migrateDiskInfo.getSource());
@@ -200,6 +200,19 @@ public class StorageSystemDataMotionStrategyTest {
Assert.assertEquals("volume path", migrateDiskInfo.getSerialNumber());
}
+ @Test
+ public void configureMigrateDiskInfoWithBackingTest() {
+ VolumeObject srcVolumeInfo = Mockito.spy(new VolumeObject());
+ Mockito.doReturn("volume path").when(srcVolumeInfo).getPath();
+ MigrateCommand.MigrateDiskInfo migrateDiskInfo = strategy.configureMigrateDiskInfo(srcVolumeInfo, "destPath", "backingPath");
+ Assert.assertEquals(MigrateCommand.MigrateDiskInfo.DiskType.BLOCK, migrateDiskInfo.getDiskType());
+ Assert.assertEquals(MigrateCommand.MigrateDiskInfo.DriverType.RAW, migrateDiskInfo.getDriverType());
+ Assert.assertEquals(MigrateCommand.MigrateDiskInfo.Source.DEV, migrateDiskInfo.getSource());
+ Assert.assertEquals("destPath", migrateDiskInfo.getSourceText());
+ Assert.assertEquals("volume path", migrateDiskInfo.getSerialNumber());
+ Assert.assertEquals("backingPath", migrateDiskInfo.getBackingStoreText());
+ }
+
@Test
public void setVolumePathTest() {
VolumeVO volume = new VolumeVO("name", 0l, 0l, 0l, 0l, 0l, "folder", "path", Storage.ProvisioningType.THIN, 0l, Volume.Type.ROOT);
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 221285a762d..d0ab77829af 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
@@ -575,6 +575,16 @@ public final class LibvirtMigrateCommandWrapper extends CommandWrapper mapMigrateStorage = new HashMap();
+ final String xmlDesc =
+ "" +
+ " " +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " bf8621b3027c497d963b\n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " \n" +
+ " " +
+ "";
+
+ final String volumeFile = "3530f749-82fd-458e-9485-a357e6e541db";
+ final String backingFile = "0bc745b6-f3d7-44a9-ad8e-68904b77e2ab";
+ String newDiskPath = "/mnt/2d0435e1-99e0-4f1d-94c0-bee1f6f8b99e/" + volumeFile;
+ String newBackingStorePath = "/mnt/2d0435e1-99e0-4f1d-94c0-bee1f6f8b99e/" + backingFile;
+ MigrateDiskInfo diskInfo = new MigrateDiskInfo("123456", DiskType.BLOCK, DriverType.RAW, Source.FILE, newDiskPath, newBackingStorePath);
+ mapMigrateStorage.put("/mnt/07eb495b-5590-3877-9fb7-23c6e9a40d40/bf8621b3-027c-497d-963b-06319650f048", diskInfo);
+
+ final String result = libvirtMigrateCmdWrapper.replaceStorage(xmlDesc, mapMigrateStorage, false);
+ InputStream in = IOUtils.toInputStream(result);
+ DocumentBuilderFactory docFactory = DocumentBuilderFactory.newInstance();
+ DocumentBuilder docBuilder = docFactory.newDocumentBuilder();
+ Document doc = docBuilder.parse(in);
+ assertXpath(doc, "/domain/devices/disk/backingStore/source/@file", newBackingStorePath);
+ assertXpath(doc, "/domain/devices/disk/source/@file", newDiskPath);
+ assertXpath(doc, "/domain/devices/disk/serial", "bf8621b3027c497d963b");
+
+ final String expectedSecretUuid = LibvirtComputingResource.generateSecretUUIDFromString(volumeFile);
+ assertXpath(doc, "/domain/devices/disk/encryption/secret/@uuid", expectedSecretUuid);
+ }
+
public void testReplaceStorageXmlDiskNotManagedStorage() throws ParserConfigurationException, TransformerException, SAXException, IOException {
final LibvirtMigrateCommandWrapper lw = new LibvirtMigrateCommandWrapper();
String destDisk1FileName = "XXXXXXXXXXXXXX";
diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
index c5a489ba832..9255f9275e9 100644
--- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -602,6 +602,32 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
});
}
+ protected void validateIpAddressRelatedConfigValues(final String configName, final String value) {
+ if (!configName.endsWith(".ip") && !configName.endsWith(".ipaddress") && !configName.endsWith(".iprange")) {
+ return;
+ }
+ if (StringUtils.isEmpty(value)) {
+ return;
+ }
+ final ConfigKey> configKey = _configDepot.get(configName);
+ if (configKey == null || !String.class.equals(configKey.type())) {
+ return;
+ }
+ boolean err = (configName.endsWith(".ip") || configName.endsWith(".ipaddress")) && !NetUtils.isValidIp4(value);
+ if (configName.endsWith(".iprange")) {
+ err = true;
+ if (value.contains("-")) {
+ String[] ips = value.split("-");
+ if (ips.length == 2 && NetUtils.isValidIp4(ips[0]) && NetUtils.isValidIp4(ips[1])) {
+ err = false;
+ }
+ }
+ }
+ if (err) {
+ throw new InvalidParameterValueException("Invalid IP address value(s) specified for the config value");
+ }
+ }
+
@Override
public boolean start() {
@@ -874,6 +900,8 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati
catergory = config.getCategory();
}
+ validateIpAddressRelatedConfigValues(name, value);
+
if (value == null) {
return _configDao.findByName(name);
}
diff --git a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
index e608c593365..2f88b5f44fc 100644
--- a/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
+++ b/server/src/main/java/com/cloud/storage/VolumeApiServiceImpl.java
@@ -4260,7 +4260,7 @@ public class VolumeApiServiceImpl extends ManagerBase implements VolumeApiServic
_volsDao.update(volumeToAttach.getId(), volumeToAttach);
}
- if (host != null && volumeToAttachStoragePool.getPoolType() == Storage.StoragePoolType.PowerFlex) {
+ if (host != null && volumeToAttachStoragePool != null && volumeToAttachStoragePool.getPoolType() == Storage.StoragePoolType.PowerFlex) {
// Unmap the volume on PowerFlex/ScaleIO pool for stopped VM
volService.revokeAccess(volFactory.getVolume(volumeToAttach.getId()), host, dataStore);
}
diff --git a/server/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java b/server/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java
index 49b87d27949..17cb96931ec 100644
--- a/server/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java
+++ b/server/src/main/java/org/apache/cloudstack/direct/download/DirectDownloadManagerImpl.java
@@ -742,7 +742,7 @@ public class DirectDownloadManagerImpl extends ManagerBase implements DirectDown
executorService.scheduleWithFixedDelay(
new DirectDownloadCertificateUploadBackgroundTask(this, hostDao, dataCenterDao,
directDownloadCertificateDao, directDownloadCertificateHostMapDao),
- 60L, DirectDownloadCertificateUploadInterval.value(), TimeUnit.HOURS);
+ 1L, DirectDownloadCertificateUploadInterval.value(), TimeUnit.HOURS);
}
return true;
}
diff --git a/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java b/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java
index e8bb8fae0b9..47dfa4b79b0 100644
--- a/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java
+++ b/server/src/test/java/com/cloud/configuration/ConfigurationManagerImplTest.java
@@ -16,22 +16,37 @@
// under the License.
package com.cloud.configuration;
-import com.cloud.utils.net.NetUtils;
+import java.util.List;
+
+import org.apache.cloudstack.framework.config.ConfigDepot;
+import org.apache.cloudstack.framework.config.ConfigKey;
import org.junit.Assert;
+import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
-import java.util.List;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.storage.StorageManager;
+import com.cloud.utils.net.NetUtils;
@RunWith(PowerMockRunner.class)
@PrepareForTest(NetUtils.class)
public class ConfigurationManagerImplTest {
+ @Mock
+ ConfigDepot configDepot;
ConfigurationManagerImpl configurationManagerImplSpy = Mockito.spy(new ConfigurationManagerImpl());
+
+ @Before
+ public void setUp() throws Exception {
+ configurationManagerImplSpy._configDepot = configDepot;
+ }
+
@Test
public void validateIfIntValueIsInRangeTestValidValueReturnNull() {
String testVariable = configurationManagerImplSpy.validateIfIntValueIsInRange("String name", "3", "1-5");
@@ -191,4 +206,50 @@ public class ConfigurationManagerImplTest {
String testVariable = configurationManagerImplSpy.validateRangeOther("NameTest1", "ThisShouldNotWork", "ThisShouldWork,ThisShouldAlsoWork,SoShouldThis");
Assert.assertNotNull(testVariable);
}
+
+ @Test
+ public void testValidateIpAddressRelatedConfigValuesUnrelated() {
+ configurationManagerImplSpy.validateIpAddressRelatedConfigValues(StorageManager.PreferredStoragePool.key(), "something");
+ configurationManagerImplSpy.validateIpAddressRelatedConfigValues("config.ip", "");
+ Mockito.when(configurationManagerImplSpy._configDepot.get("config.ip")).thenReturn(null);
+ configurationManagerImplSpy.validateIpAddressRelatedConfigValues("config.ip", "something");
+ ConfigKey> key = StorageManager.MountDisabledStoragePool;
+ Mockito.doReturn(key).when(configurationManagerImplSpy._configDepot).get(StorageManager.MountDisabledStoragePool.key());
+ configurationManagerImplSpy.validateIpAddressRelatedConfigValues(StorageManager.MountDisabledStoragePool.key(), "false");
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testValidateIpAddressRelatedConfigValuesInvalidIp() {
+ ConfigKey key = StorageManager.PreferredStoragePool; // Any ConfigKey of String type
+ Mockito.doReturn(key).when(configurationManagerImplSpy._configDepot).get("config.ip");
+ configurationManagerImplSpy.validateIpAddressRelatedConfigValues("config.ip", "abcdefg");
+ }
+
+ @Test
+ public void testValidateIpAddressRelatedConfigValuesValidIp() {
+ ConfigKey key = StorageManager.PreferredStoragePool; // Any ConfigKey of String type
+ Mockito.doReturn(key).when(configurationManagerImplSpy._configDepot).get("config.ip");
+ configurationManagerImplSpy.validateIpAddressRelatedConfigValues("config.ip", "192.168.1.1");
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testValidateIpAddressRelatedConfigValuesInvalidIpRange() {
+ ConfigKey key = StorageManager.PreferredStoragePool; // Any ConfigKey of String type. RemoteAccessVpnManagerImpl.RemoteAccessVpnClientIpRange not accessible here
+ Mockito.doReturn(key).when(configurationManagerImplSpy._configDepot).get("config.iprange");
+ configurationManagerImplSpy.validateIpAddressRelatedConfigValues("config.iprange", "xyz-192.168.1.20");
+ }
+
+ @Test(expected = InvalidParameterValueException.class)
+ public void testValidateIpAddressRelatedConfigValuesInvalidIpRange1() {
+ ConfigKey key = StorageManager.PreferredStoragePool; // Any ConfigKey of String type. RemoteAccessVpnManagerImpl.RemoteAccessVpnClientIpRange not accessible here
+ Mockito.doReturn(key).when(configurationManagerImplSpy._configDepot).get("config.iprange");
+ configurationManagerImplSpy.validateIpAddressRelatedConfigValues("config.iprange", "192.168.1.20");
+ }
+
+ @Test
+ public void testValidateIpAddressRelatedConfigValuesValidIpRange() {
+ ConfigKey key = StorageManager.PreferredStoragePool; // Any ConfigKey of String type. RemoteAccessVpnManagerImpl.RemoteAccessVpnClientIpRange not accessible here
+ Mockito.doReturn(key).when(configurationManagerImplSpy._configDepot).get("config.iprange");
+ configurationManagerImplSpy.validateIpAddressRelatedConfigValues("config.iprange", "192.168.1.1-192.168.1.100");
+ }
}
diff --git a/systemvm/agent/noVNC/core/rfb.js b/systemvm/agent/noVNC/core/rfb.js
index f92255808e3..b795aaa7525 100644
--- a/systemvm/agent/noVNC/core/rfb.js
+++ b/systemvm/agent/noVNC/core/rfb.js
@@ -433,21 +433,30 @@ export default class RFB extends EventTargetMixin {
this._resumeAuthentication();
}
- sendText(text) {
- for (var i = 0; i < text.length; i++) {
- const character = text.charAt(i);
- var charCode = USKeyTable[character] || false;
- if (charCode) {
- this.sendKey(charCode, character, true);
- this.sendKey(charCode, character, false);
- } else {
- charCode = text.charCodeAt(i)
- this.sendKey(KeyTable.XK_Shift_L, "ShiftLeft", true);
- this.sendKey(charCode, character, true);
- this.sendKey(charCode, character, false);
- this.sendKey(KeyTable.XK_Shift_L, "ShiftLeft", false);
+ sendText(text) {
+ const sleep = (time) => {
+ return new Promise(resolve => setTimeout(resolve, time))
+ }
+
+ const keyboardTypeText = async () => {
+ for (var i = 0; i < text.length; i++) {
+ const character = text.charAt(i);
+ var charCode = USKeyTable[character] || false;
+ if (charCode) {
+ this.sendKey(charCode, character, true);
+ this.sendKey(charCode, character, false);
+ } else {
+ charCode = text.charCodeAt(i)
+ this.sendKey(KeyTable.XK_Shift_L, "ShiftLeft", true);
+ this.sendKey(charCode, character, true);
+ this.sendKey(charCode, character, false);
+ this.sendKey(KeyTable.XK_Shift_L, "ShiftLeft", false);
+ }
+ await sleep(25)
}
}
+
+ keyboardTypeText()
}
sendCtrlAltDel() {
diff --git a/test/integration/component/test_configdrive.py b/test/integration/component/test_configdrive.py
index b8ce4bdde5b..38e753480db 100644
--- a/test/integration/component/test_configdrive.py
+++ b/test/integration/component/test_configdrive.py
@@ -1025,7 +1025,7 @@ class ConfigDriveUtils:
:rtype: str
"""
self.debug("Updating userdata for VM - %s" % vm.name)
- updated_user_data = base64.encodestring(new_user_data.encode()).decode()
+ updated_user_data = base64.encodebytes(new_user_data.encode()).decode()
with self.stopped_vm(vm):
vm.update(self.api_client, userdata=updated_user_data)
diff --git a/test/integration/component/test_deploy_vm_userdata_multi_nic.py b/test/integration/component/test_deploy_vm_userdata_multi_nic.py
index 2f1f256399d..766c96ac119 100644
--- a/test/integration/component/test_deploy_vm_userdata_multi_nic.py
+++ b/test/integration/component/test_deploy_vm_userdata_multi_nic.py
@@ -126,7 +126,7 @@ class TestDeployVmWithUserDataMultiNic(cloudstackTestCase):
"""Test userdata update when non default nic is without userdata for deploy and update
"""
- self.userdata = base64.encodestring(self.userdata.encode()).decode()
+ self.userdata = base64.encodebytes(self.userdata.encode()).decode()
network1 = Network.create(
self.apiclient,
diff --git a/test/integration/component/test_deploy_vm_userdata_reg.py b/test/integration/component/test_deploy_vm_userdata_reg.py
index a6e3c178286..9ac0ff00eb6 100644
--- a/test/integration/component/test_deploy_vm_userdata_reg.py
+++ b/test/integration/component/test_deploy_vm_userdata_reg.py
@@ -99,7 +99,7 @@ class TestDeployVmWithUserData(cloudstackTestCase):
# py2 didn't insert any new-lines
# so we now do the encoding in the stored userdata string and remove the '\n's
# to get a good easy string compare in the assert later on.
- cls.userdata = base64.encodestring(cls.userdata.encode()).decode().replace('\n', '')
+ cls.userdata = base64.encodebytes(cls.userdata.encode()).decode().replace('\n', '')
cls.user_data_2k= ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(2000))
cls.user_data_2kl = ''.join(random.choice(string.ascii_uppercase + string.digits) for x in range(1900))
diff --git a/tools/marvin/marvin/cloudstackConnection.py b/tools/marvin/marvin/cloudstackConnection.py
index c5cbb18dc9e..5b438daceb7 100644
--- a/tools/marvin/marvin/cloudstackConnection.py
+++ b/tools/marvin/marvin/cloudstackConnection.py
@@ -147,7 +147,7 @@ class CSConnection(object):
).replace("+", "%20")]
) for r in params]
)
- signature = base64.encodestring(
+ signature = base64.encodebytes(
hmac.new(self.securityKey.encode('utf-8'),
hash_str.encode('utf-8'),
hashlib.sha1).digest()).strip()
diff --git a/tools/ngui/requester.py b/tools/ngui/requester.py
index 3f3337d3b4e..03342dfa58d 100644
--- a/tools/ngui/requester.py
+++ b/tools/ngui/requester.py
@@ -68,7 +68,7 @@ def make_request(command, args, logger, host, port,
str.lower(urllib.quote_plus(str(r[1]))).replace("+",
"%20")]) for r in request])
- sig = urllib.quote_plus(base64.encodestring(hmac.new(secretkey, hashStr,
+ sig = urllib.quote_plus(base64.encodebytes(hmac.new(secretkey, hashStr,
hashlib.sha1).digest()).strip())
request_url += "&signature=%s" % sig
request_url = "%s://%s:%s%s?%s" % (protocol, host, port, path, request_url)
diff --git a/ui/src/views/tools/ImportUnmanagedInstance.vue b/ui/src/views/tools/ImportUnmanagedInstance.vue
index 28cd6f69a23..ca58bdd7327 100644
--- a/ui/src/views/tools/ImportUnmanagedInstance.vue
+++ b/ui/src/views/tools/ImportUnmanagedInstance.vue
@@ -177,6 +177,7 @@
:maxCpu="getMaxCpu()"
:minMemory="getMinMemory()"
:maxMemory="getMaxMemory()"
+ :cpuSpeed="getCPUSpeed()"
@update-iops-value="updateFieldValue"
@update-compute-cpunumber="updateFieldValue"
@update-compute-cpuspeed="updateFieldValue"
@@ -522,6 +523,15 @@ export default {
}
return 'serviceofferingdetails' in this.computeOffering ? this.computeOffering.serviceofferingdetails.maxmemory * 1 : Number.MAX_SAFE_INTEGER
},
+ getCPUSpeed () {
+ if (!this.computeOffering) {
+ return 0
+ }
+ if (this.computeOffering.cpuspeed) {
+ return this.computeOffering.cpuspeed * 1
+ }
+ return this.resource.cpuspeed * 1 || 0
+ },
fetchOptions (param, name, exclude) {
if (exclude && exclude.length > 0) {
if (exclude.includes(name)) {