Add option to control MAC address reuse for VR public NICs (#13001)

This commit is contained in:
Bernardo De Marco Gonçalves 2026-05-06 13:41:11 -03:00 committed by GitHub
parent 1e512ab9c6
commit 96ca1b2a7c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
35 changed files with 692 additions and 99 deletions

View File

@ -510,4 +510,6 @@ public interface Network extends ControlledEntity, StateObject<Network.State>, I
Integer getPrivateMtu();
Integer getNetworkCidrSize();
boolean getKeepMacAddressOnPublicNic();
}

View File

@ -385,6 +385,11 @@ public class NetworkProfile implements Network {
return networkCidrSize;
}
@Override
public boolean getKeepMacAddressOnPublicNic() {
return true;
}
@Override
public String toString() {
return String.format("NetworkProfile %s",

View File

@ -107,4 +107,6 @@ public interface Vpc extends ControlledEntity, Identity, InternalIdentity {
String getIp6Dns2();
boolean useRouterIpAsResolver();
boolean getKeepMacAddressOnPublicNic();
}

View File

@ -58,7 +58,7 @@ public interface VpcService {
*/
Vpc createVpc(long zoneId, long vpcOffId, long vpcOwnerId, String vpcName, String displayText, String cidr, String networkDomain,
String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2, Boolean displayVpc, Integer publicMtu, Integer cidrSize,
Long asNumber, List<Long> bgpPeerIds, Boolean useVrIpResolver) throws ResourceAllocationException;
Long asNumber, List<Long> bgpPeerIds, Boolean useVrIpResolver, boolean keepMacAddressOnPublicNic) throws ResourceAllocationException;
/**
* Persists VPC record in the database
@ -104,7 +104,7 @@ public interface VpcService {
* @throws ResourceUnavailableException if during restart some resources may not be available
* @throws InsufficientCapacityException if for instance no address space, compute or storage is sufficiently available
*/
Vpc updateVpc(long vpcId, String vpcName, String displayText, String customId, Boolean displayVpc, Integer mtu, String sourceNatIp) throws ResourceUnavailableException, InsufficientCapacityException;
Vpc updateVpc(long vpcId, String vpcName, String displayText, String customId, Boolean displayVpc, Integer mtu, String sourceNatIp, Boolean keepMacAddressOnPublicNic) throws ResourceUnavailableException, InsufficientCapacityException;
/**
* Lists VPC(s) based on the parameters passed to the API call

View File

@ -1356,6 +1356,13 @@ public class ApiConstants {
public static final String OBJECT_STORAGE_LIMIT = "objectstoragelimit";
public static final String OBJECT_STORAGE_TOTAL = "objectstoragetotal";
public static final String KEEP_MAC_ADDRESS_ON_PUBLIC_NIC = "keepmacaddressonpublicnic";
public static final String PARAMETER_DESCRIPTION_KEEP_MAC_ADDRESS_ON_PUBLIC_NIC =
"Indicates whether to use the same MAC address for the public NIC of VRs on the same network. If \"true\", when creating redundant routers or recreating" +
" a VR, CloudStack will use the same MAC address for the public NIC of all VRs. Otherwise, if \"false\", new public NICs will always have " +
" a new MAC address.";
public static final String PARAMETER_DESCRIPTION_ACTIVATION_RULE = "Quota tariff's activation rule. It can receive a JS script that results in either " +
"a boolean or a numeric value: if it results in a boolean value, the tariff value will be applied according to the result; if it results in a numeric value, the " +
"numeric value will be applied; if the result is neither a boolean nor a numeric value, the tariff will not be applied. If the rule is not informed, the tariff " +

View File

@ -199,6 +199,11 @@ public class CreateNetworkCmd extends BaseCmd implements UserCmd {
@Parameter(name=ApiConstants.AS_NUMBER, type=CommandType.LONG, since = "4.20.0", description="the AS Number of the network")
private Long asNumber;
@Parameter(name = ApiConstants.KEEP_MAC_ADDRESS_ON_PUBLIC_NIC,
description = ApiConstants.PARAMETER_DESCRIPTION_KEEP_MAC_ADDRESS_ON_PUBLIC_NIC,
type = CommandType.BOOLEAN, since = "4.23.0", authorized = {RoleType.Admin})
private Boolean keepMacAddressOnPublicNic;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -286,6 +291,10 @@ public class CreateNetworkCmd extends BaseCmd implements UserCmd {
return sourceNatIP;
}
public Boolean getKeepMacAddressOnPublicNic() {
return keepMacAddressOnPublicNic;
}
@Override
public boolean isDisplay() {
if(displayNetwork == null)

View File

@ -105,6 +105,11 @@ public class UpdateNetworkCmd extends BaseAsyncCustomIdCmd implements UserCmd {
@Parameter(name = ApiConstants.SOURCE_NAT_IP, type = CommandType.STRING, description = "IPV4 address to be assigned to the public interface of the network router. This address must already be acquired for this network", since = "4.19")
private String sourceNatIP;
@Parameter(name = ApiConstants.KEEP_MAC_ADDRESS_ON_PUBLIC_NIC,
description = ApiConstants.PARAMETER_DESCRIPTION_KEEP_MAC_ADDRESS_ON_PUBLIC_NIC,
type = CommandType.BOOLEAN, since = "4.23.0", authorized = {RoleType.Admin})
private Boolean keepMacAddressOnPublicNic;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -186,6 +191,10 @@ public class UpdateNetworkCmd extends BaseAsyncCustomIdCmd implements UserCmd {
return sourceNatIP;
}
public Boolean getKeepMacAddressOnPublicNic() {
return keepMacAddressOnPublicNic;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -130,6 +130,11 @@ public class CreateVPCCmd extends BaseAsyncCreateCmd implements UserCmd {
description="(optional) for NSX based VPCs: when set to true, use the VR IP as nameserver, otherwise use DNS1 and DNS2")
private Boolean useVrIpResolver;
@Parameter(name = ApiConstants.KEEP_MAC_ADDRESS_ON_PUBLIC_NIC,
description = ApiConstants.PARAMETER_DESCRIPTION_KEEP_MAC_ADDRESS_ON_PUBLIC_NIC,
type = CommandType.BOOLEAN, since = "4.23.0", authorized = {RoleType.Admin})
private boolean keepMacAddressOnPublicNic = true;
// ///////////////////////////////////////////////////
// ///////////////// Accessors ///////////////////////
// ///////////////////////////////////////////////////
@ -214,6 +219,10 @@ public class CreateVPCCmd extends BaseAsyncCreateCmd implements UserCmd {
return BooleanUtils.toBoolean(useVrIpResolver);
}
public boolean getKeepMacAddressOnPublicNic() {
return keepMacAddressOnPublicNic;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -69,6 +69,11 @@ public class UpdateVPCCmd extends BaseAsyncCustomIdCmd implements UserCmd {
since = "4.19")
private String sourceNatIP;
@Parameter(name = ApiConstants.KEEP_MAC_ADDRESS_ON_PUBLIC_NIC,
description = ApiConstants.PARAMETER_DESCRIPTION_KEEP_MAC_ADDRESS_ON_PUBLIC_NIC,
type = CommandType.BOOLEAN, since = "4.23.0", authorized = {RoleType.Admin})
private Boolean keepMacAddressOnPublicNic;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
@ -97,6 +102,10 @@ public class UpdateVPCCmd extends BaseAsyncCustomIdCmd implements UserCmd {
return sourceNatIP;
}
public Boolean getKeepMacAddressOnPublicNic() {
return keepMacAddressOnPublicNic;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

View File

@ -331,6 +331,10 @@ public class NetworkResponse extends BaseResponseWithAssociatedNetwork implement
@Param(description = "The BGP peers for the network", since = "4.20.0")
private Set<BgpPeerResponse> bgpPeers;
@SerializedName(ApiConstants.KEEP_MAC_ADDRESS_ON_PUBLIC_NIC)
@Param(description = ApiConstants.PARAMETER_DESCRIPTION_KEEP_MAC_ADDRESS_ON_PUBLIC_NIC, since = "4.23.0")
private Boolean keepMacAddressOnPublicNic;
public NetworkResponse() {}
public Boolean getDisplayNetwork() {
@ -702,4 +706,8 @@ public class NetworkResponse extends BaseResponseWithAssociatedNetwork implement
public void setIpv6Dns2(String ipv6Dns2) {
this.ipv6Dns2 = ipv6Dns2;
}
public void setKeepMacAddressOnPublicNic(Boolean keepMacAddressOnPublicNic) {
this.keepMacAddressOnPublicNic = keepMacAddressOnPublicNic;
}
}

View File

@ -185,6 +185,10 @@ public class VpcResponse extends BaseResponseWithAnnotations implements Controll
@Param(description = "The BGP peers for the VPC", since = "4.20.0")
private Set<BgpPeerResponse> bgpPeers;
@SerializedName(ApiConstants.KEEP_MAC_ADDRESS_ON_PUBLIC_NIC)
@Param(description = ApiConstants.PARAMETER_DESCRIPTION_KEEP_MAC_ADDRESS_ON_PUBLIC_NIC, since = "4.23.0")
private Boolean keepMacAddressOnPublicNic;
public void setId(final String id) {
this.id = id;
}
@ -366,4 +370,8 @@ public class VpcResponse extends BaseResponseWithAnnotations implements Controll
}
this.bgpPeers.add(bgpPeer);
}
public void setKeepMacAddressOnPublicNic(Boolean keepMacAddressOnPublicNic) {
this.keepMacAddressOnPublicNic = keepMacAddressOnPublicNic;
}
}

View File

@ -93,7 +93,7 @@ public class UpdateVPCCmdTest extends TestCase {
responseGenerator = Mockito.mock(ResponseGenerator.class);
cmd._responseGenerator = responseGenerator;
Mockito.verify(_vpcService, Mockito.times(0)).updateVpc(Mockito.anyLong(), Mockito.anyString(), Mockito.anyString(),
Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyInt(), Mockito.anyString());
Mockito.anyString(), Mockito.anyBoolean(), Mockito.anyInt(), Mockito.anyString(), Mockito.anyBoolean());
}
}

View File

@ -220,6 +220,11 @@ public interface NetworkOrchestrationService {
Boolean displayNetworkEnabled, String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId, String routerIp, String routerIpv6,
String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs, Integer networkCidrSize) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException;
Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, boolean bypassVlanOverlapCheck, String networkDomain, Account owner,
Long domainId, PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String ip6Gateway, String ip6Cidr,
Boolean displayNetworkEnabled, String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId, String routerIp, String routerIpv6,
String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs, Integer networkCidrSize, boolean keepMacAddressOnPublicNic) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException;
UserDataServiceProvider getPasswordResetProvider(Network network);
UserDataServiceProvider getSSHKeyResetProvider(Network network);

View File

@ -863,6 +863,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
vpcId, offering.isRedundantRouter(), predefined.getExternalId());
vo.setDisplayNetwork(isDisplayNetworkEnabled == null || isDisplayNetworkEnabled);
vo.setStrechedL2Network(offering.isSupportingStrechedL2());
vo.setKeepMacAddressOnPublicNic(predefined.getKeepMacAddressOnPublicNic());
return vo;
}
@ -2724,7 +2725,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
return createGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId,
bypassVlanOverlapCheck, null, owner, null, pNtwk, pNtwk.getDataCenterId(), ACLType.Account, null,
vpcId, null, null, true, null, null, null, true, null, null,
null, null, null, null, null, null);
null, null, null, null, null, null, true);
}
@Override
@ -2735,10 +2736,25 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
final Boolean isDisplayNetworkEnabled, final String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId,
String routerIp, String routerIpv6, String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2,
Pair<Integer, Integer> vrIfaceMTUs, Integer networkCidrSize) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
return createGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId, bypassVlanOverlapCheck,
networkDomain, owner, domainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, ip6Gateway, ip6Cidr,
isDisplayNetworkEnabled, isolatedPvlan, isolatedPvlanType, externalId, false, routerIp, routerIpv6,
ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2, vrIfaceMTUs, networkCidrSize, true);
}
@Override
@DB
public Network createGuestNetwork(final long networkOfferingId, final String name, final String displayText, final String gateway, final String cidr, String vlanId,
boolean bypassVlanOverlapCheck, String networkDomain, final Account owner, final Long domainId, final PhysicalNetwork pNtwk,
final long zoneId, final ACLType aclType, Boolean subdomainAccess, final Long vpcId, final String ip6Gateway, final String ip6Cidr,
final Boolean isDisplayNetworkEnabled, final String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId,
String routerIp, String routerIpv6, String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2,
Pair<Integer, Integer> vrIfaceMTUs, Integer networkCidrSize, boolean keepMacAddressOnPublicNic) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
// create Isolated/Shared/L2 network
return createGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId, bypassVlanOverlapCheck,
networkDomain, owner, domainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, ip6Gateway, ip6Cidr,
isDisplayNetworkEnabled, isolatedPvlan, isolatedPvlanType, externalId, false, routerIp, routerIpv6, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2, vrIfaceMTUs, networkCidrSize);
isDisplayNetworkEnabled, isolatedPvlan, isolatedPvlanType, externalId, false, routerIp, routerIpv6,
ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2, vrIfaceMTUs, networkCidrSize, keepMacAddressOnPublicNic);
}
@DB
@ -2747,7 +2763,8 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
final long zoneId, final ACLType aclType, Boolean subdomainAccess, final Long vpcId, final String ip6Gateway, final String ip6Cidr,
final Boolean isDisplayNetworkEnabled, final String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId,
final Boolean isPrivateNetwork, String routerIp, String routerIpv6, final String ip4Dns1, final String ip4Dns2,
final String ip6Dns1, final String ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs, Integer networkCidrSize) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
final String ip6Dns1, final String ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs, Integer networkCidrSize,
boolean keepMacAddressOnPublicNic) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException {
final NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId);
final DataCenterVO zone = _dcDao.findById(zoneId);
@ -3095,6 +3112,7 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra
}
}
userNetwork.setNetworkCidrSize(networkCidrSize);
userNetwork.setKeepMacAddressOnPublicNic(keepMacAddressOnPublicNic);
final List<? extends Network> networks = setupNetwork(owner, ntwkOff, userNetwork, plan, name, displayText, true, domainId, aclType, subdomainAccessFinal, vpcId,
isDisplayNetworkEnabled);
Network network;

View File

@ -203,9 +203,13 @@ public class NetworkVO implements Network {
@Column(name = "private_mtu")
Integer privateMtu;
@Column(name = "keep_mac_address_on_public_nic")
private boolean keepMacAddressOnPublicNic = true;
@Transient
Integer networkCidrSize;
public NetworkVO() {
uuid = UUID.randomUUID().toString();
}
@ -773,4 +777,13 @@ public class NetworkVO implements Network {
public void setNetworkCidrSize(Integer networkCidrSize) {
this.networkCidrSize = networkCidrSize;
}
@Override
public boolean getKeepMacAddressOnPublicNic() {
return keepMacAddressOnPublicNic;
}
public void setKeepMacAddressOnPublicNic(boolean keepMacAddressOnPublicNic) {
this.keepMacAddressOnPublicNic = keepMacAddressOnPublicNic;
}
}

View File

@ -108,6 +108,9 @@ public class VpcVO implements Vpc {
@Column(name = "use_router_ip_resolver")
boolean useRouterIpResolver = false;
@Column(name = "keep_mac_address_on_public_nic")
private boolean keepMacAddressOnPublicNic = true;
@Transient
boolean rollingRestart = false;
@ -321,4 +324,13 @@ public class VpcVO implements Vpc {
public void setUseRouterIpResolver(boolean useRouterIpResolver) {
this.useRouterIpResolver = useRouterIpResolver;
}
@Override
public boolean getKeepMacAddressOnPublicNic() {
return keepMacAddressOnPublicNic;
}
public void setKeepMacAddressOnPublicNic(boolean keepMacAddressOnPublicNic) {
this.keepMacAddressOnPublicNic = keepMacAddressOnPublicNic;
}
}

View File

@ -127,3 +127,7 @@ CREATE TABLE IF NOT EXISTS `cloud_usage`.`quota_tariff_usage` (
PRIMARY KEY (`id`),
CONSTRAINT `fk_quota_tariff_usage__tariff_id` FOREIGN KEY (`tariff_id`) REFERENCES `cloud_usage`.`quota_tariff` (`id`),
CONSTRAINT `fk_quota_tariff_usage__quota_usage_id` FOREIGN KEY (`quota_usage_id`) REFERENCES `cloud_usage`.`quota_usage` (`id`));
-- Add the 'keep_mac_address_on_public_nic' column to the 'cloud.networks' and 'cloud.vpc' tables
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.networks', 'keep_mac_address_on_public_nic', 'TINYINT(1) NOT NULL DEFAULT 1');
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vpc', 'keep_mac_address_on_public_nic', 'TINYINT(1) NOT NULL DEFAULT 1');

View File

@ -2890,6 +2890,11 @@ public class ApiResponseHelper implements ResponseGenerator, ResourceIdSupport {
}
}
if (CallContext.current().getCallingAccount().getType() == Account.Type.ADMIN &&
network.getVpcId() == null && network.getGuestType() == Network.GuestType.Isolated) {
response.setKeepMacAddressOnPublicNic(network.getKeepMacAddressOnPublicNic());
}
response.setObjectName("network");
return response;
}
@ -3653,6 +3658,9 @@ public class ApiResponseHelper implements ResponseGenerator, ResourceIdSupport {
}
}
if (CallContext.current().getCallingAccount().getType() == Account.Type.ADMIN) {
response.setKeepMacAddressOnPublicNic(vpc.getKeepMacAddressOnPublicNic());
}
response.setObjectName("vpc");
return response;
}

View File

@ -301,7 +301,7 @@ public class NetworkMigrationManagerImpl implements NetworkMigrationManager {
copyOfVpc = _vpcService.createVpc(vpc.getZoneId(), vpcOfferingId, vpc.getAccountId(), vpc.getName(),
vpc.getDisplayText(), vpc.getCidr(), vpc.getNetworkDomain(), vpc.getIp4Dns1(), vpc.getIp4Dns2(),
vpc.getIp6Dns1(), vpc.getIp6Dns2(), vpc.isDisplay(), vpc.getPublicMtu(), null, null, null, vpc.useRouterIpAsResolver());
vpc.getIp6Dns1(), vpc.getIp6Dns2(), vpc.isDisplay(), vpc.getPublicMtu(), null, null, null, vpc.useRouterIpAsResolver(), vpc.getKeepMacAddressOnPublicNic());
copyOfVpcId = copyOfVpc.getId();
//on resume of migration the uuid will be swapped already. So the copy will have the value of the original vpcid.

View File

@ -1549,6 +1549,8 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
DataCenter zone = getAndValidateZone(cmd, pNtwk);
boolean keepMacAddressOnPublicNic = getAndValidateSupportForKeepMacAddressOnPublicNicParameter(cmd.getKeepMacAddressOnPublicNic(), ntwkOff);
_accountMgr.checkAccess(owner, ntwkOff, zone);
validateZoneAvailability(caller, zone);
@ -1834,7 +1836,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
Network network = commitNetwork(networkOfferingId, gateway, startIP, endIP, netmask, networkDomain, vlanId, bypassVlanOverlapCheck, name, displayText, caller, physicalNetworkId, zone.getId(),
domainId, isDomainSpecific, subdomainAccess, vpcId, startIPv6, endIPv6, ip6Gateway, ip6Cidr, displayNetwork, aclId, secondaryVlanId, privateVlanType, ntwkOff, pNtwk, aclType, owner, cidr, createVlan,
externalId, routerIPv4, routerIPv6, associatedNetwork, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2, interfaceMTUs, networkCidrSize);
externalId, routerIPv4, routerIPv6, associatedNetwork, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2, interfaceMTUs, networkCidrSize, keepMacAddressOnPublicNic);
// retrieve, acquire and associate the correct IP addresses
checkAndSetRouterSourceNatIp(owner, cmd, network);
@ -1879,6 +1881,24 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
}
}
protected boolean getAndValidateSupportForKeepMacAddressOnPublicNicParameter(Boolean keepMacAddressOnPublicNic, NetworkOffering networkOffering) {
if (networkOffering.isForVpc() && keepMacAddressOnPublicNic != null) {
throw new InvalidParameterValueException(
String.format("The [%s] parameter cannot be specified on the creation of VPC tiers.", ApiConstants.KEEP_MAC_ADDRESS_ON_PUBLIC_NIC)
);
}
GuestType guestType = networkOffering.getGuestType();
if (guestType != GuestType.Isolated && keepMacAddressOnPublicNic != null) {
throw new InvalidParameterValueException(String.format(
"The [%s] parameter can only be specified on the creation of [%s] networks.",
ApiConstants.KEEP_MAC_ADDRESS_ON_PUBLIC_NIC, GuestType.Isolated
));
}
return keepMacAddressOnPublicNic == null || keepMacAddressOnPublicNic;
}
@Override
@DB
@ActionEvent(eventType = EventTypes.EVENT_NETWORK_CREATE, eventDescription = "creating network")
@ -2282,7 +2302,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
final Boolean displayNetwork, final Long aclId, final String isolatedPvlan, final PVlanType isolatedPvlanType, final NetworkOffering ntwkOff, final PhysicalNetwork pNtwk, final ACLType aclType, final Account ownerFinal,
final String cidr, final boolean createVlan, final String externalId, String routerIp, String routerIpv6,
final Network associatedNetwork, final String ip4Dns1, final String ip4Dns2, final String ip6Dns1, final String ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs,
final Integer networkCidrSize) throws InsufficientCapacityException, ResourceAllocationException {
final Integer networkCidrSize, final boolean keepMacAddressOnPublicNic) throws InsufficientCapacityException, ResourceAllocationException {
try {
Network network = Transaction.execute(new TransactionCallbackWithException<Network, Exception>() {
@Override
@ -2348,7 +2368,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
}
network = _networkMgr.createGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId, bypassVlanOverlapCheck, networkDomain, owner, sharedDomainId, pNtwk,
zoneId, aclType, subdomainAccess, vpcId, ip6Gateway, ip6Cidr, displayNetwork, isolatedPvlan, isolatedPvlanType, externalId, routerIp, routerIpv6, ip4Dns1, ip4Dns2,
ip6Dns1, ip6Dns2, vrIfaceMTUs, networkCidrSize);
ip6Dns1, ip6Dns2, vrIfaceMTUs, networkCidrSize, keepMacAddressOnPublicNic);
}
if (createVlan && network != null) {
@ -3156,6 +3176,7 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
String ip4Dns2 = cmd.getIp4Dns2();
String ip6Dns1 = cmd.getIp6Dns1();
String ip6Dns2 = cmd.getIp6Dns2();
Boolean keepMacAddressOnPublicNic = cmd.getKeepMacAddressOnPublicNic();
boolean restartNetwork = false;
@ -3214,6 +3235,10 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
network.setUuid(customId);
}
if (keepMacAddressOnPublicNic != null) {
network.setKeepMacAddressOnPublicNic(getAndValidateSupportForKeepMacAddressOnPublicNicParameter(keepMacAddressOnPublicNic, offering));
}
// display flag is not null and has changed
if (displayNetwork != null && displayNetwork != network.getDisplayNetwork()) {
// Update resource count if it needs to be updated

View File

@ -737,55 +737,91 @@ public class NetworkHelperImpl implements NetworkHelper {
}
protected LinkedHashMap<Network, List<? extends NicProfile>> configurePublicNic(final RouterDeploymentDefinition routerDeploymentDefinition, final boolean hasGuestNic) throws InsufficientAddressCapacityException {
final LinkedHashMap<Network, List<? extends NicProfile>> publicConfig = new LinkedHashMap<Network, List<? extends NicProfile>>(3);
if (routerDeploymentDefinition.isPublicNetwork()) {
logger.debug("Adding NIC for Virtual Router in Public network ");
// if source nat service is supported by the network, get the source
// nat ip address
final NicProfile defaultNic = new NicProfile();
defaultNic.setDefaultNic(true);
final PublicIp sourceNatIp = routerDeploymentDefinition.getSourceNatIP();
defaultNic.setIPv4Address(sourceNatIp.getAddress().addr());
defaultNic.setIPv4Gateway(sourceNatIp.getGateway());
defaultNic.setIPv4Netmask(sourceNatIp.getNetmask());
defaultNic.setMacAddress(sourceNatIp.getMacAddress());
// get broadcast from public network
final Network pubNet = _networkDao.findById(sourceNatIp.getNetworkId());
if (pubNet.getBroadcastDomainType() == BroadcastDomainType.Vxlan) {
defaultNic.setBroadcastType(BroadcastDomainType.Vxlan);
defaultNic.setBroadcastUri(BroadcastDomainType.Vxlan.toUri(sourceNatIp.getVlanTag()));
defaultNic.setIsolationUri(BroadcastDomainType.Vxlan.toUri(sourceNatIp.getVlanTag()));
} else {
defaultNic.setBroadcastType(BroadcastDomainType.Vlan);
defaultNic.setBroadcastUri(sourceNatIp.getVlanTag() != null ? BroadcastDomainType.Vlan.toUri(sourceNatIp.getVlanTag()) : null);
defaultNic.setIsolationUri(sourceNatIp.getVlanTag() != null ? IsolationType.Vlan.toUri(sourceNatIp.getVlanTag()) : null);
}
//If guest nic has already been added we will have 2 devices in the list.
if (hasGuestNic) {
defaultNic.setDeviceId(2);
}
final NetworkOffering publicOffering = _networkModel.getSystemAccountNetworkOfferings(NetworkOffering.SystemPublicNetwork).get(0);
final List<? extends Network> publicNetworks = _networkMgr.setupNetwork(s_systemAccount, publicOffering, routerDeploymentDefinition.getPlan(), null, null, false);
final String publicIp = defaultNic.getIPv4Address();
// We want to use the identical MAC address for RvR on public
// interface if possible
final NicVO peerNic = _nicDao.findByIp4AddressAndNetworkId(publicIp, publicNetworks.get(0).getId());
if (peerNic != null) {
logger.info("Use same MAC as previous RvR, the MAC is " + peerNic.getMacAddress());
defaultNic.setMacAddress(peerNic.getMacAddress());
}
if (routerDeploymentDefinition.getGuestNetwork() != null) {
ipv6Service.updateNicIpv6(defaultNic, routerDeploymentDefinition.getDest().getDataCenter(), routerDeploymentDefinition.getGuestNetwork());
}
publicConfig.put(publicNetworks.get(0), new ArrayList<NicProfile>(Arrays.asList(defaultNic)));
final LinkedHashMap<Network, List<? extends NicProfile>> publicConfig = new LinkedHashMap<>(3);
if (!routerDeploymentDefinition.isPublicNetwork()) {
return publicConfig;
}
final PublicIp sourceNatIp = routerDeploymentDefinition.getSourceNatIP();
final NicProfile defaultNic = new NicProfile();
configurePublicVrNicBasedOnSourceNatIp(defaultNic, sourceNatIp);
if (hasGuestNic) {
logger.debug("Guest NIC has already been configured, therefore setting device ID of new VR (with source NAT [{}]) public NIC to [2].", sourceNatIp);
defaultNic.setDeviceId(2);
}
final NetworkOffering publicOffering = _networkModel.getSystemAccountNetworkOfferings(NetworkOffering.SystemPublicNetwork).get(0);
final List<? extends Network> publicNetworks = _networkMgr.setupNetwork(s_systemAccount, publicOffering, routerDeploymentDefinition.getPlan(), null, null, false);
setPublicNicMacAddressSameAsPeerNic(defaultNic, publicNetworks.get(0), routerDeploymentDefinition);
if (routerDeploymentDefinition.getGuestNetwork() != null) {
ipv6Service.updateNicIpv6(defaultNic, routerDeploymentDefinition.getDest().getDataCenter(), routerDeploymentDefinition.getGuestNetwork());
}
publicConfig.put(publicNetworks.get(0), List.of(defaultNic));
return publicConfig;
}
/**
* Configures the public NIC of a Virtual Router based on the provided source NAT IP.
* @param nic Virtual Router public NIC to be configured.
* @param sourceNatIp Source NAT IP which should be used to configure the Virtual Router's public NIC.
*/
protected void configurePublicVrNicBasedOnSourceNatIp(NicProfile nic, PublicIp sourceNatIp) {
logger.debug("Configuring public NIC of VR with source NAT IP equal to [{}]", sourceNatIp.getAddress().addr());
nic.setDefaultNic(true);
nic.setIPv4Address(sourceNatIp.getAddress().addr());
nic.setIPv4Gateway(sourceNatIp.getGateway());
nic.setIPv4Netmask(sourceNatIp.getNetmask());
nic.setMacAddress(sourceNatIp.getMacAddress());
Network publicNetwork = _networkDao.findById(sourceNatIp.getNetworkId());
if (publicNetwork.getBroadcastDomainType() == BroadcastDomainType.Vxlan) {
nic.setBroadcastType(BroadcastDomainType.Vxlan);
nic.setBroadcastUri(BroadcastDomainType.Vxlan.toUri(sourceNatIp.getVlanTag()));
nic.setIsolationUri(BroadcastDomainType.Vxlan.toUri(sourceNatIp.getVlanTag()));
} else {
nic.setBroadcastType(BroadcastDomainType.Vlan);
nic.setBroadcastUri(sourceNatIp.getVlanTag() != null ? BroadcastDomainType.Vlan.toUri(sourceNatIp.getVlanTag()) : null);
nic.setIsolationUri(sourceNatIp.getVlanTag() != null ? IsolationType.Vlan.toUri(sourceNatIp.getVlanTag()) : null);
}
}
/**
* Sets the MAC address of the new VR's public NIC the same as the previous VR's public NIC MAC address if
* {@link RouterDeploymentDefinition#getKeepMacAddressOnPublicNic()} is set to {@code true} and a peer NIC is found; otherwise,
* does nothing.
*/
protected void setPublicNicMacAddressSameAsPeerNic(NicProfile defaultNic, Network publicNetwork, RouterDeploymentDefinition routerDeploymentDefinition) throws InsufficientAddressCapacityException {
String publicIp = defaultNic.getIPv4Address();
logger.info("Verifying if we will use same MAC address for public NIC of new VR (with source NAT [{}]).", publicIp);
logger.debug("Searching for peer NIC for public IP [{}] and network [{}].", publicIp, publicNetwork.getUuid());
NicVO peerNic = _nicDao.findByIp4AddressAndNetworkId(publicIp, publicNetwork.getId());
if (peerNic == null) {
logger.info("We will not use the same MAC address for public NIC of new VR as we have not found a peer NIC for public IP [{}] and network [{}].",
publicIp, publicNetwork.getUuid());
return;
}
logger.info("Found peer NIC [{}] for public IP [{}] and network [{}].", peerNic.getUuid(), publicIp, publicNetwork.getUuid());
boolean keepMacAddressOnPublicNic = routerDeploymentDefinition.getKeepMacAddressOnPublicNic();
String macAddressLog = String.format("same MAC address for public NIC of new VR (with source NAT [%s]) as the [keep_mac_address_on_public_nic] property is configured as [%s].", publicIp, keepMacAddressOnPublicNic);
if (keepMacAddressOnPublicNic) {
logger.info("Using {}", macAddressLog);
defaultNic.setMacAddress(peerNic.getMacAddress());
return;
}
logger.info("Not using {}", macAddressLog);
boolean fetchNewMacAddress = peerNic.getMacAddress().equals(defaultNic.getMacAddress());
if (fetchNewMacAddress) {
logger.debug("Fetching new MAC address for public NIC of new VR, since the MAC address of the peer NIC [UUID: {}, MAC address: {}] is equal to the predefined MAC address of the current NIC.", peerNic.getUuid(), peerNic.getMacAddress());
routerDeploymentDefinition.findSourceNatIP();
configurePublicVrNicBasedOnSourceNatIp(defaultNic, routerDeploymentDefinition.getSourceNatIP());
}
}
@Override
public LinkedHashMap<Network, List<? extends NicProfile>> configureDefaultNics(final RouterDeploymentDefinition routerDeploymentDefinition) throws ConcurrentOperationException, InsufficientAddressCapacityException {

View File

@ -1568,7 +1568,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
@ActionEvent(eventType = EventTypes.EVENT_VPC_CREATE, eventDescription = "creating vpc", create = true)
public Vpc createVpc(final long zoneId, final long vpcOffId, final long vpcOwnerId, final String vpcName, final String displayText, final String cidr, String networkDomain,
final String ip4Dns1, final String ip4Dns2, final String ip6Dns1, final String ip6Dns2, final Boolean displayVpc, Integer publicMtu,
final Integer cidrSize, final Long asNumber, final List<Long> bgpPeerIds, Boolean useVrIpResolver) throws ResourceAllocationException {
final Integer cidrSize, final Long asNumber, final List<Long> bgpPeerIds, Boolean useVrIpResolver, boolean keepMacAddressOnPublicNic) throws ResourceAllocationException {
final Account caller = CallContext.current().getCallingAccount();
final Account owner = _accountMgr.getAccount(vpcOwnerId);
@ -1668,6 +1668,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
vpc.setPublicMtu(publicMtu);
vpc.setDisplay(Boolean.TRUE.equals(displayVpc));
vpc.setUseRouterIpResolver(Boolean.TRUE.equals(useVrIpResolver));
vpc.setKeepMacAddressOnPublicNic(keepMacAddressOnPublicNic);
try (CheckedReservation vpcReservation = new CheckedReservation(owner, ResourceType.vpc, null, null, 1L, reservationDao, _resourceLimitMgr)) {
if (vpc.getCidr() == null && cidrSize != null) {
@ -1728,7 +1729,8 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
List<Long> bgpPeerIds = (cmd instanceof CreateVPCCmdByAdmin) ? ((CreateVPCCmdByAdmin)cmd).getBgpPeerIds() : null;
Vpc vpc = createVpc(cmd.getZoneId(), cmd.getVpcOffering(), cmd.getEntityOwnerId(), cmd.getVpcName(), cmd.getDisplayText(),
cmd.getCidr(), cmd.getNetworkDomain(), cmd.getIp4Dns1(), cmd.getIp4Dns2(), cmd.getIp6Dns1(),
cmd.getIp6Dns2(), cmd.isDisplay(), cmd.getPublicMtu(), cmd.getCidrSize(), cmd.getAsNumber(), bgpPeerIds, cmd.getUseVrIpResolver());
cmd.getIp6Dns2(), cmd.isDisplay(), cmd.getPublicMtu(), cmd.getCidrSize(), cmd.getAsNumber(), bgpPeerIds,
cmd.getUseVrIpResolver(), cmd.getKeepMacAddressOnPublicNic());
String sourceNatIP = cmd.getSourceNatIP();
boolean forNsx = isVpcForProvider(Provider.Nsx, vpc);
@ -1940,12 +1942,14 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
@Override
public Vpc updateVpc(UpdateVPCCmd cmd) throws ResourceUnavailableException, InsufficientCapacityException {
return updateVpc(cmd.getId(), cmd.getVpcName(), cmd.getDisplayText(), cmd.getCustomId(), cmd.isDisplayVpc(), cmd.getPublicMtu(), cmd.getSourceNatIP());
return updateVpc(cmd.getId(), cmd.getVpcName(), cmd.getDisplayText(), cmd.getCustomId(),
cmd.isDisplayVpc(), cmd.getPublicMtu(), cmd.getSourceNatIP(), cmd.getKeepMacAddressOnPublicNic());
}
@Override
@ActionEvent(eventType = EventTypes.EVENT_VPC_UPDATE, eventDescription = "updating vpc")
public Vpc updateVpc(final long vpcId, final String vpcName, final String displayText, final String customId, final Boolean displayVpc, Integer mtu, String sourceNatIp) throws ResourceUnavailableException, InsufficientCapacityException {
public Vpc updateVpc(final long vpcId, final String vpcName, final String displayText, final String customId,
final Boolean displayVpc, Integer mtu, String sourceNatIp, Boolean keepMacAddressOnPublicNic) throws ResourceUnavailableException, InsufficientCapacityException {
final Account caller = CallContext.current().getCallingAccount();
// Verify input parameters
@ -1977,6 +1981,10 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
vpc.setDisplay(displayVpc);
}
if (keepMacAddressOnPublicNic != null) {
vpc.setKeepMacAddressOnPublicNic(keepMacAddressOnPublicNic);
}
mtu = validateMtu(vpcToUpdate, mtu);
if (mtu != null) {
updateMtuOfVpcNetwork(vpcToUpdate, vpc, mtu);

View File

@ -394,7 +394,7 @@ public class RouterDeploymentDefinition {
}
}
protected void findSourceNatIP() throws InsufficientAddressCapacityException, ConcurrentOperationException {
public void findSourceNatIP() throws InsufficientAddressCapacityException, ConcurrentOperationException {
sourceNatIp = null;
DataCenter zone = dest.getDataCenter();
Long zoneId = null;
@ -548,4 +548,8 @@ public class RouterDeploymentDefinition {
return needReset;
}
public boolean getKeepMacAddressOnPublicNic() {
return guestNetwork == null || guestNetwork.getKeepMacAddressOnPublicNic();
}
}

View File

@ -117,7 +117,7 @@ public class VpcRouterDeploymentDefinition extends RouterDeploymentDefinition {
}
@Override
protected void findSourceNatIP() throws InsufficientAddressCapacityException, ConcurrentOperationException {
public void findSourceNatIP() throws InsufficientAddressCapacityException, ConcurrentOperationException {
sourceNatIp = null;
DataCenter zone = dest.getDataCenter();
Long zoneId = null;
@ -219,4 +219,9 @@ public class VpcRouterDeploymentDefinition extends RouterDeploymentDefinition {
public boolean isRollingRestart() {
return vpc.isRollingRestart();
}
@Override
public boolean getKeepMacAddressOnPublicNic() {
return vpc == null || vpc.getKeepMacAddressOnPublicNic();
}
}

View File

@ -460,7 +460,7 @@ public class NetworkServiceImplTest {
null, null, false, null, accountMock, null, phyNet,
1L, null, null, null, null, null,
true, null, null, null, null, null,
null, null, null, null, new Pair<>(1500, privateMtu), null);
null, null, null, null, new Pair<>(1500, privateMtu), null, true);
}
@Test
public void testValidateMtuConfigWhenMtusExceedThreshold() {
@ -1330,4 +1330,52 @@ public class NetworkServiceImplTest {
Mockito.verify(accountJoin).addAnd("type", SearchCriteria.Op.EQ, Account.Type.PROJECT);
Mockito.verify(sc).addAnd("id", SearchCriteria.Op.SC, accountJoin);
}
@Test(expected = InvalidParameterValueException.class)
public void getAndValidateSupportForKeepMacAddressOnPublicNicParameterTestThrowExceptionWhenParamIsSpecifiedOnTiersCreation() {
networkOfferingVO = Mockito.mock(NetworkOfferingVO.class);
Mockito.when(networkOfferingVO.isForVpc()).thenReturn(true);
service.getAndValidateSupportForKeepMacAddressOnPublicNicParameter(true, networkOfferingVO);
}
@Test
public void getAndValidateSupportForKeepMacAddressOnPublicNicParameterTestReturnTrueByDefaultOnTiersCreation() {
networkOfferingVO = Mockito.mock(NetworkOfferingVO.class);
Mockito.when(networkOfferingVO.isForVpc()).thenReturn(true);
Assert.assertTrue(service.getAndValidateSupportForKeepMacAddressOnPublicNicParameter(null, networkOfferingVO));
}
@Test(expected = InvalidParameterValueException.class)
public void getAndValidateSupportForKeepMacAddressOnPublicNicParameterTestThrowExceptionWhenParamIsSpecifiedOnNonIsolatedNetworksCreation() {
networkOfferingVO = Mockito.mock(NetworkOfferingVO.class);
Mockito.when(networkOfferingVO.getGuestType()).thenReturn(Network.GuestType.Shared);
service.getAndValidateSupportForKeepMacAddressOnPublicNicParameter(true, networkOfferingVO);
}
@Test
public void getAndValidateSupportForKeepMacAddressOnPublicNicParameterTestReturnTrueByDefaultOnNonIsolatedNetworksCreation() {
networkOfferingVO = Mockito.mock(NetworkOfferingVO.class);
Mockito.when(networkOfferingVO.getGuestType()).thenReturn(Network.GuestType.L2);
Assert.assertTrue(service.getAndValidateSupportForKeepMacAddressOnPublicNicParameter(null, networkOfferingVO));
}
@Test
public void getAndValidateSupportForKeepMacAddressOnPublicNicParameterTestReturnTrueByDefaultOnIsolatedNetworksCreation() {
networkOfferingVO = Mockito.mock(NetworkOfferingVO.class);
Mockito.when(networkOfferingVO.getGuestType()).thenReturn(Network.GuestType.Isolated);
Assert.assertTrue(service.getAndValidateSupportForKeepMacAddressOnPublicNicParameter(null, networkOfferingVO));
}
@Test
public void getAndValidateSupportForKeepMacAddressOnPublicNicParameterTestReturnSpecifiedValueOnIsolatedNetworksCreation() {
networkOfferingVO = Mockito.mock(NetworkOfferingVO.class);
Mockito.when(networkOfferingVO.getGuestType()).thenReturn(Network.GuestType.Isolated);
Assert.assertFalse(service.getAndValidateSupportForKeepMacAddressOnPublicNicParameter(false, networkOfferingVO));
}
}

View File

@ -24,18 +24,31 @@ import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.lenient;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import com.cloud.deploy.DeployDestination;
import com.cloud.exception.InsufficientAddressCapacityException;
import com.cloud.network.Ipv6Service;
import com.cloud.network.Network;
import com.cloud.network.Networks;
import com.cloud.network.addr.PublicIp;
import com.cloud.network.dao.NetworkVO;
import com.cloud.offering.NetworkOffering;
import com.cloud.utils.net.Ip;
import com.cloud.vm.NicProfile;
import com.cloud.vm.NicVO;
import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService;
import org.apache.cloudstack.network.router.deployment.RouterDeploymentDefinition;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.Spy;
import org.mockito.junit.MockitoJUnitRunner;
import com.cloud.agent.AgentManager;
@ -57,6 +70,9 @@ import com.cloud.vm.VirtualMachineName;
import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.dao.NicDao;
import java.util.List;
import java.util.Map;
@RunWith(MockitoJUnitRunner.class)
public class NetworkHelperImplTest {
@ -69,32 +85,59 @@ public class NetworkHelperImplTest {
@Mock
DomainRouterDao routerDao;
@Spy
@InjectMocks
protected NetworkHelperImpl nwHelper = new NetworkHelperImpl();
protected NetworkHelperImpl networkHelperSpy = new NetworkHelperImpl();
@Mock
NetworkOrchestrationService networkOrchestrationService;
@Mock
NetworkDao networkDao;
@Mock
NetworkModel networkModel;
@Mock
NicDao nicDao;
private NicDao nicDaoMock;
@Mock
private RouterDeploymentDefinition routerDeploymentDefinition;
@Mock
private VirtualRouterProvider virtualProvider;
@Mock
private Account owner;
@Mock
private ServiceOfferingVO routerOffering;
@Mock
private VMTemplateVO template;
@Mock
private PublicIp publicIpMock;
@Mock
private RouterDeploymentDefinition routerDeploymentDefinitionMock;
@Mock
private Ipv6Service ipv6ServiceMock;
@Mock
private NicVO nicVoMock;
@Mock
private Network networkMock;
private NicProfile nicProfile = new NicProfile();
@Before
public void setUp() {
nwHelper._networkDao = networkDao;
nwHelper._networkModel = networkModel;
networkHelperSpy._networkDao = networkDao;
networkHelperSpy._networkModel = networkModel;
when(template.getId()).thenReturn(1L);
when(template.isDynamicallyScalable()).thenReturn(true);
when(virtualProvider.getId()).thenReturn(1L);
@ -107,7 +150,7 @@ public class NetworkHelperImplTest {
public void testSendCommandsToRouterWrongRouterVersion()
throws AgentUnavailableException, OperationTimedoutException, ResourceUnavailableException {
// Prepare
NetworkHelperImpl nwHelperUT = spy(this.nwHelper);
NetworkHelperImpl nwHelperUT = networkHelperSpy;
VirtualRouter vr = mock(VirtualRouter.class);
doReturn(false).when(nwHelperUT).checkRouterVersion(vr);
@ -122,7 +165,7 @@ public class NetworkHelperImplTest {
public void testSendCommandsToRouter()
throws AgentUnavailableException, OperationTimedoutException, ResourceUnavailableException {
// Prepare
NetworkHelperImpl nwHelperUT = spy(this.nwHelper);
NetworkHelperImpl nwHelperUT = networkHelperSpy;
VirtualRouter vr = mock(VirtualRouter.class);
when(vr.getHostId()).thenReturn(HOST_ID);
doReturn(true).when(nwHelperUT).checkRouterVersion(vr);
@ -160,7 +203,7 @@ public class NetworkHelperImplTest {
public void testSendCommandsToRouterWithTrueResult()
throws AgentUnavailableException, OperationTimedoutException, ResourceUnavailableException {
// Prepare
NetworkHelperImpl nwHelperUT = spy(this.nwHelper);
NetworkHelperImpl nwHelperUT = networkHelperSpy;
VirtualRouter vr = mock(VirtualRouter.class);
when(vr.getHostId()).thenReturn(HOST_ID);
doReturn(true).when(nwHelperUT).checkRouterVersion(vr);
@ -198,7 +241,7 @@ public class NetworkHelperImplTest {
public void testSendCommandsToRouterWithNoAnswers()
throws AgentUnavailableException, OperationTimedoutException, ResourceUnavailableException {
// Prepare
NetworkHelperImpl nwHelperUT = spy(this.nwHelper);
NetworkHelperImpl nwHelperUT = networkHelperSpy;
VirtualRouter vr = mock(VirtualRouter.class);
when(vr.getHostId()).thenReturn(HOST_ID);
doReturn(true).when(nwHelperUT).checkRouterVersion(vr);
@ -227,7 +270,7 @@ public class NetworkHelperImplTest {
boolean offerHA = false;
Long vpcId = 900L;
when(routerDao.persist(any(DomainRouterVO.class))).thenAnswer(invocation -> invocation.getArgument(0));
DomainRouterVO result = nwHelper.createOrUpdateDomainRouter(
DomainRouterVO result = networkHelperSpy.createOrUpdateDomainRouter(
null, id, routerDeploymentDefinition, owner, userId, routerOffering, offerHA, vpcId, template);
assertNotNull(result);
assertEquals(id, result.getId());
@ -261,11 +304,234 @@ public class NetworkHelperImplTest {
owner.getDomainId(), owner.getId(), userId, routerDeploymentDefinition.isRedundant(), VirtualRouter.RedundantState.UNKNOWN,
offerHA, false, vpcId);
existing.setDynamicallyScalable(false);
DomainRouterVO result = nwHelper.createOrUpdateDomainRouter(
DomainRouterVO result = networkHelperSpy.createOrUpdateDomainRouter(
existing, id, routerDeploymentDefinition, owner, userId, routerOffering, offerHA, vpcId, template);
verify(routerDao).update(existing.getId(), existing);
assertEquals(template.getId(), result.getTemplateId());
assertEquals(Hypervisor.HypervisorType.KVM, result.getHypervisorType());
assertTrue(result.isDynamicallyScalable());
}
private NicProfile getExpectedNicProfile(boolean vxlan, String vlanTag) {
NicProfile nic = new NicProfile();
nic.setDefaultNic(true);
nic.setIPv4Address("192.168.0.10");
nic.setIPv4Gateway("192.168.0.1");
nic.setIPv4Netmask("255.255.255.0");
nic.setMacAddress("ff-ff-ff-ff-ff-ff");
if (vxlan) {
nic.setBroadcastType(Networks.BroadcastDomainType.Vxlan);
nic.setBroadcastUri(Networks.BroadcastDomainType.Vxlan.toUri(vlanTag));
nic.setIsolationUri(Networks.BroadcastDomainType.Vxlan.toUri(vlanTag));
} else {
nic.setBroadcastType(Networks.BroadcastDomainType.Vlan);
nic.setBroadcastUri(vlanTag != null ? Networks.BroadcastDomainType.Vlan.toUri(vlanTag) : null);
nic.setIsolationUri(vlanTag != null ? Networks.IsolationType.Vlan.toUri(vlanTag) : null);
}
return nic;
}
@Test
public void configurePublicVrNicBasedOnSourceNatIpTestConfigureVxLanNic() {
String vlanTag = "200";
NicProfile expected = getExpectedNicProfile(true, vlanTag);
Ip ipMock = Mockito.mock(Ip.class);
NetworkVO publicNetworkMock = Mockito.mock(NetworkVO.class);
long networkId = 1L;
Mockito.when(publicIpMock.getAddress()).thenReturn(ipMock);
Mockito.when(ipMock.addr()).thenReturn(expected.getIPv4Address());
Mockito.when(publicIpMock.getGateway()).thenReturn(expected.getIPv4Gateway());
Mockito.when(publicIpMock.getNetmask()).thenReturn(expected.getIPv4Netmask());
Mockito.when(publicIpMock.getMacAddress()).thenReturn(expected.getMacAddress());
Mockito.when(publicIpMock.getNetworkId()).thenReturn(networkId);
Mockito.when(networkDao.findById(networkId)).thenReturn(publicNetworkMock);
Mockito.when(publicNetworkMock.getBroadcastDomainType()).thenReturn(Networks.BroadcastDomainType.Vxlan);
Mockito.when(publicIpMock.getVlanTag()).thenReturn(vlanTag);
networkHelperSpy.configurePublicVrNicBasedOnSourceNatIp(nicProfile, publicIpMock);
Assert.assertTrue(nicProfile.isDefaultNic());
Assert.assertEquals(expected.getIPv4Address(), nicProfile.getIPv4Address());
Assert.assertEquals(expected.getIPv4Gateway(), nicProfile.getIPv4Gateway());
Assert.assertEquals(expected.getIPv4Netmask(), nicProfile.getIPv4Netmask());
Assert.assertEquals(expected.getMacAddress(), nicProfile.getMacAddress());
Assert.assertEquals(expected.getBroadcastType(), nicProfile.getBroadcastType());
Assert.assertEquals(expected.getBroadCastUri(), nicProfile.getBroadCastUri());
Assert.assertEquals(expected.getIsolationUri(), nicProfile.getIsolationUri());
}
@Test
public void configurePublicVrNicBasedOnSourceNatIpTestConfigureVlanNicWithVlanTag() {
String vlanTag = "200";
NicProfile expected = getExpectedNicProfile(false, vlanTag);
Ip ipMock = Mockito.mock(Ip.class);
NetworkVO publicNetworkMock = Mockito.mock(NetworkVO.class);
long networkId = 1L;
Mockito.when(publicIpMock.getAddress()).thenReturn(ipMock);
Mockito.when(ipMock.addr()).thenReturn(expected.getIPv4Address());
Mockito.when(publicIpMock.getGateway()).thenReturn(expected.getIPv4Gateway());
Mockito.when(publicIpMock.getNetmask()).thenReturn(expected.getIPv4Netmask());
Mockito.when(publicIpMock.getMacAddress()).thenReturn(expected.getMacAddress());
Mockito.when(publicIpMock.getNetworkId()).thenReturn(networkId);
Mockito.when(networkDao.findById(networkId)).thenReturn(publicNetworkMock);
Mockito.when(publicNetworkMock.getBroadcastDomainType()).thenReturn(Networks.BroadcastDomainType.Vlan);
Mockito.when(publicIpMock.getVlanTag()).thenReturn(vlanTag);
networkHelperSpy.configurePublicVrNicBasedOnSourceNatIp(nicProfile, publicIpMock);
Assert.assertTrue(nicProfile.isDefaultNic());
Assert.assertEquals(expected.getIPv4Address(), nicProfile.getIPv4Address());
Assert.assertEquals(expected.getIPv4Gateway(), nicProfile.getIPv4Gateway());
Assert.assertEquals(expected.getIPv4Netmask(), nicProfile.getIPv4Netmask());
Assert.assertEquals(expected.getMacAddress(), nicProfile.getMacAddress());
Assert.assertEquals(expected.getBroadcastType(), nicProfile.getBroadcastType());
Assert.assertEquals(expected.getBroadCastUri(), nicProfile.getBroadCastUri());
Assert.assertEquals(expected.getIsolationUri(), nicProfile.getIsolationUri());
}
@Test
public void configurePublicVrNicBasedOnSourceNatIpTestConfigureVlanNicWithNoVlanTag() {
String vlanTag = null;
NicProfile expected = getExpectedNicProfile(false, vlanTag);
Ip ipMock = Mockito.mock(Ip.class);
NetworkVO publicNetworkMock = Mockito.mock(NetworkVO.class);
long networkId = 1L;
Mockito.when(publicIpMock.getAddress()).thenReturn(ipMock);
Mockito.when(ipMock.addr()).thenReturn(expected.getIPv4Address());
Mockito.when(publicIpMock.getGateway()).thenReturn(expected.getIPv4Gateway());
Mockito.when(publicIpMock.getNetmask()).thenReturn(expected.getIPv4Netmask());
Mockito.when(publicIpMock.getMacAddress()).thenReturn(expected.getMacAddress());
Mockito.when(publicIpMock.getNetworkId()).thenReturn(networkId);
Mockito.when(networkDao.findById(networkId)).thenReturn(publicNetworkMock);
Mockito.when(publicNetworkMock.getBroadcastDomainType()).thenReturn(Networks.BroadcastDomainType.Vlan);
Mockito.when(publicIpMock.getVlanTag()).thenReturn(vlanTag);
networkHelperSpy.configurePublicVrNicBasedOnSourceNatIp(nicProfile, publicIpMock);
Assert.assertTrue(nicProfile.isDefaultNic());
Assert.assertEquals(expected.getIPv4Address(), nicProfile.getIPv4Address());
Assert.assertEquals(expected.getIPv4Gateway(), nicProfile.getIPv4Gateway());
Assert.assertEquals(expected.getIPv4Netmask(), nicProfile.getIPv4Netmask());
Assert.assertEquals(expected.getMacAddress(), nicProfile.getMacAddress());
Assert.assertEquals(expected.getBroadcastType(), nicProfile.getBroadcastType());
Assert.assertEquals(expected.getBroadCastUri(), nicProfile.getBroadCastUri());
Assert.assertEquals(expected.getIsolationUri(), nicProfile.getIsolationUri());
}
@Test
public void setPublicNicMacAddressSameAsPeerNicTestDoNothingWhenThereIsNoPeer() throws InsufficientAddressCapacityException {
String newMacAddress = "ff-ff-ff-ff-ff-ff";
nicProfile.setIPv4Address("10.0.0.1");
nicProfile.setMacAddress(newMacAddress);
Mockito.when(nicDaoMock.findByIp4AddressAndNetworkId(Mockito.anyString(), Mockito.anyLong())).thenReturn(null);
networkHelperSpy.setPublicNicMacAddressSameAsPeerNic(nicProfile, networkMock, routerDeploymentDefinitionMock);
Assert.assertEquals(newMacAddress, nicProfile.getMacAddress());
}
@Test
public void setPublicNicMacAddressSameAsPeerNicTestKeepMacAddress() throws InsufficientAddressCapacityException {
String peerMacAddress = "ff-ff-ff-ff-ff-ff";
nicProfile.setIPv4Address("10.0.0.1");
nicProfile.setMacAddress("ff-ff-ff-ff-ff-f1");
Mockito.when(nicDaoMock.findByIp4AddressAndNetworkId(Mockito.anyString(), Mockito.anyLong())).thenReturn(nicVoMock);
Mockito.when(nicVoMock.getMacAddress()).thenReturn(peerMacAddress);
Mockito.when(routerDeploymentDefinitionMock.getKeepMacAddressOnPublicNic()).thenReturn(true);
networkHelperSpy.setPublicNicMacAddressSameAsPeerNic(nicProfile, networkMock, routerDeploymentDefinitionMock);
Assert.assertEquals(peerMacAddress, nicProfile.getMacAddress());
}
@Test
public void setPublicNicMacAddressSameAsPeerNicTestDifferentMacAddressFetchingNewSourceNatIp() throws InsufficientAddressCapacityException {
String macAddress = "ff-ff-ff-ff-ff-f1";
nicProfile.setIPv4Address("10.0.0.1");
nicProfile.setMacAddress(macAddress);
PublicIp publicIpMock = Mockito.mock(PublicIp.class);
Mockito.when(nicDaoMock.findByIp4AddressAndNetworkId(Mockito.anyString(), Mockito.anyLong())).thenReturn(nicVoMock);
Mockito.when(nicVoMock.getMacAddress()).thenReturn(macAddress);
Mockito.when(routerDeploymentDefinitionMock.getKeepMacAddressOnPublicNic()).thenReturn(false);
Mockito.when(routerDeploymentDefinitionMock.getSourceNatIP()).thenReturn(publicIpMock);
Mockito.doNothing().when(networkHelperSpy).configurePublicVrNicBasedOnSourceNatIp(nicProfile, publicIpMock);
networkHelperSpy.setPublicNicMacAddressSameAsPeerNic(nicProfile, networkMock, routerDeploymentDefinitionMock);
Mockito.verify(routerDeploymentDefinitionMock).findSourceNatIP();
Mockito.verify(networkHelperSpy).configurePublicVrNicBasedOnSourceNatIp(nicProfile, publicIpMock);
}
@Test
public void setPublicNicMacAddressSameAsPeerNicTestDifferentMacAddressNotFetchingNewSourceNatIp() throws InsufficientAddressCapacityException {
String newMacAddress = "ff-ff-ff-ff-ff-ff";
nicProfile.setIPv4Address("10.0.0.1");
nicProfile.setMacAddress(newMacAddress);
Mockito.when(nicDaoMock.findByIp4AddressAndNetworkId(Mockito.anyString(), Mockito.anyLong())).thenReturn(nicVoMock);
Mockito.when(nicVoMock.getMacAddress()).thenReturn("ff-ff-ff-ff-ff-f1");
Mockito.when(routerDeploymentDefinitionMock.getKeepMacAddressOnPublicNic()).thenReturn(false);
networkHelperSpy.setPublicNicMacAddressSameAsPeerNic(nicProfile, networkMock, routerDeploymentDefinitionMock);
Mockito.verify(routerDeploymentDefinitionMock, Mockito.never()).findSourceNatIP();
Mockito.verify(networkHelperSpy, Mockito.never()).configurePublicVrNicBasedOnSourceNatIp(Mockito.any(), Mockito.any());
Assert.assertEquals(newMacAddress, nicProfile.getMacAddress());
}
@Test
public void configurePublicNicTestReturnEmptyMapWhenNetworkIsNotPublic() throws InsufficientAddressCapacityException {
Mockito.when(routerDeploymentDefinitionMock.isPublicNetwork()).thenReturn(false);
Map<Network, List<? extends NicProfile>> nic = networkHelperSpy.configurePublicNic(routerDeploymentDefinitionMock, false);
Assert.assertTrue(nic.isEmpty());
}
@Test
public void configurePublicNicTestConfigureDeviceId() throws InsufficientAddressCapacityException {
PublicIp publicIpMock = Mockito.mock(PublicIp.class);
NetworkOffering networkOfferingMock = Mockito.mock(NetworkOffering.class);
Mockito.when(routerDeploymentDefinitionMock.isPublicNetwork()).thenReturn(true);
Mockito.when(routerDeploymentDefinitionMock.getSourceNatIP()).thenReturn(publicIpMock);
Mockito.doNothing().when(networkHelperSpy).configurePublicVrNicBasedOnSourceNatIp(Mockito.any(), Mockito.any());
Mockito.doReturn(List.of(networkOfferingMock)).when(networkModel).getSystemAccountNetworkOfferings(Mockito.any());
Mockito.doReturn(List.of(networkMock)).when(networkOrchestrationService).setupNetwork(
Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyBoolean()
);
Mockito.doNothing().when(networkHelperSpy).setPublicNicMacAddressSameAsPeerNic(Mockito.any(), Mockito.any(), Mockito.any());
Map<Network, List<? extends NicProfile>> nic = networkHelperSpy.configurePublicNic(routerDeploymentDefinitionMock, true);
Integer nicDeviceId = nic.get(networkMock).get(0).getDeviceId();
Assert.assertEquals(2, nicDeviceId.intValue());
}
@Test
public void configurePublicNicTestUpdateGuestNetworksIpv6Nic() throws InsufficientAddressCapacityException {
PublicIp publicIpMock = Mockito.mock(PublicIp.class);
NetworkOffering networkOfferingMock = Mockito.mock(NetworkOffering.class);
DeployDestination deployDestinationMock = Mockito.mock(DeployDestination.class);
Mockito.when(routerDeploymentDefinitionMock.isPublicNetwork()).thenReturn(true);
Mockito.when(routerDeploymentDefinitionMock.getSourceNatIP()).thenReturn(publicIpMock);
Mockito.doNothing().when(networkHelperSpy).configurePublicVrNicBasedOnSourceNatIp(Mockito.any(), Mockito.any());
Mockito.doReturn(List.of(networkOfferingMock)).when(networkModel).getSystemAccountNetworkOfferings(Mockito.any());
Mockito.doReturn(List.of(networkMock)).when(networkOrchestrationService).setupNetwork(
Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.any(), Mockito.anyBoolean()
);
Mockito.doNothing().when(networkHelperSpy).setPublicNicMacAddressSameAsPeerNic(Mockito.any(), Mockito.any(), Mockito.any());
Mockito.when(routerDeploymentDefinitionMock.getGuestNetwork()).thenReturn(networkMock);
Mockito.when(routerDeploymentDefinitionMock.getDest()).thenReturn(deployDestinationMock);
Map<Network, List<? extends NicProfile>> nic = networkHelperSpy.configurePublicNic(routerDeploymentDefinitionMock, false);
Mockito.verify(ipv6ServiceMock).updateNicIpv6(Mockito.eq(nic.get(networkMock).get(0)), Mockito.any(), Mockito.eq(networkMock));
}
}

View File

@ -492,7 +492,7 @@ public class VpcManagerImplTest {
mockVpcDnsResources(false, false);
try {
manager.createVpc(zoneId, vpcOfferingId, vpcOwnerId, vpcName, vpcName, ip4Cidr, vpcDomain,
ip4Dns[0], null, null, null, true, 1500, null, null, null, false);
ip4Dns[0], null, null, null, true, 1500, null, null, null, false, true);
} catch (ResourceAllocationException e) {
Assert.fail(String.format("failure with exception: %s", e.getMessage()));
}
@ -503,7 +503,7 @@ public class VpcManagerImplTest {
mockVpcDnsResources(true, false);
try {
manager.createVpc(zoneId, vpcOfferingId, vpcOwnerId, vpcName, vpcName, ip4Cidr, vpcDomain,
ip4Dns[0], ip4Dns[1], ip6Dns[0], null, true, 1500, null, null, null, false);
ip4Dns[0], ip4Dns[1], ip6Dns[0], null, true, 1500, null, null, null, false, true);
} catch (ResourceAllocationException e) {
Assert.fail(String.format("failure with exception: %s", e.getMessage()));
}
@ -517,7 +517,7 @@ public class VpcManagerImplTest {
Mockito.when(vpc.getUuid()).thenReturn("uuid");
try (MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
manager.createVpc(zoneId, vpcOfferingId, vpcOwnerId, vpcName, vpcName, ip4Cidr, vpcDomain,
ip4Dns[0], ip4Dns[1], null, null, true, 1500, null, null, null, false);
ip4Dns[0], ip4Dns[1], null, null, true, 1500, null, null, null, false, true);
} catch (ResourceAllocationException e) {
Assert.fail(String.format("failure with exception: %s", e.getMessage()));
}
@ -533,7 +533,7 @@ public class VpcManagerImplTest {
doNothing().when(routedIpv4Manager).getOrCreateIpv4SubnetForVpc(any(), anyString());
try (MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
manager.createVpc(zoneId, vpcOfferingId, vpcOwnerId, vpcName, vpcName, ip4Cidr, vpcDomain,
ip4Dns[0], ip4Dns[1], null, null, true, 1500, null, null, null, false);
ip4Dns[0], ip4Dns[1], null, null, true, 1500, null, null, null, false, true);
} catch (ResourceAllocationException e) {
Assert.fail(String.format("failure with exception: %s", e.getMessage()));
}
@ -556,7 +556,7 @@ public class VpcManagerImplTest {
try (MockedConstruction<CheckedReservation> mockCheckedReservation = Mockito.mockConstruction(CheckedReservation.class)) {
manager.createVpc(zoneId, vpcOfferingId, vpcOwnerId, vpcName, vpcName, null, vpcDomain,
ip4Dns[0], ip4Dns[1], null, null, true, 1500, 24, null, bgpPeerIds, false);
ip4Dns[0], ip4Dns[1], null, null, true, 1500, 24, null, bgpPeerIds, false, true);
} catch (ResourceAllocationException e) {
Assert.fail(String.format("failure with exception: %s", e.getMessage()));
}

View File

@ -704,11 +704,19 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches
public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, boolean bypassVlanOverlapCheck, String networkDomain,
Account owner, Long domainId, PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String gatewayv6,
String cidrv6, Boolean displayNetworkEnabled, String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId, String routerIp, String routerIpv6,
String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs, Integer networkCidrSize) throws ConcurrentOperationException, ResourceAllocationException {
String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs, Integer networkCidrSize) throws ConcurrentOperationException {
// TODO Auto-generated method stub
return null;
}
@Override
public Network createGuestNetwork(long networkOfferingId, String name, String displayText, String gateway, String cidr, String vlanId, boolean bypassVlanOverlapCheck, String networkDomain,
Account owner, Long domainId, PhysicalNetwork physicalNetwork, long zoneId, ACLType aclType, Boolean subdomainAccess, Long vpcId, String gatewayv6,
String cidrv6, Boolean displayNetworkEnabled, String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId, String routerIp, String routerIpv6,
String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2, Pair<Integer, Integer> vrIfaceMTUs, Integer networkCidrSize, boolean keepMacAddressOnPublicNic) throws ConcurrentOperationException {
return null;
}
/* (non-Javadoc)
* @see com.cloud.network.NetworkManager#getPasswordResetProvider(com.cloud.network.Network)
*/

View File

@ -1433,6 +1433,7 @@
"label.javadistribution": "Java Runtime Distribution",
"label.javaversion": "Java Runtime Version",
"label.keep": "Keep",
"label.keep.mac.address.on.public.nic": "Use same MAC address for public NIC of VRs",
"label.kernelversion": "Kernel Version",
"label.key": "Key",
"label.keyboard": "Keyboard language",

View File

@ -904,6 +904,7 @@
"label.items.selected": "item(ns) selecionados",
"label.japanese.keyboard": "Teclado japon\u00eas",
"label.keep": "Manter",
"label.keep.mac.address.on.public.nic": "Utilizar o mesmo endere\u00e7o MAC para a NIC p\u00fablica dos VRs",
"label.key": "Chave",
"label.keyboard": "Linguagem do teclado",
"label.keyboardtype": "Tipo de teclado",

View File

@ -49,9 +49,14 @@ export default {
return fields
},
details: () => {
var fields = ['name', 'id', 'description', 'type', 'traffictype', 'vpcid', 'vlan', 'broadcasturi', 'cidr', 'ip6cidr', 'netmask', 'gateway', 'asnumber', 'aclname', 'ispersistent', 'restartrequired', 'reservediprange', 'redundantrouter', 'networkdomain', 'egressdefaultpolicy', 'zonename', 'account', 'domainpath', 'associatednetwork', 'associatednetworkid', 'ip4routing', 'ip6firewall', 'ip6routing', 'ip6routes', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 'publicmtu', 'privatemtu']
if (!isAdmin()) {
fields = fields.filter(function (e) { return e !== 'broadcasturi' })
const fields = ['name', 'id', 'description', 'type', 'traffictype', 'vpcid', 'vlan', 'cidr', 'ip6cidr', 'netmask', 'gateway', 'asnumber', 'aclname', 'ispersistent', 'restartrequired', 'reservediprange', 'redundantrouter', 'networkdomain', 'egressdefaultpolicy', 'zonename', 'account', 'domainpath', 'associatednetwork', 'associatednetworkid', 'ip4routing', 'ip6firewall', 'ip6routing', 'ip6routes', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 'publicmtu', 'privatemtu']
if (isAdmin()) {
const vlanIndex = fields.findIndex(detail => detail === 'vlan')
fields.splice(vlanIndex + 1, 0, 'broadcasturi')
fields.push({
field: 'keepmacaddressonpublicnic',
customTitle: 'keep.mac.address.on.public.nic'
})
}
return fields
},
@ -233,7 +238,16 @@ export default {
fields.push(...['domain', 'zonename'])
return fields
},
details: ['name', 'id', 'displaytext', 'cidr', 'networkdomain', 'ip4routing', 'ip4routes', 'ip6routes', 'ispersistent', 'redundantvpcrouter', 'restartrequired', 'zonename', 'account', 'domain', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 'publicmtu'],
details: () => {
const fields = ['name', 'id', 'displaytext', 'cidr', 'networkdomain', 'ip4routing', 'ip4routes', 'ip6routes', 'ispersistent', 'redundantvpcrouter', 'restartrequired', 'zonename', 'account', 'domain', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 'publicmtu']
if (isAdmin()) {
fields.push({
field: 'keepmacaddressonpublicnic',
customTitle: 'keep.mac.address.on.public.nic'
})
}
return fields
},
searchFilters: ['name', 'zoneid', 'domainid', 'account', 'restartrequired', 'tags'],
related: [{
name: 'vm',
@ -268,7 +282,13 @@ export default {
icon: 'edit-outlined',
label: 'label.edit',
dataView: true,
args: ['name', 'displaytext', 'publicmtu', 'sourcenatipaddress']
args: () => {
const fields = ['name', 'displaytext', 'publicmtu', 'sourcenatipaddress']
if (isAdmin()) {
fields.push('keepmacaddressonpublicnic')
}
return fields
}
},
{
api: 'restartVPC',

View File

@ -294,6 +294,11 @@
:title="$t('label.default.network.' + field.name + '.isolated.network')"
:tooltip="field.description"
/>
<tooltip-label
v-else-if="field.name === 'keepmacaddressonpublicnic' && currentAction.api === 'updateVPC'"
:title="$t('label.keep.mac.address.on.public.nic')"
:tooltip="field.description"
/>
<tooltip-label
v-else
:title="$t('label.' + field.name)"

View File

@ -294,6 +294,15 @@
v-model:value="form.sourcenatipaddress"
:placeholder="apiParams.sourcenatipaddress?.description"/>
</a-form-item>
<a-form-item name="keepMacAddressOnPublicNic" ref="keepMacAddressOnPublicNic" v-if="isAdmin() && !selectedNetworkOffering?.forvpc">
<template #label>
<tooltip-label
:title="$t('label.keep.mac.address.on.public.nic')"
:tooltip="apiParams.keepmacaddressonpublicnic?.description"
/>
</template>
<a-switch v-model:checked="form.keepMacAddressOnPublicNic" />
</a-form-item>
<div :span="24" class="action-button">
<a-button
:loading="actionLoading"
@ -408,7 +417,9 @@ export default {
methods: {
initForm () {
this.formRef = ref()
this.form = reactive({})
this.form = reactive({
keepMacAddressOnPublicNic: true
})
this.rules = reactive({
name: [{ required: true, message: this.$t('message.error.name') }],
zoneid: [{ type: 'number', required: true, message: this.$t('message.error.select') }],
@ -600,14 +611,15 @@ export default {
const formRaw = toRaw(this.form)
const values = this.handleRemoveFields(formRaw)
this.actionLoading = true
var params = {
const params = {
zoneId: this.selectedZone.id,
name: values.name,
displayText: values.displaytext,
networkOfferingId: this.selectedNetworkOffering.id
networkOfferingId: this.selectedNetworkOffering.id,
keepmacaddressonpublicnic: values.keepMacAddressOnPublicNic
}
var usefulFields = ['gateway', 'netmask', 'cidrsize', 'startip', 'startipv4', 'endip', 'endipv4', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 'sourcenatipaddress', 'externalid', 'vpcid', 'vlan', 'networkdomain']
for (var field of usefulFields) {
const usefulFields = ['gateway', 'netmask', 'cidrsize', 'startip', 'startipv4', 'endip', 'endipv4', 'dns1', 'dns2', 'ip6dns1', 'ip6dns2', 'sourcenatipaddress', 'externalid', 'vpcid', 'vlan', 'networkdomain']
for (const field of usefulFields) {
if (this.isValidTextValueForKey(values, field)) {
params[field] = values[field]
}

View File

@ -202,6 +202,15 @@
v-model:value="form.sourcenatipaddress"
:placeholder="apiParams.sourcenatipaddress?.description"/>
</a-form-item>
<a-form-item name="keepMacAddressOnPublicNic" ref="keepMacAddressOnPublicNic" v-if="isAdmin()">
<template #label>
<tooltip-label
:title="$t('label.keep.mac.address.on.public.nic')"
:tooltip="apiParams.keepmacaddressonpublicnic?.description"
/>
</template>
<a-switch v-model:checked="form.keepMacAddressOnPublicNic" />
</a-form-item>
<a-form-item name="start" ref="start">
<template #label>
<tooltip-label :title="$t('label.start')" :tooltip="apiParams.start.description"/>
@ -287,7 +296,8 @@ export default {
initForm () {
this.formRef = ref()
this.form = reactive({
start: true
start: true,
keepMacAddressOnPublicNic: true
})
this.rules = reactive({
name: [{ required: true, message: this.$t('message.error.required.input') }],
@ -447,7 +457,7 @@ export default {
if (this.loading) return
this.formRef.value.validate().then(() => {
const values = toRaw(this.form)
var params = {}
const params = {}
if (this.owner?.account) {
params.account = this.owner.account
params.domainid = this.owner.domainid
@ -460,7 +470,11 @@ export default {
if (input === '' || input === null || input === undefined) {
continue
}
params[key] = input
if (key === 'keepMacAddressOnPublicNic') {
params.keepmacaddressonpublicnic = input
} else {
params[key] = input
}
}
if (this.selectedVpcOffering.networkmode === 'ROUTED') {
if ((values.cidr === undefined || values.cidr === '') && (values.cidrsize === undefined || values.cidrsize === '')) {

View File

@ -208,6 +208,15 @@
</template>
<a-switch v-model:checked="form.displaynetwork" />
</a-form-item>
<a-form-item name="keepMacAddressOnPublicNic" ref="keepMacAddressOnPublicNic" v-if="isAdmin() && isUpdatingIsolatedNetwork && !resource?.vpcid">
<template #label>
<tooltip-label
:title="$t('label.keep.mac.address.on.public.nic')"
:tooltip="apiParams.keepmacaddressonpublicnic?.description"
/>
</template>
<a-switch v-model:checked="form.keepMacAddressOnPublicNic" />
</a-form-item>
<a-form-item name="forced" ref="forced" v-if="isAdmin()">
<template #label>
<tooltip-label :title="$t('label.forced')" :tooltip="apiParams.forced.description"/>
@ -310,7 +319,8 @@ export default {
this.form = reactive({
displaynetwork: this.resource.displaynetwork,
privatemtu: this.resource.privatemtu,
publicmtu: this.resource.publicmtu
publicmtu: this.resource.publicmtu,
keepMacAddressOnPublicNic: this.resource.keepmacaddressonpublicnic
})
this.rules = reactive({
name: [{ required: true, message: this.$t('message.error.required.input') }],
@ -393,18 +403,20 @@ export default {
const formRaw = toRaw(this.form)
const values = this.handleRemoveFields(formRaw)
this.loading = true
var manualFields = ['name', 'networkofferingid']
const manualFields = ['name', 'networkofferingid']
const params = {
id: this.resource.id,
name: values.name
}
for (var field in values) {
for (const field in values) {
if (manualFields.includes(field)) continue
var fieldValue = values[field]
if (fieldValue !== undefined &&
fieldValue !== null &&
(!(field in this.resourceValues) || this.resourceValues[field] !== fieldValue)) {
params[field] = fieldValue
const fieldValue = values[field]
if (fieldValue !== undefined && fieldValue !== null && (!(field in this.resourceValues) || this.resourceValues[field] !== fieldValue)) {
if (field === 'keepMacAddressOnPublicNic') {
params.keepmacaddressonpublicnic = fieldValue
} else {
params[field] = fieldValue
}
}
}
if (values.networkofferingid !== undefined &&