Skip to content

Commit b53c760

Browse files
Allow preserving duplicate MACs during VM import
1 parent f6efda5 commit b53c760

10 files changed

Lines changed: 110 additions & 36 deletions

File tree

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -250,6 +250,7 @@ public class ApiConstants {
250250
public static final String FILESYSTEM = "filesystem";
251251
public static final String FIRSTNAME = "firstname";
252252
public static final String FORCED = "forced";
253+
public static final String ALLOW_DUPLICATE_MAC_ADDRESSES = "allowduplicatemacaddresses";
253254
public static final String FORCED_DESTROY_LOCAL_STORAGE = "forcedestroylocalstorage";
254255
public static final String FORCE_CONVERT_TO_POOL = "forceconverttopool";
255256

api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ImportUnmanagedInstanceCmd.java

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,9 +152,15 @@ public class ImportUnmanagedInstanceCmd extends BaseAsyncCmd {
152152

153153
@Parameter(name = ApiConstants.FORCED,
154154
type = CommandType.BOOLEAN,
155-
description = "Instance is imported despite some of its NIC's MAC addresses are already present, in case the MAC address exists then a new MAC address is generated")
155+
description = "Instance is imported even if some NIC MAC addresses already exist. If a MAC address exists, a new MAC address is generated")
156156
private Boolean forced;
157157

158+
@Parameter(name = ApiConstants.ALLOW_DUPLICATE_MAC_ADDRESSES,
159+
type = CommandType.BOOLEAN,
160+
since = "4.23.0",
161+
description = "Preserve imported NIC MAC addresses even when they already exist on the target network. Intended for migration cutover workflows where the source and imported VMs are not active on the same L2 network at the same time")
162+
private Boolean allowDuplicateMacAddresses;
163+
158164
/////////////////////////////////////////////////////
159165
/////////////////// Accessors ///////////////////////
160166
/////////////////////////////////////////////////////
@@ -278,6 +284,10 @@ public boolean isForced() {
278284
return BooleanUtils.isTrue(forced);
279285
}
280286

287+
public boolean isAllowDuplicateMacAddresses() {
288+
return BooleanUtils.isTrue(allowDuplicateMacAddresses);
289+
}
290+
281291
/////////////////////////////////////////////////////
282292
/////////////// API Implementation///////////////////
283293
/////////////////////////////////////////////////////

engine/api/src/main/java/org/apache/cloudstack/engine/orchestration/service/NetworkOrchestrationService.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ void implementNetworkElementsAndResources(DeployDestination dest, ReservationCon
372372
*/
373373
void cleanupNicDhcpDnsEntry(Network network, VirtualMachineProfile vmProfile, NicProfile nicProfile);
374374

375-
Pair<NicProfile, Integer> importNic(final String macAddress, int deviceId, final Network network, final Boolean isDefaultNic, final VirtualMachine vm, final Network.IpAddresses ipAddresses, final DataCenter datacenter, boolean forced) throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException;
375+
Pair<NicProfile, Integer> importNic(final String macAddress, int deviceId, final Network network, final Boolean isDefaultNic, final VirtualMachine vm, final Network.IpAddresses ipAddresses, final DataCenter datacenter, boolean forced, boolean allowDuplicateMacAddress) throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException;
376376

377377
void unmanageNics(VirtualMachineProfile vm);
378378

engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4770,7 +4770,7 @@ public NicVO savePlaceholderNic(final Network network, final String ip4Address,
47704770

47714771
@DB
47724772
@Override
4773-
public Pair<NicProfile, Integer> importNic(final String macAddress, int deviceId, final Network network, final Boolean isDefaultNic, final VirtualMachine vm, final Network.IpAddresses ipAddresses, final DataCenter dataCenter, final boolean forced)
4773+
public Pair<NicProfile, Integer> importNic(final String macAddress, int deviceId, final Network network, final Boolean isDefaultNic, final VirtualMachine vm, final Network.IpAddresses ipAddresses, final DataCenter dataCenter, final boolean forced, final boolean allowDuplicateMacAddress)
47744774
throws ConcurrentOperationException, InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException {
47754775
logger.debug("Allocating NIC for Instance {} in Network {} during import", vm, network);
47764776
String selectedIp = null;
@@ -4796,7 +4796,7 @@ public NicVO doInTransaction(TransactionStatus status) {
47964796
throw new CloudRuntimeException("Invalid mac address: " + macAddressToPersist);
47974797
}
47984798
NicVO existingNic = _nicDao.findByNetworkIdAndMacAddress(network.getId(), macAddressToPersist);
4799-
if (existingNic != null) {
4799+
if (existingNic != null && !allowDuplicateMacAddress) {
48004800
macAddressToPersist = generateNewMacAddressIfForced(network, macAddressToPersist, forced);
48014801
}
48024802
NicVO vo = new NicVO(network.getGuruName(), vm.getId(), network.getId(), vm.getType());

engine/orchestration/src/test/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestratorTest.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -913,7 +913,7 @@ public void testImportNicAcquireGuestIPFailed() throws Exception {
913913
Mockito.when(testOrchestrator._networkModel.listNetworkOfferingServices(networkOfferingId)).thenReturn(Arrays.asList(Service.Dns, Service.Dhcp));
914914
String macAddress = "02:01:01:82:00:01";
915915
int deviceId = 0;
916-
testOrchestrator.importNic(macAddress, deviceId, network, true, vm, ipAddresses, dataCenter, false);
916+
testOrchestrator.importNic(macAddress, deviceId, network, true, vm, ipAddresses, dataCenter, false, false);
917917
}
918918

919919
@Test(expected = InsufficientVirtualNetworkCapacityException.class)
@@ -932,7 +932,7 @@ public void testImportNicAutoAcquireGuestIPFailed() throws Exception {
932932
Mockito.when(testOrchestrator._networkModel.listNetworkOfferingServices(networkOfferingId)).thenReturn(Arrays.asList(Service.Dns, Service.Dhcp));
933933
String macAddress = "02:01:01:82:00:01";
934934
int deviceId = 0;
935-
testOrchestrator.importNic(macAddress, deviceId, network, true, vm, ipAddresses, dataCenter, false);
935+
testOrchestrator.importNic(macAddress, deviceId, network, true, vm, ipAddresses, dataCenter, false, false);
936936
}
937937

938938
@Test
@@ -959,7 +959,7 @@ public void testImportNicNoIP4Address() throws Exception {
959959
Mockito.when(testOrchestrator._networkModel.getNetworkTag(hypervisorType, network)).thenReturn("testtag");
960960
try (MockedStatic<Transaction> transactionMocked = Mockito.mockStatic(Transaction.class)) {
961961
transactionMocked.when(() -> Transaction.execute(any(TransactionCallback.class))).thenReturn(nic);
962-
Pair<NicProfile, Integer> nicProfileIntegerPair = testOrchestrator.importNic(macAddress, deviceId, network, true, vm, ipAddresses, dataCenter, false);
962+
Pair<NicProfile, Integer> nicProfileIntegerPair = testOrchestrator.importNic(macAddress, deviceId, network, true, vm, ipAddresses, dataCenter, false, false);
963963
verify(testOrchestrator._networkModel, times(1)).getNetworkRate(networkId, vmId);
964964
verify(testOrchestrator._networkModel, times(1)).isSecurityGroupSupportedInNetwork(network);
965965
verify(testOrchestrator._networkModel, times(1)).getNetworkTag(Hypervisor.HypervisorType.KVM, network);
@@ -997,7 +997,7 @@ public void testImportNicWithIP4Address() throws Exception {
997997
Mockito.when(testOrchestrator._networkModel.getNetworkTag(hypervisorType, network)).thenReturn("testtag");
998998
try (MockedStatic<Transaction> transactionMocked = Mockito.mockStatic(Transaction.class)) {
999999
transactionMocked.when(() -> Transaction.execute(any(TransactionCallback.class))).thenReturn(nic);
1000-
Pair<NicProfile, Integer> nicProfileIntegerPair = testOrchestrator.importNic(macAddress, deviceId, network, true, vm, ipAddresses, dataCenter, false);
1000+
Pair<NicProfile, Integer> nicProfileIntegerPair = testOrchestrator.importNic(macAddress, deviceId, network, true, vm, ipAddresses, dataCenter, false, false);
10011001
verify(testOrchestrator, times(1)).getSelectedIpForNicImport(network, dataCenter, ipAddresses);
10021002
verify(testOrchestrator._networkModel, times(1)).getNetworkRate(networkId, vmId);
10031003
verify(testOrchestrator._networkModel, times(1)).isSecurityGroupSupportedInNetwork(network);

0 commit comments

Comments
 (0)