Skip to content

Commit cec6ade

Browse files
authored
change live migration API used on kvm (#8952)
1 parent 0e08a12 commit cec6ade

5 files changed

Lines changed: 230 additions & 9 deletions

File tree

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtVMDef.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -972,6 +972,10 @@ public String getDiskLabel() {
972972
return _diskLabel;
973973
}
974974

975+
public void setDiskLabel(String label) {
976+
_diskLabel = label;
977+
}
978+
975979
public DiskType getDiskType() {
976980
return _diskType;
977981
}

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/MigrateKVMAsync.java

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,20 @@
1818
*/
1919
package com.cloud.hypervisor.kvm.resource;
2020

21+
import java.util.Iterator;
22+
import java.util.Set;
2123
import java.util.concurrent.Callable;
2224

25+
import org.apache.log4j.Logger;
2326
import org.libvirt.Connect;
2427
import org.libvirt.Domain;
2528
import org.libvirt.LibvirtException;
29+
import org.libvirt.TypedParameter;
30+
import org.libvirt.TypedStringParameter;
31+
import org.libvirt.TypedUlongParameter;
2632

2733
public class MigrateKVMAsync implements Callable<Domain> {
34+
protected Logger logger = Logger.getLogger(getClass());
2835

2936
private final LibvirtComputingResource libvirtComputingResource;
3037

@@ -37,6 +44,8 @@ public class MigrateKVMAsync implements Callable<Domain> {
3744
private boolean migrateNonSharedInc;
3845
private boolean autoConvergence;
3946

47+
protected Set<String> migrateDiskLabels;
48+
4049
// Libvirt Migrate Flags reference:
4150
// https://libvirt.org/html/libvirt-libvirt-domain.html#virDomainMigrateFlags
4251

@@ -87,7 +96,7 @@ public class MigrateKVMAsync implements Callable<Domain> {
8796
private static final int LIBVIRT_VERSION_SUPPORTS_AUTO_CONVERGE = 1002003;
8897

8998
public MigrateKVMAsync(final LibvirtComputingResource libvirtComputingResource, final Domain dm, final Connect dconn, final String dxml,
90-
final boolean migrateStorage, final boolean migrateNonSharedInc, final boolean autoConvergence, final String vmName, final String destIp) {
99+
final boolean migrateStorage, final boolean migrateNonSharedInc, final boolean autoConvergence, final String vmName, final String destIp, Set<String> migrateDiskLabels) {
91100
this.libvirtComputingResource = libvirtComputingResource;
92101

93102
this.dm = dm;
@@ -98,6 +107,7 @@ public MigrateKVMAsync(final LibvirtComputingResource libvirtComputingResource,
98107
this.autoConvergence = autoConvergence;
99108
this.vmName = vmName;
100109
this.destIp = destIp;
110+
this.migrateDiskLabels = migrateDiskLabels;
101111
}
102112

103113
@Override
@@ -121,6 +131,37 @@ public Domain call() throws LibvirtException {
121131
flags |= VIR_MIGRATE_AUTO_CONVERGE;
122132
}
123133

124-
return dm.migrate(dconn, flags, dxml, vmName, "tcp:" + destIp, libvirtComputingResource.getMigrateSpeed());
134+
TypedParameter [] parameters = createTypedParameterList();
135+
136+
logger.debug(String.format("Migrating [%s] with flags [%s], destination [%s] and speed [%s]. The disks with the following labels will be migrated [%s].", vmName, flags,
137+
destIp, libvirtComputingResource.getMigrateSpeed(), migrateDiskLabels));
138+
139+
return dm.migrate(dconn, parameters, flags);
140+
141+
}
142+
143+
protected TypedParameter[] createTypedParameterList() {
144+
int sizeOfMigrateDiskLabels = 0;
145+
if (migrateDiskLabels != null) {
146+
sizeOfMigrateDiskLabels = migrateDiskLabels.size();
147+
}
148+
149+
TypedParameter[] parameters = new TypedParameter[4 + sizeOfMigrateDiskLabels];
150+
parameters[0] = new TypedStringParameter(Domain.DomainMigrateParameters.VIR_MIGRATE_PARAM_DEST_NAME, vmName);
151+
parameters[1] = new TypedStringParameter(Domain.DomainMigrateParameters.VIR_MIGRATE_PARAM_DEST_XML, dxml);
152+
parameters[2] = new TypedStringParameter(Domain.DomainMigrateParameters.VIR_MIGRATE_PARAM_URI, "tcp:" + destIp);
153+
parameters[3] = new TypedUlongParameter(Domain.DomainMigrateParameters.VIR_MIGRATE_PARAM_BANDWIDTH, libvirtComputingResource.getMigrateSpeed());
154+
155+
if (sizeOfMigrateDiskLabels == 0) {
156+
return parameters;
157+
}
158+
159+
Iterator<String> iterator = migrateDiskLabels.iterator();
160+
for (int i = 0; i < sizeOfMigrateDiskLabels; i++) {
161+
parameters[4 + i] = new TypedStringParameter(Domain.DomainMigrateParameters.VIR_MIGRATE_PARAM_MIGRATE_DISKS, iterator.next());
162+
}
163+
164+
return parameters;
125165
}
166+
126167
}

plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapper.java

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import java.io.InputStream;
2525
import java.net.URISyntaxException;
2626
import java.nio.charset.StandardCharsets;
27+
import java.util.HashSet;
2728
import java.util.List;
2829
import java.util.Map;
2930
import java.util.Set;
@@ -190,6 +191,7 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
190191
// migrateStorage's value should always only be associated with the initial state of mapMigrateStorage.
191192
final boolean migrateStorage = MapUtils.isNotEmpty(mapMigrateStorage);
192193
final boolean migrateStorageManaged = command.isMigrateStorageManaged();
194+
Set<String> migrateDiskLabels = null;
193195

194196
if (migrateStorage) {
195197
if (s_logger.isDebugEnabled()) {
@@ -199,6 +201,7 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
199201
if (s_logger.isDebugEnabled()) {
200202
s_logger.debug(String.format("Changed VM [%s] XML configuration of used storage. New XML configuration is [%s].", vmName, xmlDesc));
201203
}
204+
migrateDiskLabels = getMigrateStorageDeviceLabels(disks, mapMigrateStorage);
202205
}
203206

204207
Map<String, DpdkTO> dpdkPortsMapping = command.getDpdkInterfaceMapping();
@@ -227,7 +230,7 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
227230

228231
final Callable<Domain> worker = new MigrateKVMAsync(libvirtComputingResource, dm, dconn, xmlDesc,
229232
migrateStorage, migrateNonSharedInc,
230-
command.isAutoConvergence(), vmName, command.getDestinationIp());
233+
command.isAutoConvergence(), vmName, command.getDestinationIp(), migrateDiskLabels);
231234
final Future<Domain> migrateThread = executor.submit(worker);
232235
executor.shutdown();
233236
long sleeptime = 0;
@@ -365,6 +368,30 @@ Use VIR_DOMAIN_XML_SECURE (value = 1) prior to v1.0.0.
365368
return new MigrateAnswer(command, result == null, result, null);
366369
}
367370

371+
/**
372+
* Gets the disk labels (vda, vdb...) of the disks mapped for migration on mapMigrateStorage.
373+
* @param diskDefinitions list of all the disksDefinitions of the VM.
374+
* @param mapMigrateStorage map of the disks that should be migrated.
375+
* @return set with the labels of the disks that should be migrated.
376+
* */
377+
protected Set<String> getMigrateStorageDeviceLabels(List<DiskDef> diskDefinitions, Map<String, MigrateCommand.MigrateDiskInfo> mapMigrateStorage) {
378+
HashSet<String> setOfLabels = new HashSet<>();
379+
s_logger.debug(String.format("Searching for disk labels of disks [%s].", mapMigrateStorage.keySet()));
380+
for (String fileName : mapMigrateStorage.keySet()) {
381+
for (DiskDef diskDef : diskDefinitions) {
382+
String diskPath = diskDef.getDiskPath();
383+
if (diskPath != null && diskPath.contains(fileName)) {
384+
setOfLabels.add(diskDef.getDiskLabel());
385+
s_logger.debug(String.format("Found label [%s] for disk [%s].", diskDef.getDiskLabel(), fileName));
386+
break;
387+
}
388+
}
389+
}
390+
391+
return setOfLabels;
392+
}
393+
394+
368395
/**
369396
* Checks if the CPU shares are equal in the source host and destination host.
370397
* <ul>
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
//
2+
// Licensed to the Apache Software Foundation (ASF) under one
3+
// or more contributor license agreements. See the NOTICE file
4+
// distributed with this work for additional information
5+
// regarding copyright ownership. The ASF licenses this file
6+
// to you under the Apache License, Version 2.0 (the
7+
// "License"); you may not use this file except in compliance
8+
// with the License. You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing,
13+
// software distributed under the License is distributed on an
14+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
// KIND, either express or implied. See the License for the
16+
// specific language governing permissions and limitations
17+
// under the License.
18+
//
19+
20+
package com.cloud.hypervisor.kvm.resource;
21+
22+
import org.junit.Assert;
23+
import org.junit.Test;
24+
import org.junit.runner.RunWith;
25+
import org.libvirt.Connect;
26+
import org.libvirt.Domain;
27+
import org.libvirt.TypedParameter;
28+
import org.mockito.Mock;
29+
import org.mockito.Mockito;
30+
import org.mockito.junit.MockitoJUnitRunner;
31+
32+
import java.util.Set;
33+
34+
@RunWith(MockitoJUnitRunner.class)
35+
public class MigrateKVMAsyncTest {
36+
37+
@Mock
38+
private LibvirtComputingResource libvirtComputingResource;
39+
@Mock
40+
private Connect connect;
41+
@Mock
42+
private Domain domain;
43+
44+
45+
@Test
46+
public void createTypedParameterListTestNoMigrateDiskLabels() {
47+
MigrateKVMAsync migrateKVMAsync = new MigrateKVMAsync(libvirtComputingResource, domain, connect, "testxml",
48+
false, false, false, "tst", "1.1.1.1", null);
49+
50+
Mockito.doReturn(10).when(libvirtComputingResource).getMigrateSpeed();
51+
52+
TypedParameter[] result = migrateKVMAsync.createTypedParameterList();
53+
54+
Assert.assertEquals(4, result.length);
55+
56+
Assert.assertEquals("tst", result[0].getValueAsString());
57+
Assert.assertEquals("testxml", result[1].getValueAsString());
58+
Assert.assertEquals("tcp:1.1.1.1", result[2].getValueAsString());
59+
Assert.assertEquals("10", result[3].getValueAsString());
60+
61+
}
62+
63+
@Test
64+
public void createTypedParameterListTestWithMigrateDiskLabels() {
65+
Set<String> labels = Set.of("vda", "vdb");
66+
MigrateKVMAsync migrateKVMAsync = new MigrateKVMAsync(libvirtComputingResource, domain, connect, "testxml",
67+
false, false, false, "tst", "1.1.1.1", labels);
68+
69+
Mockito.doReturn(10).when(libvirtComputingResource).getMigrateSpeed();
70+
71+
TypedParameter[] result = migrateKVMAsync.createTypedParameterList();
72+
73+
Assert.assertEquals(6, result.length);
74+
75+
Assert.assertEquals("tst", result[0].getValueAsString());
76+
Assert.assertEquals("testxml", result[1].getValueAsString());
77+
Assert.assertEquals("tcp:1.1.1.1", result[2].getValueAsString());
78+
Assert.assertEquals("10", result[3].getValueAsString());
79+
80+
Assert.assertEquals(labels, Set.of(result[4].getValueAsString(), result[5].getValueAsString()));
81+
}
82+
83+
}

plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtMigrateCommandWrapperTest.java

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,12 @@
2626
import java.io.InputStream;
2727
import java.nio.charset.StandardCharsets;
2828
import java.util.ArrayList;
29+
import java.util.Arrays;
2930
import java.util.HashMap;
3031
import java.util.List;
3132
import java.util.Map;
3233
import java.util.Scanner;
34+
import java.util.Set;
3335

3436
import javax.xml.parsers.DocumentBuilder;
3537
import javax.xml.parsers.DocumentBuilderFactory;
@@ -585,6 +587,14 @@ public void setup() throws Exception {
585587
" </devices>\n" +
586588
"</domain>\n";
587589

590+
private Map<String, MigrateDiskInfo> createMapMigrateStorage(String sourceText, String path) {
591+
Map<String, MigrateDiskInfo> mapMigrateStorage = new HashMap<String, MigrateDiskInfo>();
592+
593+
MigrateDiskInfo diskInfo = new MigrateDiskInfo("123456", DiskType.BLOCK, DriverType.RAW, Source.FILE, sourceText);
594+
mapMigrateStorage.put(path, diskInfo);
595+
return mapMigrateStorage;
596+
}
597+
588598
@Test
589599
public void testReplaceIpForVNCInDescFile() {
590600
final String targetIp = "192.168.22.21";
@@ -761,10 +771,8 @@ static void assertXpath(final Document doc, final String xPathExpr,
761771

762772
@Test
763773
public void testReplaceStorage() throws Exception {
764-
Map<String, MigrateDiskInfo> mapMigrateStorage = new HashMap<String, MigrateDiskInfo>();
774+
Map<String, MigrateDiskInfo> mapMigrateStorage = createMapMigrateStorage("sourceTest", "/mnt/812ea6a3-7ad0-30f4-9cab-01e3f2985b98/4650a2f7-fce5-48e2-beaa-bcdf063194e6");
765775

766-
MigrateDiskInfo diskInfo = new MigrateDiskInfo("123456", DiskType.BLOCK, DriverType.RAW, Source.FILE, "sourctest");
767-
mapMigrateStorage.put("/mnt/812ea6a3-7ad0-30f4-9cab-01e3f2985b98/4650a2f7-fce5-48e2-beaa-bcdf063194e6", diskInfo);
768776
final String result = libvirtMigrateCmdWrapper.replaceStorage(fullfile, mapMigrateStorage, true);
769777

770778
InputStream in = IOUtils.toInputStream(result);
@@ -778,7 +786,6 @@ public void testReplaceStorage() throws Exception {
778786

779787
@Test
780788
public void testReplaceStorageWithSecrets() throws Exception {
781-
Map<String, MigrateDiskInfo> mapMigrateStorage = new HashMap<String, MigrateDiskInfo>();
782789

783790
final String xmlDesc =
784791
"<domain type='kvm' id='3'>" +
@@ -799,8 +806,7 @@ public void testReplaceStorageWithSecrets() throws Exception {
799806

800807
final String volumeFile = "3530f749-82fd-458e-9485-a357e6e541db";
801808
String newDiskPath = "/mnt/2d0435e1-99e0-4f1d-94c0-bee1f6f8b99e/" + volumeFile;
802-
MigrateDiskInfo diskInfo = new MigrateDiskInfo("123456", DiskType.BLOCK, DriverType.RAW, Source.FILE, newDiskPath);
803-
mapMigrateStorage.put("/mnt/07eb495b-5590-3877-9fb7-23c6e9a40d40/bf8621b3-027c-497d-963b-06319650f048", diskInfo);
809+
Map<String, MigrateDiskInfo> mapMigrateStorage = createMapMigrateStorage(newDiskPath, "/mnt/07eb495b-5590-3877-9fb7-23c6e9a40d40/bf8621b3-027c-497d-963b-06319650f048");
804810
final String result = libvirtMigrateCmdWrapper.replaceStorage(xmlDesc, mapMigrateStorage, false);
805811
final String expectedSecretUuid = LibvirtComputingResource.generateSecretUUIDFromString(volumeFile);
806812

@@ -951,4 +957,64 @@ public void updateVmSharesIfNeededTestNewCpuSharesLowerThanCurrentSharesShouldUp
951957

952958
Assert.assertEquals(updateShares, newVmCpuShares);
953959
}
960+
961+
@Test
962+
public void getMigrateStorageDeviceLabelsTestNoDiskDefinitions() {
963+
Map<String, MigrateDiskInfo> mapMigrateStorage = createMapMigrateStorage("sourceTest", "/mnt/812ea6a3-7ad0-30f4-9cab-01e3f2985b98/4650a2f7-fce5-48e2-beaa-bcdf063194e6");
964+
965+
Set<String> result = libvirtMigrateCmdWrapper.getMigrateStorageDeviceLabels(new ArrayList<>(), mapMigrateStorage);
966+
967+
assertTrue(result.isEmpty());
968+
}
969+
970+
@Test
971+
public void getMigrateStorageDeviceLabelsTestNoMapMigrateStorage() {
972+
List<DiskDef> disks = new ArrayList<>();
973+
DiskDef diskDef0 = new DiskDef();
974+
975+
diskDef0.setDiskPath("volPath");
976+
disks.add(diskDef0);
977+
978+
Set<String> result = libvirtMigrateCmdWrapper.getMigrateStorageDeviceLabels(disks, new HashMap<>());
979+
980+
assertTrue(result.isEmpty());
981+
}
982+
983+
@Test
984+
public void getMigrateStorageDeviceLabelsTestPathIsNotFound() {
985+
List<DiskDef> disks = new ArrayList<>();
986+
DiskDef diskDef0 = new DiskDef();
987+
988+
diskDef0.setDiskPath("volPath");
989+
disks.add(diskDef0);
990+
991+
Map<String, MigrateDiskInfo> mapMigrateStorage = createMapMigrateStorage("sourceTest", "/mnt/812ea6a3-7ad0-30f4-9cab-01e3f2985b98/4650a2f7-fce5-48e2-beaa-bcdf063194e6");
992+
993+
Set<String> result = libvirtMigrateCmdWrapper.getMigrateStorageDeviceLabels(disks, mapMigrateStorage);
994+
995+
assertTrue(result.isEmpty());
996+
}
997+
998+
@Test
999+
public void getMigrateStorageDeviceLabelsTestFindPathAndLabels() {
1000+
List<DiskDef> disks = new ArrayList<>();
1001+
DiskDef diskDef0 = new DiskDef();
1002+
DiskDef diskDef1 = new DiskDef();
1003+
1004+
diskDef0.setDiskPath("volPath1");
1005+
diskDef0.setDiskLabel("vda");
1006+
disks.add(diskDef0);
1007+
1008+
diskDef1.setDiskPath("volPath2");
1009+
diskDef1.setDiskLabel("vdb");
1010+
disks.add(diskDef1);
1011+
1012+
Map<String, MigrateDiskInfo> mapMigrateStorage = createMapMigrateStorage("sourceTest", "volPath1");
1013+
mapMigrateStorage.put("volPath2", new MigrateDiskInfo("123457", DiskType.BLOCK, DriverType.RAW, Source.FILE, "sourceText"));
1014+
1015+
Set<String> result = libvirtMigrateCmdWrapper.getMigrateStorageDeviceLabels(disks, mapMigrateStorage);
1016+
1017+
assertTrue(result.containsAll(Arrays.asList("vda", "vdb")));
1018+
}
1019+
9541020
}

0 commit comments

Comments
 (0)