mirror of https://github.com/apache/cloudstack.git
Merge 1caa367d87 into 74af9b9875
This commit is contained in:
commit
92a75f46ae
|
|
@ -146,6 +146,7 @@ jobs:
|
|||
smoke/test_vm_snapshot_kvm
|
||||
smoke/test_vm_snapshots
|
||||
smoke/test_volumes
|
||||
smoke/test_vpc_conserve_mode
|
||||
smoke/test_vpc_ipv6
|
||||
smoke/test_vpc_redundant
|
||||
smoke/test_vpc_router_nics
|
||||
|
|
|
|||
|
|
@ -279,4 +279,6 @@ public interface NetworkService {
|
|||
IpAddresses getIpAddressesFromIps(String ipAddress, String ip6Address, String macAddress);
|
||||
|
||||
String getNicVlanValueForExternalVm(NicTO nic);
|
||||
|
||||
Long getPreferredNetworkIdForPublicIpRuleAssignment(IpAddress ip, Long networkId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -84,4 +84,6 @@ public interface VpcOffering extends InternalIdentity, Identity {
|
|||
NetworkOffering.RoutingMode getRoutingMode();
|
||||
|
||||
Boolean isSpecifyAsNumber();
|
||||
|
||||
boolean isConserveMode();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ public interface VpcProvisioningService {
|
|||
Map serviceCapabilitystList, NetUtils.InternetProtocol internetProtocol,
|
||||
Long serviceOfferingId, String externalProvider, NetworkOffering.NetworkMode networkMode,
|
||||
List<Long> domainIds, List<Long> zoneIds, VpcOffering.State state,
|
||||
NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber);
|
||||
NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber, boolean conserveMode);
|
||||
|
||||
|
||||
Pair<List<? extends VpcOffering>,Integer> listVpcOfferings(ListVPCOfferingsCmd cmd);
|
||||
|
|
|
|||
|
|
@ -986,6 +986,7 @@ public class ApiConstants {
|
|||
public static final String REGION_ID = "regionid";
|
||||
public static final String VPC_OFF_ID = "vpcofferingid";
|
||||
public static final String VPC_OFF_NAME = "vpcofferingname";
|
||||
public static final String VPC_OFFERING_CONSERVE_MODE = "vpcofferingconservemode";
|
||||
public static final String NETWORK = "network";
|
||||
public static final String VPC_ID = "vpcid";
|
||||
public static final String VPC_NAME = "vpcname";
|
||||
|
|
|
|||
|
|
@ -161,6 +161,12 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd {
|
|||
description = "the routing mode for the VPC offering. Supported types are: Static or Dynamic.")
|
||||
private String routingMode;
|
||||
|
||||
@Parameter(name = ApiConstants.CONSERVE_MODE, type = CommandType.BOOLEAN,
|
||||
since = "4.23.0",
|
||||
description = "True if the VPC offering is IP conserve mode enabled, allowing public IPs to be used across multiple VPC tiers. Default value is false")
|
||||
private Boolean conserveMode;
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////
|
||||
/////////////////// Accessors ///////////////////////
|
||||
/////////////////////////////////////////////////////
|
||||
|
|
@ -311,6 +317,10 @@ public class CreateVPCOfferingCmd extends BaseAsyncCreateCmd {
|
|||
return routingMode;
|
||||
}
|
||||
|
||||
public boolean isConserveMode() {
|
||||
return BooleanUtils.toBoolean(conserveMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void create() throws ResourceAllocationException {
|
||||
VpcOffering vpcOff = _vpcProvSvc.createVpcOffering(this);
|
||||
|
|
|
|||
|
|
@ -54,7 +54,6 @@ import com.cloud.vm.VirtualMachine;
|
|||
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
|
||||
public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements PortForwardingRule {
|
||||
|
||||
|
||||
// ///////////////////////////////////////////////////
|
||||
// ////////////// API parameters /////////////////////
|
||||
// ///////////////////////////////////////////////////
|
||||
|
|
@ -278,13 +277,7 @@ public class CreatePortForwardingRuleCmd extends BaseAsyncCreateCmd implements P
|
|||
@Override
|
||||
public long getNetworkId() {
|
||||
IpAddress ip = _entityMgr.findById(IpAddress.class, getIpAddressId());
|
||||
Long ntwkId = null;
|
||||
|
||||
if (ip.getAssociatedWithNetworkId() != null) {
|
||||
ntwkId = ip.getAssociatedWithNetworkId();
|
||||
} else {
|
||||
ntwkId = networkId;
|
||||
}
|
||||
Long ntwkId = _networkService.getPreferredNetworkIdForPublicIpRuleAssignment(ip, networkId);
|
||||
if (ntwkId == null) {
|
||||
throw new InvalidParameterValueException("Unable to create port forwarding rule for the ipAddress id=" + ipAddressId +
|
||||
" as ip is not associated with any network and no networkId is passed in");
|
||||
|
|
|
|||
|
|
@ -102,6 +102,10 @@ public class VpcOfferingResponse extends BaseResponse {
|
|||
@Param(description = "The routing mode for the network offering, supported types are Static or Dynamic.")
|
||||
private String routingMode;
|
||||
|
||||
@SerializedName(ApiConstants.CONSERVE_MODE)
|
||||
@Param(description = "True if the VPC offering is IP conserve mode enabled, allowing public IP services to be used across multiple VPC tiers.", since = "4.23.0")
|
||||
private Boolean conserveMode;
|
||||
|
||||
public void setId(String id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
|
@ -201,4 +205,12 @@ public class VpcOfferingResponse extends BaseResponse {
|
|||
public void setRoutingMode(String routingMode) {
|
||||
this.routingMode = routingMode;
|
||||
}
|
||||
|
||||
public Boolean getConserveMode() {
|
||||
return conserveMode;
|
||||
}
|
||||
|
||||
public void setConserveMode(Boolean conserveMode) {
|
||||
this.conserveMode = conserveMode;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -73,6 +73,10 @@ public class VpcResponse extends BaseResponseWithAnnotations implements Controll
|
|||
@Param(description = "VPC offering name the VPC is created from", since = "4.13.2")
|
||||
private String vpcOfferingName;
|
||||
|
||||
@SerializedName(ApiConstants.VPC_OFFERING_CONSERVE_MODE)
|
||||
@Param(description = "true if VPC offering is ip conserve mode enabled", since = "4.23")
|
||||
private Boolean vpcOfferingConserveMode;
|
||||
|
||||
@SerializedName(ApiConstants.CREATED)
|
||||
@Param(description = "The date this VPC was created")
|
||||
private Date created;
|
||||
|
|
@ -197,6 +201,10 @@ public class VpcResponse extends BaseResponseWithAnnotations implements Controll
|
|||
this.displayText = displayText;
|
||||
}
|
||||
|
||||
public void setVpcOfferingConserveMode(Boolean vpcOfferingConserveMode) {
|
||||
this.vpcOfferingConserveMode = vpcOfferingConserveMode;
|
||||
}
|
||||
|
||||
public void setCreated(final Date created) {
|
||||
this.created = created;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -288,4 +288,6 @@ public interface IpAddressManager {
|
|||
PublicIpQuarantine updatePublicIpAddressInQuarantine(Long quarantineProcessId, Date endDate);
|
||||
|
||||
void updateSourceNatIpAddress(IPAddressVO requestedIp, List<IPAddressVO> userIps) throws Exception;
|
||||
|
||||
Long getPreferredNetworkIdForPublicIpRuleAssignment(IpAddress ip, Long networkId);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ import com.cloud.user.Account;
|
|||
public interface LoadBalancingRulesManager {
|
||||
|
||||
LoadBalancer createPublicLoadBalancer(String xId, String name, String description, int srcPort, int destPort, long sourceIpId, String protocol, String algorithm,
|
||||
boolean openFirewall, CallContext caller, String lbProtocol, Boolean forDisplay, String cidrList) throws NetworkRuleConflictException;
|
||||
boolean openFirewall, CallContext caller, String lbProtocol, Boolean forDisplay, String cidrList, Long networkId) throws NetworkRuleConflictException;
|
||||
|
||||
boolean removeAllLoadBalanacersForIp(long ipId, Account caller, long callerUserId);
|
||||
|
||||
|
|
|
|||
|
|
@ -211,4 +211,9 @@ public interface VpcManager {
|
|||
void reconfigStaticNatForVpcVr(Long vpcId);
|
||||
|
||||
boolean applyStaticRouteForVpcVpnIfNeeded(Long vpcId, boolean updateAllVpn) throws ResourceUnavailableException;
|
||||
|
||||
/**
|
||||
* Returns true if the network is part of a VPC, and the VPC is created from conserve mode enabled VPC offering
|
||||
*/
|
||||
boolean isNetworkOnVpcEnabledConserveMode(Network network);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -91,6 +91,9 @@ public class VpcOfferingVO implements VpcOffering {
|
|||
@Column(name = "specify_as_number")
|
||||
private Boolean specifyAsNumber = false;
|
||||
|
||||
@Column(name = "conserve_mode")
|
||||
private boolean conserveMode;
|
||||
|
||||
public VpcOfferingVO() {
|
||||
this.uuid = UUID.randomUUID().toString();
|
||||
}
|
||||
|
|
@ -242,4 +245,13 @@ public class VpcOfferingVO implements VpcOffering {
|
|||
public void setSpecifyAsNumber(Boolean specifyAsNumber) {
|
||||
this.specifyAsNumber = specifyAsNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConserveMode() {
|
||||
return conserveMode;
|
||||
}
|
||||
|
||||
public void setConserveMode(boolean conserveMode) {
|
||||
this.conserveMode = conserveMode;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -98,3 +98,6 @@ ALTER TABLE `cloud`.`user` DROP COLUMN api_key, DROP COLUMN secret_key;
|
|||
CALL `cloud`.`IDEMPOTENT_UPDATE_API_PERMISSION`('User', 'deleteUserKeys', 'ALLOW');
|
||||
CALL `cloud`.`IDEMPOTENT_UPDATE_API_PERMISSION`('Domain Admin', 'deleteUserKeys', 'ALLOW');
|
||||
CALL `cloud`.`IDEMPOTENT_UPDATE_API_PERMISSION`('Resource Admin', 'deleteUserKeys', 'ALLOW');
|
||||
|
||||
-- Add conserve mode for VPC offerings
|
||||
CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vpc_offerings','conserve_mode', 'tinyint(1) unsigned NULL DEFAULT 0 COMMENT ''True if the VPC offering is IP conserve mode enabled, allowing public IP services to be used across multiple VPC tiers'' ');
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ select
|
|||
`vpc_offerings`.`sort_key` AS `sort_key`,
|
||||
`vpc_offerings`.`routing_mode` AS `routing_mode`,
|
||||
`vpc_offerings`.`specify_as_number` AS `specify_as_number`,
|
||||
`vpc_offerings`.`conserve_mode` AS `conserve_mode`,
|
||||
group_concat(distinct `domain`.`id` separator ',') AS `domain_id`,
|
||||
group_concat(distinct `domain`.`uuid` separator ',') AS `domain_uuid`,
|
||||
group_concat(distinct `domain`.`name` separator ',') AS `domain_name`,
|
||||
|
|
|
|||
|
|
@ -363,7 +363,7 @@ public class LoadBalanceRuleHandler {
|
|||
lb.setSourceIpAddressId(ipId);
|
||||
|
||||
result = _lbMgr.createPublicLoadBalancer(lb.getXid(), lb.getName(), lb.getDescription(), lb.getSourcePortStart(), lb.getDefaultPortStart(), ipId.longValue(),
|
||||
lb.getProtocol(), lb.getAlgorithm(), false, CallContext.current(), lb.getLbProtocol(), true, null);
|
||||
lb.getProtocol(), lb.getAlgorithm(), false, CallContext.current(), lb.getLbProtocol(), true, null, networkId);
|
||||
} catch (final NetworkRuleConflictException e) {
|
||||
logger.warn("Failed to create LB rule, not continuing with ELB deployment");
|
||||
if (newIp) {
|
||||
|
|
|
|||
|
|
@ -293,7 +293,7 @@ public class ContrailManagerImpl extends ManagerBase implements ContrailManager
|
|||
}
|
||||
serviceProviderMap.put(svc, providerSet);
|
||||
}
|
||||
vpcOffer = _vpcProvSvc.createVpcOffering(juniperVPCOfferingName, juniperVPCOfferingDisplayText, services, serviceProviderMap, null, null, null, null, null, null, null, VpcOffering.State.Enabled, null, false);
|
||||
vpcOffer = _vpcProvSvc.createVpcOffering(juniperVPCOfferingName, juniperVPCOfferingDisplayText, services, serviceProviderMap, null, null, null, null, null, null, null, VpcOffering.State.Enabled, null, false, false);
|
||||
long id = vpcOffer.getId();
|
||||
_vpcOffDao.update(id, (VpcOfferingVO)vpcOffer);
|
||||
return _vpcOffDao.findById(id);
|
||||
|
|
|
|||
|
|
@ -3535,6 +3535,7 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
if (voff != null) {
|
||||
response.setVpcOfferingId(voff.getUuid());
|
||||
response.setVpcOfferingName(voff.getName());
|
||||
response.setVpcOfferingConserveMode(voff.isConserveMode());
|
||||
}
|
||||
response.setCidr(vpc.getCidr());
|
||||
response.setRestartRequired(vpc.isRestartRequired());
|
||||
|
|
|
|||
|
|
@ -77,6 +77,7 @@ public class VpcOfferingJoinDaoImpl extends GenericDaoBase<VpcOfferingJoinVO, Lo
|
|||
if (offering.isSpecifyAsNumber() != null) {
|
||||
offeringResponse.setSpecifyAsNumber(offering.isSpecifyAsNumber());
|
||||
}
|
||||
offeringResponse.setConserveMode(offering.isConserveMode());
|
||||
if (offering instanceof VpcOfferingJoinVO) {
|
||||
VpcOfferingJoinVO offeringJoinVO = (VpcOfferingJoinVO) offering;
|
||||
offeringResponse.setDomainId(offeringJoinVO.getDomainUuid());
|
||||
|
|
|
|||
|
|
@ -112,6 +112,9 @@ public class VpcOfferingJoinVO implements VpcOffering {
|
|||
@Column(name = "specify_as_number")
|
||||
private Boolean specifyAsNumber = false;
|
||||
|
||||
@Column(name = "conserve_mode")
|
||||
private boolean conserveMode;
|
||||
|
||||
public VpcOfferingJoinVO() {
|
||||
}
|
||||
|
||||
|
|
@ -178,6 +181,11 @@ public class VpcOfferingJoinVO implements VpcOffering {
|
|||
return specifyAsNumber;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConserveMode() {
|
||||
return conserveMode;
|
||||
}
|
||||
|
||||
public void setSpecifyAsNumber(Boolean specifyAsNumber) {
|
||||
this.specifyAsNumber = specifyAsNumber;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1543,6 +1543,14 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
|
|||
return ipaddr;
|
||||
}
|
||||
|
||||
protected IPAddressVO getExistingSourceNatInVPC(Long vpcId) {
|
||||
List<IPAddressVO> ips = _ipAddressDao.listByAssociatedVpc(vpcId, true);
|
||||
if (CollectionUtils.isEmpty(ips)) {
|
||||
return null;
|
||||
}
|
||||
return ips.get(0);
|
||||
}
|
||||
|
||||
protected IPAddressVO getExistingSourceNatInNetwork(long ownerId, Long networkId) {
|
||||
List<? extends IpAddress> addrs;
|
||||
Network guestNetwork = _networksDao.findById(networkId);
|
||||
|
|
@ -1723,7 +1731,11 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
|
|||
NetworkOffering offering = _networkOfferingDao.findById(network.getNetworkOfferingId());
|
||||
boolean sharedSourceNat = offering.isSharedSourceNat();
|
||||
boolean isSourceNat = false;
|
||||
if (!sharedSourceNat) {
|
||||
if (network.getVpcId() != null) {
|
||||
// For VPCs: Check if the VPC Source NAT IP address is the same we are associating
|
||||
IPAddressVO vpcSourceNatIpAddress = getExistingSourceNatInVPC(network.getVpcId());
|
||||
isSourceNat = vpcSourceNatIpAddress != null && vpcSourceNatIpAddress.getId() == ipToAssoc.getId();
|
||||
} else if (!sharedSourceNat) {
|
||||
if (getExistingSourceNatInNetwork(owner.getId(), network.getId()) == null) {
|
||||
if (network.getGuestType() == GuestType.Isolated && network.getVpcId() == null && !ipToAssoc.isPortable()) {
|
||||
isSourceNat = true;
|
||||
|
|
@ -2647,4 +2659,31 @@ public class IpAddressManagerImpl extends ManagerBase implements IpAddressManage
|
|||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getPreferredNetworkIdForPublicIpRuleAssignment(IpAddress ip, Long networkId) {
|
||||
boolean vpcConserveMode = isPublicIpOnVpcConserveMode(ip);
|
||||
return getPreferredNetworkIdForRule(ip, vpcConserveMode, networkId);
|
||||
}
|
||||
|
||||
protected Long getPreferredNetworkIdForRule(IpAddress ip, boolean vpcConserveModeEnabled, Long networkId) {
|
||||
if (vpcConserveModeEnabled) {
|
||||
// Since VPC Conserve mode allows rules from multiple VPC tiers, always check the networkId parameter first
|
||||
return networkId != null ? networkId : ip.getAssociatedWithNetworkId();
|
||||
} else {
|
||||
// In case of Guest Networks or VPC Tier Networks VPC Conserve mode disabled prefer the associated networkId
|
||||
return ip.getAssociatedWithNetworkId() != null ? ip.getAssociatedWithNetworkId() : networkId;
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean isPublicIpOnVpcConserveMode(IpAddress ip) {
|
||||
if (ip.getVpcId() == null) {
|
||||
return false;
|
||||
}
|
||||
Vpc vpc = _vpcMgr.getActiveVpc(ip.getVpcId());
|
||||
if (vpc == null) {
|
||||
return false;
|
||||
}
|
||||
VpcOffering vpcOffering = vpcOfferingDao.findById(vpc.getVpcOfferingId());
|
||||
return vpcOffering != null && vpcOffering.isConserveMode();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6434,6 +6434,11 @@ public class NetworkServiceImpl extends ManagerBase implements NetworkService, C
|
|||
return Networks.BroadcastDomainType.getValue(nic.getBroadcastUri());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getPreferredNetworkIdForPublicIpRuleAssignment(IpAddress ip, Long networkId) {
|
||||
return _ipAddrMgr.getPreferredNetworkIdForPublicIpRuleAssignment(ip, networkId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Network.IpAddresses getIpAddressesFromIps(String ipAddress, String ip6Address, String macAddress) {
|
||||
if (ip6Address != null) {
|
||||
|
|
|
|||
|
|
@ -30,6 +30,8 @@ import java.util.Set;
|
|||
import javax.inject.Inject;
|
||||
import javax.naming.ConfigurationException;
|
||||
|
||||
import com.cloud.network.vpc.Vpc;
|
||||
import com.cloud.network.vpc.dao.VpcOfferingDao;
|
||||
import org.apache.commons.lang3.ObjectUtils;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
|
@ -159,6 +161,8 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
|||
IpAddressManager _ipAddrMgr;
|
||||
@Inject
|
||||
RoutedIpv4Manager routedIpv4Manager;
|
||||
@Inject
|
||||
VpcOfferingDao vpcOfferingDao;
|
||||
|
||||
private boolean _elbEnabled = false;
|
||||
static Boolean rulesContinueOnErrFlag = true;
|
||||
|
|
@ -395,6 +399,10 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
|||
assert (rules.size() >= 1);
|
||||
}
|
||||
|
||||
NetworkVO newRuleNetwork = getNewRuleNetwork(newRule);
|
||||
boolean newRuleIsOnVpcNetwork = newRuleNetwork.getVpcId() != null;
|
||||
boolean vpcConserveModeEnabled = _vpcMgr.isNetworkOnVpcEnabledConserveMode(newRuleNetwork);
|
||||
|
||||
for (FirewallRuleVO rule : rules) {
|
||||
if (rule.getId() == newRule.getId()) {
|
||||
continue; // Skips my own rule.
|
||||
|
|
@ -443,8 +451,15 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
|||
}
|
||||
|
||||
// Checking if the rule applied is to the same network that is passed in the rule.
|
||||
if (rule.getNetworkId() != newRule.getNetworkId() && rule.getState() != State.Revoke) {
|
||||
throw new NetworkRuleConflictException("New rule is for a different network than what's specified in rule " + rule.getXid());
|
||||
// (except for VPCs with conserve mode = true)
|
||||
if ((!newRuleIsOnVpcNetwork || !vpcConserveModeEnabled)
|
||||
&& rule.getNetworkId() != newRule.getNetworkId() && rule.getState() != State.Revoke) {
|
||||
String errMsg = String.format("New rule is for a different network than what's specified in rule %s", rule.getXid());
|
||||
if (newRuleIsOnVpcNetwork) {
|
||||
Vpc vpc = _vpcMgr.getActiveVpc(newRuleNetwork.getVpcId());
|
||||
errMsg += String.format(" - VPC id=%s is not using conserve mode", vpc.getUuid());
|
||||
}
|
||||
throw new NetworkRuleConflictException(errMsg);
|
||||
}
|
||||
|
||||
//Check for the ICMP protocol. This has to be done separately from other protocols as we need to check the ICMP codes and ICMP type also.
|
||||
|
|
@ -493,6 +508,14 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService,
|
|||
}
|
||||
}
|
||||
|
||||
protected NetworkVO getNewRuleNetwork(FirewallRule newRule) {
|
||||
NetworkVO newRuleNetwork = _networkDao.findById(newRule.getNetworkId());
|
||||
if (newRuleNetwork == null) {
|
||||
throw new InvalidParameterValueException("Unable to create firewall rule as cannot find network by id=" + newRule.getNetworkId());
|
||||
}
|
||||
return newRuleNetwork;
|
||||
}
|
||||
|
||||
protected boolean checkIfRulesHaveConflictingPortRanges(FirewallRule newRule, FirewallRule rule, boolean oneOfRulesIsFirewall, boolean bothRulesFirewall, boolean bothRulesPortForwarding, boolean duplicatedCidrs) {
|
||||
String rulesAsString = String.format("[%s] and [%s]", rule, newRule);
|
||||
|
||||
|
|
|
|||
|
|
@ -1740,6 +1740,8 @@ public class LoadBalancingRulesManagerImpl<Type> extends ManagerBase implements
|
|||
throw new NetworkRuleConflictException("Can't do load balance on IP address: " + ipVO.getAddress());
|
||||
}
|
||||
|
||||
verifyLoadBalancerRuleNetwork(name, network, ipVO);
|
||||
|
||||
String cidrString = generateCidrString(cidrList);
|
||||
|
||||
boolean performedIpAssoc = false;
|
||||
|
|
@ -1763,7 +1765,7 @@ public class LoadBalancingRulesManagerImpl<Type> extends ManagerBase implements
|
|||
}
|
||||
|
||||
result = createPublicLoadBalancer(xId, name, description, srcPortStart, defPortStart, ipVO.getId(), protocol, algorithm, openFirewall, CallContext.current(),
|
||||
lbProtocol, forDisplay, cidrString);
|
||||
lbProtocol, forDisplay, cidrString, networkId);
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Failed to create load balancer due to ", ex);
|
||||
if (ex instanceof NetworkRuleConflictException) {
|
||||
|
|
@ -1792,7 +1794,18 @@ public class LoadBalancingRulesManagerImpl<Type> extends ManagerBase implements
|
|||
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
|
||||
protected void verifyLoadBalancerRuleNetwork(String lbName, Network network, IPAddressVO ipVO) {
|
||||
boolean isVpcConserveModeEnabled = _vpcMgr.isNetworkOnVpcEnabledConserveMode(network);
|
||||
if (!isVpcConserveModeEnabled && ipVO.getAssociatedWithNetworkId() != null && network.getId() != ipVO.getAssociatedWithNetworkId()) {
|
||||
String msg = String.format("Cannot create Load Balancer rule %s as the IP address %s is not associated " +
|
||||
"with the network %s (ID=%s)", lbName, ipVO.getAddress(), network.getName(), network.getUuid());
|
||||
logger.error(msg);
|
||||
throw new InvalidParameterValueException(msg);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transforms the cidrList from a List of Strings to a String which contains all the CIDRs from cidrList separated by whitespaces. This is used to facilitate both the persistence
|
||||
* in the DB and also later when building the configuration String in the getRulesForPool method of the HAProxyConfigurator class.
|
||||
*/
|
||||
|
|
@ -1826,7 +1839,7 @@ public class LoadBalancingRulesManagerImpl<Type> extends ManagerBase implements
|
|||
@Override
|
||||
public LoadBalancer createPublicLoadBalancer(final String xId, final String name, final String description, final int srcPort, final int destPort, final long sourceIpId,
|
||||
final String protocol, final String algorithm, final boolean openFirewall, final CallContext caller, final String lbProtocol,
|
||||
final Boolean forDisplay, String cidrList) throws NetworkRuleConflictException {
|
||||
final Boolean forDisplay, String cidrList, Long networkIdParam) throws NetworkRuleConflictException {
|
||||
if (!NetUtils.isValidPort(destPort)) {
|
||||
throw new InvalidParameterValueException("privatePort is an invalid value: " + destPort);
|
||||
}
|
||||
|
|
@ -1855,7 +1868,7 @@ public class LoadBalancingRulesManagerImpl<Type> extends ManagerBase implements
|
|||
|
||||
_accountMgr.checkAccess(caller.getCallingAccount(), null, true, ipAddr);
|
||||
|
||||
final Long networkId = ipAddr.getAssociatedWithNetworkId();
|
||||
final Long networkId = _ipAddrMgr.getPreferredNetworkIdForPublicIpRuleAssignment(ipAddr, networkIdParam);
|
||||
if (networkId == null) {
|
||||
InvalidParameterValueException ex =
|
||||
new InvalidParameterValueException("Unable to create load balancer rule ; specified sourceip id is not associated with any network");
|
||||
|
|
|
|||
|
|
@ -388,7 +388,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
}
|
||||
createVpcOffering(VpcOffering.defaultVPCOfferingName, VpcOffering.defaultVPCOfferingName, svcProviderMap,
|
||||
true, State.Enabled, null, false,
|
||||
false, false, null, null, false);
|
||||
false, false, null, null, false, false);
|
||||
}
|
||||
|
||||
// configure default vpc offering with Netscaler as LB Provider
|
||||
|
|
@ -408,7 +408,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
}
|
||||
}
|
||||
createVpcOffering(VpcOffering.defaultVPCNSOfferingName, VpcOffering.defaultVPCNSOfferingName,
|
||||
svcProviderMap, false, State.Enabled, null, false, false, false, null, null, false);
|
||||
svcProviderMap, false, State.Enabled, null, false, false, false, null, null, false, false);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -429,7 +429,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
}
|
||||
}
|
||||
createVpcOffering(VpcOffering.redundantVPCOfferingName, VpcOffering.redundantVPCOfferingName, svcProviderMap, true, State.Enabled,
|
||||
null, false, false, true, null, null, false);
|
||||
null, false, false, true, null, null, false, false);
|
||||
}
|
||||
|
||||
// configure default vpc offering with NSX as network service provider in NAT mode
|
||||
|
|
@ -446,7 +446,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
}
|
||||
}
|
||||
createVpcOffering(VpcOffering.DEFAULT_VPC_NAT_NSX_OFFERING_NAME, VpcOffering.DEFAULT_VPC_NAT_NSX_OFFERING_NAME, svcProviderMap, false,
|
||||
State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.NATTED, null, false);
|
||||
State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.NATTED, null, false, false);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -464,7 +464,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
}
|
||||
}
|
||||
createVpcOffering(VpcOffering.DEFAULT_VPC_ROUTE_NSX_OFFERING_NAME, VpcOffering.DEFAULT_VPC_ROUTE_NSX_OFFERING_NAME, svcProviderMap, false,
|
||||
State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.ROUTED, null, false);
|
||||
State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.ROUTED, null, false, false);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -482,7 +482,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
}
|
||||
}
|
||||
createVpcOffering(VpcOffering.DEFAULT_VPC_ROUTE_NETRIS_OFFERING_NAME, VpcOffering.DEFAULT_VPC_ROUTE_NETRIS_OFFERING_NAME, svcProviderMap, false,
|
||||
State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.ROUTED, null, false);
|
||||
State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.ROUTED, null, false, false);
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -500,7 +500,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
}
|
||||
}
|
||||
createVpcOffering(VpcOffering.DEFAULT_VPC_NAT_NETRIS_OFFERING_NAME, VpcOffering.DEFAULT_VPC_NAT_NETRIS_OFFERING_NAME, svcProviderMap, false,
|
||||
State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.NATTED, null, false);
|
||||
State.Enabled, null, false, false, false, NetworkOffering.NetworkMode.NATTED, null, false, false);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -586,6 +586,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
}
|
||||
boolean specifyAsNumber = cmd.getSpecifyAsNumber();
|
||||
String routingModeString = cmd.getRoutingMode();
|
||||
boolean conserveMode = cmd.isConserveMode();
|
||||
|
||||
// check if valid domain
|
||||
if (CollectionUtils.isNotEmpty(cmd.getDomainIds())) {
|
||||
|
|
@ -624,7 +625,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
|
||||
return createVpcOffering(vpcOfferingName, displayText, supportedServices,
|
||||
serviceProviderList, serviceCapabilityList, internetProtocol, serviceOfferingId, provider, networkMode,
|
||||
domainIds, zoneIds, (enable ? State.Enabled : State.Disabled), routingMode, specifyAsNumber);
|
||||
domainIds, zoneIds, (enable ? State.Enabled : State.Disabled), routingMode, specifyAsNumber, conserveMode);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -632,7 +633,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
public VpcOffering createVpcOffering(final String name, final String displayText, final List<String> supportedServices, final Map<String, List<String>> serviceProviders,
|
||||
final Map serviceCapabilityList, final NetUtils.InternetProtocol internetProtocol, final Long serviceOfferingId,
|
||||
final String externalProvider, final NetworkOffering.NetworkMode networkMode, List<Long> domainIds, List<Long> zoneIds, State state,
|
||||
NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber) {
|
||||
NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber, boolean conserveMode) {
|
||||
|
||||
if (!Ipv6Service.Ipv6OfferingCreationEnabled.value() && !(internetProtocol == null || NetUtils.InternetProtocol.IPv4.equals(internetProtocol))) {
|
||||
throw new InvalidParameterValueException(String.format("Configuration %s needs to be enabled for creating IPv6 supported VPC offering", Ipv6Service.Ipv6OfferingCreationEnabled.key()));
|
||||
|
|
@ -727,7 +728,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
final boolean offersRegionLevelVPC = isVpcOfferingForRegionLevelVpc(serviceCapabilityList);
|
||||
final boolean redundantRouter = isVpcOfferingRedundantRouter(serviceCapabilityList, redundantRouterService);
|
||||
final VpcOfferingVO offering = createVpcOffering(name, displayText, svcProviderMap, false, state, serviceOfferingId, supportsDistributedRouter, offersRegionLevelVPC,
|
||||
redundantRouter, networkMode, routingMode, specifyAsNumber);
|
||||
redundantRouter, networkMode, routingMode, specifyAsNumber, conserveMode);
|
||||
|
||||
if (offering != null) {
|
||||
List<VpcOfferingDetailsVO> detailsVO = new ArrayList<>();
|
||||
|
|
@ -755,7 +756,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
@DB
|
||||
protected VpcOfferingVO createVpcOffering(final String name, final String displayText, final Map<Service, Set<Provider>> svcProviderMap,
|
||||
final boolean isDefault, final State state, final Long serviceOfferingId, final boolean supportsDistributedRouter, final boolean offersRegionLevelVPC,
|
||||
final boolean redundantRouter, NetworkOffering.NetworkMode networkMode, NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber) {
|
||||
final boolean redundantRouter, NetworkOffering.NetworkMode networkMode, NetworkOffering.RoutingMode routingMode, boolean specifyAsNumber, boolean conserveMode) {
|
||||
|
||||
return Transaction.execute(new TransactionCallback<VpcOfferingVO>() {
|
||||
@Override
|
||||
|
|
@ -771,6 +772,7 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
if (Objects.nonNull(routingMode)) {
|
||||
offering.setRoutingMode(routingMode);
|
||||
}
|
||||
offering.setConserveMode(conserveMode);
|
||||
|
||||
logger.debug("Adding vpc offering " + offering);
|
||||
offering = _vpcOffDao.persist(offering);
|
||||
|
|
@ -2954,6 +2956,20 @@ public class VpcManagerImpl extends ManagerBase implements VpcManager, VpcProvis
|
|||
return true;
|
||||
}
|
||||
|
||||
protected boolean isNetworkOnVpc(Network network) {
|
||||
return network.getVpcId() != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isNetworkOnVpcEnabledConserveMode(Network newRuleNetwork) {
|
||||
if (isNetworkOnVpc(newRuleNetwork)) {
|
||||
Vpc vpc = getActiveVpc(newRuleNetwork.getVpcId());
|
||||
VpcOfferingVO vpcOffering = vpc != null ? _vpcOffDao.findById(vpc.getVpcOfferingId()) : null;
|
||||
return vpcOffering != null && vpcOffering.isConserveMode();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected boolean applyStaticRoutes(final List<StaticRouteVO> routes, final Account caller, final boolean updateRoutesInDB) throws ResourceUnavailableException {
|
||||
final boolean success = true;
|
||||
final List<StaticRouteProfile> staticRouteProfiles = getVpcStaticRoutes(routes);
|
||||
|
|
|
|||
|
|
@ -24,13 +24,18 @@ import com.cloud.network.Network;
|
|||
import com.cloud.network.NetworkModel;
|
||||
import com.cloud.network.NetworkRuleApplier;
|
||||
import com.cloud.network.dao.FirewallRulesDao;
|
||||
import com.cloud.network.dao.NetworkDao;
|
||||
import com.cloud.network.dao.NetworkVO;
|
||||
import com.cloud.network.element.FirewallServiceProvider;
|
||||
import com.cloud.network.element.VirtualRouterElement;
|
||||
import com.cloud.network.element.VpcVirtualRouterElement;
|
||||
import com.cloud.network.rules.FirewallRule;
|
||||
import com.cloud.network.rules.FirewallRule.Purpose;
|
||||
import com.cloud.network.rules.FirewallRuleVO;
|
||||
import com.cloud.network.vpc.Vpc;
|
||||
import com.cloud.network.vpc.VpcManager;
|
||||
import com.cloud.network.vpc.VpcOfferingVO;
|
||||
import com.cloud.network.vpc.dao.VpcOfferingDao;
|
||||
import com.cloud.user.AccountManager;
|
||||
import com.cloud.user.DomainManager;
|
||||
import com.cloud.utils.component.ComponentContext;
|
||||
|
|
@ -43,6 +48,7 @@ import org.junit.Test;
|
|||
import org.junit.runner.RunWith;
|
||||
import org.mockito.InjectMocks;
|
||||
import org.mockito.Mock;
|
||||
import org.mockito.Mockito;
|
||||
import org.mockito.MockitoAnnotations;
|
||||
import org.mockito.Spy;
|
||||
import org.mockito.junit.MockitoJUnitRunner;
|
||||
|
|
@ -76,6 +82,10 @@ public class FirewallManagerTest {
|
|||
IpAddressManager _ipAddrMgr;
|
||||
@Mock
|
||||
FirewallRulesDao _firewallDao;
|
||||
@Mock
|
||||
NetworkDao _networkDao;
|
||||
@Mock
|
||||
VpcOfferingDao vpcOfferingDao;
|
||||
|
||||
@Spy
|
||||
@InjectMocks
|
||||
|
|
@ -163,50 +173,102 @@ public class FirewallManagerTest {
|
|||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetectRulesConflict() {
|
||||
List<FirewallRuleVO> ruleList = new ArrayList<FirewallRuleVO>();
|
||||
FirewallRuleVO rule1 = spy(new FirewallRuleVO("rule1", 3, 500, "UDP", 1, 2, 1, Purpose.Vpn, null, null, null, null));
|
||||
FirewallRuleVO rule2 = spy(new FirewallRuleVO("rule2", 3, 1701, "UDP", 1, 2, 1, Purpose.Vpn, null, null, null, null));
|
||||
FirewallRuleVO rule3 = spy(new FirewallRuleVO("rule3", 3, 4500, "UDP", 1, 2, 1, Purpose.Vpn, null, null, null, null));
|
||||
private List<FirewallRuleVO> createExistingFirewallListRulesList(long existingNetworkId) {
|
||||
List<FirewallRuleVO> ruleList = new ArrayList<>();
|
||||
FirewallRuleVO rule1 = spy(new FirewallRuleVO("rule1", 3, 500, "UDP", existingNetworkId, 2, 1, Purpose.Vpn, null, null, null, null));
|
||||
FirewallRuleVO rule2 = spy(new FirewallRuleVO("rule2", 3, 1701, "UDP", existingNetworkId, 2, 1, Purpose.Vpn, null, null, null, null));
|
||||
FirewallRuleVO rule3 = spy(new FirewallRuleVO("rule3", 3, 4500, "UDP", existingNetworkId, 2, 1, Purpose.Vpn, null, null, null, null));
|
||||
|
||||
List<String> sString = Arrays.asList("10.1.1.1/24","192.168.1.1/24");
|
||||
List<String> dString1 = Arrays.asList("10.1.1.1/25");
|
||||
List<String> dString2 = Arrays.asList("10.1.1.128/25");
|
||||
|
||||
FirewallRuleVO rule4 = spy(new FirewallRuleVO("rule4", 3L, 10, 20, "TCP", 1, 2, 1, Purpose.Firewall, sString, dString1, null, null,
|
||||
FirewallRuleVO rule4 = spy(new FirewallRuleVO("rule4", 3L, 10, 20, "TCP", existingNetworkId, 2, 1, Purpose.Firewall, sString, dString1, null, null,
|
||||
null, FirewallRule.TrafficType.Egress));
|
||||
|
||||
when(rule1.getId()).thenReturn(1L);
|
||||
when(rule2.getId()).thenReturn(2L);
|
||||
when(rule3.getId()).thenReturn(3L);
|
||||
when(rule4.getId()).thenReturn(4L);
|
||||
|
||||
ruleList.add(rule1);
|
||||
ruleList.add(rule2);
|
||||
ruleList.add(rule3);
|
||||
ruleList.add(rule4);
|
||||
|
||||
FirewallManagerImpl firewallMgr = (FirewallManagerImpl)_firewallMgr;
|
||||
return ruleList;
|
||||
}
|
||||
|
||||
when(firewallMgr._firewallDao.listByIpAndPurposeAndNotRevoked(3,null)).thenReturn(ruleList);
|
||||
when(rule1.getId()).thenReturn(1L);
|
||||
when(rule2.getId()).thenReturn(2L);
|
||||
when(rule3.getId()).thenReturn(3L);
|
||||
when(rule4.getId()).thenReturn(4L);
|
||||
private List<FirewallRule> createNewRuleList(long newNetworkId) {
|
||||
List<String> sString = Arrays.asList("10.1.1.1/24","192.168.1.1/24");
|
||||
List<String> dString2 = Arrays.asList("10.1.1.128/25");
|
||||
|
||||
FirewallRule newRule1 = new FirewallRuleVO("newRule1", 3, 500, "TCP", 1, 2, 1, Purpose.PortForwarding, null, null, null, null);
|
||||
FirewallRule newRule2 = new FirewallRuleVO("newRule2", 3, 1701, "TCP", 1, 2, 1, Purpose.PortForwarding, null, null, null, null);
|
||||
FirewallRule newRule3 = new FirewallRuleVO("newRule3", 3, 4500, "TCP", 1, 2, 1, Purpose.PortForwarding, null, null, null, null);
|
||||
FirewallRule newRule4 = new FirewallRuleVO("newRule4", 3L, 15, 25, "TCP", 1, 2, 1, Purpose.Firewall, sString, dString2, null, null,
|
||||
FirewallRule newRule1 = new FirewallRuleVO("newRule1", 3, 500, "TCP", newNetworkId, 2, 1, Purpose.PortForwarding, null, null, null, null);
|
||||
FirewallRule newRule2 = new FirewallRuleVO("newRule2", 3, 1701, "TCP", newNetworkId, 2, 1, Purpose.PortForwarding, null, null, null, null);
|
||||
FirewallRule newRule3 = new FirewallRuleVO("newRule3", 3, 4500, "TCP", newNetworkId, 2, 1, Purpose.PortForwarding, null, null, null, null);
|
||||
FirewallRule newRule4 = new FirewallRuleVO("newRule4", 3L, 15, 25, "TCP", newNetworkId, 2, 1, Purpose.Firewall, sString, dString2, null, null,
|
||||
null, FirewallRule.TrafficType.Egress);
|
||||
return Arrays.asList(newRule1, newRule2, newRule3, newRule4);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetectRulesConflictIsolatedNetwork() {
|
||||
List<FirewallRuleVO> ruleList = createExistingFirewallListRulesList(1L);
|
||||
when(_firewallMgr._firewallDao.listByIpAndPurposeAndNotRevoked(3,null)).thenReturn(ruleList);
|
||||
|
||||
List<FirewallRule> newRuleList = createNewRuleList(1L);
|
||||
|
||||
NetworkVO networkVO = Mockito.mock(NetworkVO.class);
|
||||
when(_firewallMgr._networkDao.findById(1L)).thenReturn(networkVO);
|
||||
when(networkVO.getVpcId()).thenReturn(null);
|
||||
|
||||
try {
|
||||
firewallMgr.detectRulesConflict(newRule1);
|
||||
firewallMgr.detectRulesConflict(newRule2);
|
||||
firewallMgr.detectRulesConflict(newRule3);
|
||||
firewallMgr.detectRulesConflict(newRule4);
|
||||
for (FirewallRule newRule : newRuleList) {
|
||||
_firewallMgr.detectRulesConflict(newRule);
|
||||
}
|
||||
}
|
||||
catch (NetworkRuleConflictException ex) {
|
||||
Assert.fail();
|
||||
}
|
||||
}
|
||||
|
||||
private void testDetectRulesConflictVpcBase(boolean vpcConserveMode) throws NetworkRuleConflictException {
|
||||
long existingNetworkId = 1L;
|
||||
long newNetworkId = 2L;
|
||||
long vpcId = 10L;
|
||||
|
||||
List<FirewallRuleVO> ruleList = createExistingFirewallListRulesList(existingNetworkId);
|
||||
when(_firewallMgr._firewallDao.listByIpAndPurposeAndNotRevoked(3,null)).thenReturn(ruleList);
|
||||
|
||||
List<FirewallRule> newRuleList = createNewRuleList(newNetworkId);
|
||||
|
||||
NetworkVO newNetworkVO = Mockito.mock(NetworkVO.class);
|
||||
Vpc vpc = Mockito.mock(Vpc.class);
|
||||
VpcOfferingVO vpcOffering = Mockito.mock(VpcOfferingVO.class);
|
||||
|
||||
when(_firewallMgr._networkDao.findById(2L)).thenReturn(newNetworkVO);
|
||||
when(newNetworkVO.getVpcId()).thenReturn(vpcId);
|
||||
when(_vpcMgr.getActiveVpc(vpcId)).thenReturn(vpc);
|
||||
when(vpc.getVpcOfferingId()).thenReturn(1L);
|
||||
when(vpcOfferingDao.findById(1L)).thenReturn(vpcOffering);
|
||||
when(vpcOffering.isConserveMode()).thenReturn(vpcConserveMode);
|
||||
|
||||
for (FirewallRule newRule : newRuleList) {
|
||||
_firewallMgr.detectRulesConflict(newRule);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDetectRulesConflictVpcConserveMode() throws NetworkRuleConflictException {
|
||||
// When VPC conserve mode is enabled, rules can be created for multiple network tiers
|
||||
testDetectRulesConflictVpcBase(true);
|
||||
}
|
||||
|
||||
@Test(expected = NetworkRuleConflictException.class)
|
||||
public void testDetectRulesConflictVpcConserveModeFalse() throws NetworkRuleConflictException {
|
||||
// When VPC conserve mode is disabled, an exception should be thrown when attempting to create rules on different network tiers
|
||||
testDetectRulesConflictVpcBase(false);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkIfRulesHaveConflictingPortRangesTestOnlyOneRuleIsFirewallReturnsFalse()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -581,4 +581,27 @@ public class VpcManagerImplTest {
|
|||
Assert.assertThrows(InvalidParameterValueException.class, () -> manager.validateVpcPrivateGatewayAclId(vpcId, differentVpcAclId));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsNetworkOnVpcEnabledConserveModeIsolatedNetwork() {
|
||||
Network network = mock(Network.class);
|
||||
Mockito.when(network.getVpcId()).thenReturn(null);
|
||||
Assert.assertFalse(manager.isNetworkOnVpcEnabledConserveMode(network));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testIsNetworkOnVpcEnabledConserveModeVpcNetworkConserveMode() {
|
||||
Network network = mock(Network.class);
|
||||
Vpc vpc = mock(Vpc.class);
|
||||
VpcOfferingVO vpcOffering = mock(VpcOfferingVO.class);
|
||||
long vpcId = 10L;
|
||||
long vpcOfferingId = 11L;
|
||||
|
||||
Mockito.when(network.getVpcId()).thenReturn(vpcId);
|
||||
Mockito.when(vpcDao.getActiveVpcById(Mockito.eq(vpcId))).thenReturn(vpc);
|
||||
Mockito.when(vpc.getVpcOfferingId()).thenReturn(vpcOfferingId);
|
||||
Mockito.when(vpcOfferingDao.findById(Mockito.eq(vpcOfferingId))).thenReturn(vpcOffering);
|
||||
Mockito.when(vpcOffering.isConserveMode()).thenReturn(true);
|
||||
Assert.assertTrue(manager.isNetworkOnVpcEnabledConserveMode(network));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1148,4 +1148,9 @@ public class MockNetworkManagerImpl extends ManagerBase implements NetworkOrches
|
|||
public String getNicVlanValueForExternalVm(NicTO nic) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long getPreferredNetworkIdForPublicIpRuleAssignment(IpAddress ip, Long networkId) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,9 +28,16 @@ from marvin.lib.utils import (isAlmostEqual,
|
|||
from marvin.lib.base import (Domain,
|
||||
VpcOffering,
|
||||
Account,
|
||||
VPC)
|
||||
VPC,
|
||||
NetworkOffering,
|
||||
Network,
|
||||
VirtualMachine,
|
||||
ServiceOffering,
|
||||
PublicIPAddress,
|
||||
NATRule)
|
||||
from marvin.lib.common import (get_domain,
|
||||
get_zone)
|
||||
get_zone,
|
||||
get_test_template)
|
||||
from nose.plugins.attrib import attr
|
||||
|
||||
import time
|
||||
|
|
@ -222,6 +229,7 @@ class TestDomainsVpcOfferings(cloudstackTestCase):
|
|||
cls.apiclient = testClient.getApiClient()
|
||||
cls.localservices = Services().services
|
||||
cls.services = testClient.getParsedTestDataConfig()
|
||||
cls.hypervisor = cls.testClient.getHypervisorInfo()
|
||||
# Create domains
|
||||
cls.domain_1 = Domain.create(
|
||||
cls.apiclient,
|
||||
|
|
@ -402,3 +410,158 @@ class TestDomainsVpcOfferings(cloudstackTestCase):
|
|||
self.debug("Vpc created for first child subdomain %s" % self.valid_account_3.domainid)
|
||||
|
||||
return
|
||||
|
||||
@attr(
|
||||
tags=[
|
||||
"advanced",
|
||||
"eip",
|
||||
"sg",
|
||||
"advancedns",
|
||||
"smoke"],
|
||||
required_hardware="false")
|
||||
def test_04_validate_vpc_offering_conserve_mode_disabled(self):
|
||||
"""Test to create and validate vpc with conserve mode disabled for an existing domain specified vpc offering"""
|
||||
|
||||
# Validate the following:
|
||||
# 1. Create Vpc for user in domain for which offering is specified
|
||||
# 2. Validate that conserve mode is disabled for the vpc (cannot reuse ip address on multiple VPC tiers)
|
||||
|
||||
template = get_test_template(
|
||||
self.apiclient,
|
||||
self.zone.id,
|
||||
self.hypervisor)
|
||||
if template == FAILED:
|
||||
assert False, "get_test_template() failed to return template"
|
||||
|
||||
valid_account_1 = Account.create(
|
||||
self.apiclient,
|
||||
self.services["account"],
|
||||
domainid=self.domain_1.id
|
||||
)
|
||||
self.cleanup.append(valid_account_1)
|
||||
|
||||
service_offering = ServiceOffering.create(
|
||||
self.apiclient,
|
||||
self.services["service_offerings"]["tiny"]
|
||||
)
|
||||
self.cleanup.append(service_offering)
|
||||
|
||||
self.services["vpc"]["cidr"] = "10.10.20.0/24"
|
||||
vpc = VPC.create(
|
||||
apiclient=self.apiclient,
|
||||
services=self.services["vpc"],
|
||||
account=valid_account_1.name,
|
||||
domainid=valid_account_1.domainid,
|
||||
zoneid=self.zone.id,
|
||||
vpcofferingid=self.vpc_offering.id
|
||||
)
|
||||
self.debug("Vpc created for subdomain %s" % valid_account_1.domainid)
|
||||
|
||||
self.services["network_offering"]["supportedservices"] = 'Vpn,Dhcp,Dns,SourceNat,Lb,UserData,StaticNat,NetworkACL,PortForwarding'
|
||||
self.services["network_offering"]["serviceProviderList"] = {
|
||||
"Vpn": 'VpcVirtualRouter',
|
||||
"Dhcp": 'VpcVirtualRouter',
|
||||
"Dns": 'VpcVirtualRouter',
|
||||
"SourceNat": 'VpcVirtualRouter',
|
||||
"Lb": 'VpcVirtualRouter',
|
||||
"UserData": 'VpcVirtualRouter',
|
||||
"StaticNat": 'VpcVirtualRouter',
|
||||
"NetworkACL": 'VpcVirtualRouter',
|
||||
"PortForwarding": 'VpcVirtualRouter'
|
||||
}
|
||||
network_offering = NetworkOffering.create(
|
||||
self.apiclient,
|
||||
self.services["network_offering"]
|
||||
)
|
||||
network_offering.update(self.apiclient, state="Enabled")
|
||||
self.cleanup.append(network_offering)
|
||||
|
||||
gateway_tier1 = "10.10.20.1"
|
||||
netmask_tiers = "255.255.255.240"
|
||||
|
||||
self.services["network_offering"]["name"] = "tier1-" + vpc.id
|
||||
self.services["network_offering"]["displayname"] = "tier1-" + vpc.id
|
||||
tier1 = Network.create(
|
||||
self.apiclient,
|
||||
services=self.services["network_offering"],
|
||||
accountid=valid_account_1.name,
|
||||
domainid=valid_account_1.domainid,
|
||||
networkofferingid=network_offering.id,
|
||||
zoneid=self.zone.id,
|
||||
vpcid=vpc.id,
|
||||
gateway=gateway_tier1,
|
||||
netmask=netmask_tiers,
|
||||
)
|
||||
|
||||
gateway_tier2 = "10.10.20.17"
|
||||
self.services["network_offering"]["name"] = "tier2-" + vpc.id
|
||||
self.services["network_offering"]["displayname"] = "tier2-" + vpc.id
|
||||
tier2 = Network.create(
|
||||
self.apiclient,
|
||||
services=self.services["network_offering"],
|
||||
accountid=valid_account_1.name,
|
||||
domainid=valid_account_1.domainid,
|
||||
networkofferingid=network_offering.id,
|
||||
zoneid=self.zone.id,
|
||||
vpcid=vpc.id,
|
||||
gateway=gateway_tier2,
|
||||
netmask=netmask_tiers,
|
||||
)
|
||||
|
||||
self.services["virtual_machine"]["displayname"] = "vm1" + vpc.id
|
||||
vm1 = VirtualMachine.create(
|
||||
self.apiclient,
|
||||
services=self.services["virtual_machine"],
|
||||
templateid=template.id,
|
||||
zoneid=self.zone.id,
|
||||
accountid=valid_account_1.name,
|
||||
domainid=valid_account_1.domainid,
|
||||
serviceofferingid=service_offering.id,
|
||||
networkids=[tier1.id],
|
||||
)
|
||||
|
||||
self.services["virtual_machine"]["displayname"] = "vm2" + vpc.id
|
||||
vm2 = VirtualMachine.create(
|
||||
self.apiclient,
|
||||
services=self.services["virtual_machine"],
|
||||
templateid=template.id,
|
||||
zoneid=self.zone.id,
|
||||
accountid=valid_account_1.name,
|
||||
domainid=valid_account_1.domainid,
|
||||
serviceofferingid=service_offering.id,
|
||||
networkids=[tier2.id],
|
||||
)
|
||||
|
||||
public_ip = PublicIPAddress.create(
|
||||
self.apiclient,
|
||||
zoneid=self.zone.id,
|
||||
accountid=valid_account_1.name,
|
||||
domainid=valid_account_1.domainid,
|
||||
vpcid=vpc.id,
|
||||
)
|
||||
|
||||
nat_rule = NATRule.create(
|
||||
self.apiclient,
|
||||
vm1,
|
||||
self.services["natrule"],
|
||||
ipaddressid=public_ip.ipaddress.id,
|
||||
vpcid=vpc.id,
|
||||
networkid=tier1.id,
|
||||
)
|
||||
|
||||
self.services["natrule"]["privateport"] = 80
|
||||
self.services["natrule"]["publicport"] = 80
|
||||
try:
|
||||
NATRule.create(
|
||||
self.apiclient,
|
||||
vm2,
|
||||
self.services["natrule"],
|
||||
ipaddressid=public_ip.ipaddress.id,
|
||||
vpcid=vpc.id,
|
||||
networkid=tier2.id,
|
||||
)
|
||||
self.fail(
|
||||
"Expected cross-tier rule creation to fail with conserveMode=False, but succeeded"
|
||||
)
|
||||
except CloudstackAPIException as e:
|
||||
self.debug("Expected cross-tier rule creation to failure with conserveMode=False")
|
||||
|
|
|
|||
|
|
@ -0,0 +1,314 @@
|
|||
# Licensed to the Apache Software Foundation (ASF) under one
|
||||
# or more contributor license agreements. See the NOTICE file
|
||||
# distributed with this work for additional information
|
||||
# regarding copyright ownership. The ASF licenses this file
|
||||
# to you under the Apache License, Version 2.0 (the
|
||||
# "License"); you may not use this file except in compliance
|
||||
# with the License. You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing,
|
||||
# software distributed under the License is distributed on an
|
||||
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
# KIND, either express or implied. See the License for the
|
||||
# specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""Tests for VPC Conserve Mode (since 4.23.0)
|
||||
|
||||
Conserve mode allows public IP services (LB, Port Forwarding, Static NAT) to be
|
||||
shared across multiple VPC tiers using the same public IP address.
|
||||
|
||||
When conserve mode is ON:
|
||||
- A single public IP can have rules targeting VMs in different VPC tiers
|
||||
- FirewallManagerImpl skips the cross-network conflict check for that VPC
|
||||
|
||||
When conserve mode is OFF (default before 4.23.0):
|
||||
- Rules on a given public IP must all belong to the same VPC tier (network)
|
||||
- Attempting to create a rule on a different tier than an existing rule raises
|
||||
a NetworkRuleConflictException
|
||||
"""
|
||||
|
||||
from marvin.cloudstackException import CloudstackAPIException
|
||||
from marvin.cloudstackTestCase import cloudstackTestCase
|
||||
from marvin.codes import FAILED
|
||||
from marvin.lib.base import (
|
||||
Account,
|
||||
LoadBalancerRule,
|
||||
NATRule,
|
||||
Network,
|
||||
NetworkOffering,
|
||||
PublicIPAddress,
|
||||
ServiceOffering,
|
||||
VirtualMachine,
|
||||
VPC,
|
||||
VpcOffering,
|
||||
)
|
||||
from marvin.lib.common import (
|
||||
get_domain,
|
||||
get_test_template,
|
||||
get_zone,
|
||||
list_publicIP
|
||||
)
|
||||
from marvin.lib.utils import cleanup_resources
|
||||
from nose.plugins.attrib import attr
|
||||
import logging
|
||||
|
||||
class TestVPCConserveModeRules(cloudstackTestCase):
|
||||
"""Tests that conserve mode for VPC controls whether rules on the same public IP are allowed in multiple VPC tiers.
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.testClient = super(TestVPCConserveModeRules, cls).getClsTestClient()
|
||||
cls.apiclient = cls.testClient.getApiClient()
|
||||
cls.services = cls.testClient.getParsedTestDataConfig()
|
||||
cls.zone = get_zone(cls.apiclient, cls.testClient.getZoneForTests())
|
||||
cls.domain = get_domain(cls.apiclient)
|
||||
cls.hypervisor = cls.testClient.getHypervisorInfo()
|
||||
cls.logger = logging.getLogger("TestVPCConserveModeRules")
|
||||
cls._cleanup = []
|
||||
|
||||
cls.account = Account.create(
|
||||
cls.apiclient,
|
||||
cls.services["account"],
|
||||
admin=True,
|
||||
domainid=cls.domain.id)
|
||||
cls._cleanup.append(cls.account)
|
||||
|
||||
cls.template = get_test_template(
|
||||
cls.apiclient,
|
||||
cls.zone.id,
|
||||
cls.hypervisor)
|
||||
if cls.template == FAILED:
|
||||
assert False, "get_test_template() failed to return template"
|
||||
|
||||
cls.service_offering = ServiceOffering.create(
|
||||
cls.apiclient,
|
||||
cls.services["service_offerings"]["tiny"]
|
||||
)
|
||||
cls._cleanup.append(cls.service_offering)
|
||||
|
||||
cls.services["vpc_offering"]["supportedservices"] = 'Vpn,Dhcp,Dns,SourceNat,Lb,UserData,StaticNat,NetworkACL,PortForwarding'
|
||||
cls.services["vpc_offering"]["conservemode"] = True
|
||||
cls.vpc_offering_conserve_mode = VpcOffering.create(
|
||||
cls.apiclient,
|
||||
cls.services["vpc_offering"]
|
||||
)
|
||||
cls.vpc_offering_conserve_mode.update(cls.apiclient, state="Enabled")
|
||||
cls._cleanup.append(cls.vpc_offering_conserve_mode)
|
||||
|
||||
cls.services["network_offering"]["supportedservices"] = 'Vpn,Dhcp,Dns,SourceNat,Lb,UserData,StaticNat,NetworkACL,PortForwarding'
|
||||
cls.services["network_offering"]["serviceProviderList"] = {
|
||||
"Vpn": 'VpcVirtualRouter',
|
||||
"Dhcp": 'VpcVirtualRouter',
|
||||
"Dns": 'VpcVirtualRouter',
|
||||
"SourceNat": 'VpcVirtualRouter',
|
||||
"Lb": 'VpcVirtualRouter',
|
||||
"UserData": 'VpcVirtualRouter',
|
||||
"StaticNat": 'VpcVirtualRouter',
|
||||
"NetworkACL": 'VpcVirtualRouter',
|
||||
"PortForwarding": 'VpcVirtualRouter'
|
||||
}
|
||||
cls.network_offering = NetworkOffering.create(
|
||||
cls.apiclient,
|
||||
cls.services["network_offering"],
|
||||
conservemode=True
|
||||
)
|
||||
cls.network_offering.update(cls.apiclient, state="Enabled")
|
||||
cls._cleanup.append(cls.network_offering)
|
||||
|
||||
cls.services["vpc"]["cidr"] = "10.10.20.0/24"
|
||||
|
||||
cls.vpc = VPC.create(
|
||||
cls.apiclient,
|
||||
cls.services["vpc"],
|
||||
vpcofferingid=cls.vpc_offering_conserve_mode.id,
|
||||
zoneid=cls.zone.id,
|
||||
account=cls.account.name,
|
||||
domainid=cls.account.domainid,
|
||||
)
|
||||
cls._cleanup.append(cls.vpc)
|
||||
|
||||
gateway_tier1 = "10.10.20.1"
|
||||
netmask_tiers = "255.255.255.240"
|
||||
|
||||
cls.services["network_offering"]["name"] = "tier1-" + cls.vpc.id
|
||||
cls.services["network_offering"]["displayname"] = "tier1-" + cls.vpc.id
|
||||
cls.tier1 = Network.create(
|
||||
cls.apiclient,
|
||||
services=cls.services["network_offering"],
|
||||
accountid=cls.account.name,
|
||||
domainid=cls.account.domainid,
|
||||
networkofferingid=cls.network_offering.id,
|
||||
zoneid=cls.zone.id,
|
||||
vpcid=cls.vpc.id,
|
||||
gateway=gateway_tier1,
|
||||
netmask=netmask_tiers,
|
||||
)
|
||||
cls._cleanup.append(cls.tier1)
|
||||
|
||||
gateway_tier2 = "10.10.20.17"
|
||||
cls.services["network_offering"]["name"] = "tier2-" + cls.vpc.id
|
||||
cls.services["network_offering"]["displayname"] = "tier2-" + cls.vpc.id
|
||||
cls.tier2 = Network.create(
|
||||
cls.apiclient,
|
||||
services=cls.services["network_offering"],
|
||||
accountid=cls.account.name,
|
||||
domainid=cls.account.domainid,
|
||||
networkofferingid=cls.network_offering.id,
|
||||
zoneid=cls.zone.id,
|
||||
vpcid=cls.vpc.id,
|
||||
gateway=gateway_tier2,
|
||||
netmask=netmask_tiers,
|
||||
)
|
||||
cls._cleanup.append(cls.tier2)
|
||||
|
||||
cls.services["virtual_machine"]["displayname"] = "vm1" + cls.vpc.id
|
||||
cls.vm1 = VirtualMachine.create(
|
||||
cls.apiclient,
|
||||
services=cls.services["virtual_machine"],
|
||||
templateid=cls.template.id,
|
||||
zoneid=cls.zone.id,
|
||||
accountid=cls.account.name,
|
||||
domainid=cls.account.domainid,
|
||||
serviceofferingid=cls.service_offering.id,
|
||||
networkids=[cls.tier1.id],
|
||||
)
|
||||
cls.services["virtual_machine"]["displayname"] = "vm2" + cls.vpc.id
|
||||
cls.vm2 = VirtualMachine.create(
|
||||
cls.apiclient,
|
||||
services=cls.services["virtual_machine"],
|
||||
templateid=cls.template.id,
|
||||
zoneid=cls.zone.id,
|
||||
accountid=cls.account.name,
|
||||
domainid=cls.account.domainid,
|
||||
serviceofferingid=cls.service_offering.id,
|
||||
networkids=[cls.tier2.id],
|
||||
)
|
||||
cls._cleanup.append(cls.vm1)
|
||||
cls._cleanup.append(cls.vm2)
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
super(TestVPCConserveModeRules, cls).tearDownClass()
|
||||
|
||||
def setUp(self):
|
||||
self.apiclient = self.testClient.getApiClient()
|
||||
self.cleanup = []
|
||||
|
||||
def tearDown(self):
|
||||
super(TestVPCConserveModeRules, self).tearDown()
|
||||
|
||||
@attr(tags=["advanced", "advancedns", "smoke"], required_hardware="false")
|
||||
def test_01_vpc_conserve_mode_cross_tier_rules_allowed(self):
|
||||
"""With conserveMode=True, LB rule on VPC Tier 1 and Port Forwarding rule on VPC Tier 2 can
|
||||
share the same public IP without a NetworkRuleConflictException.
|
||||
"""
|
||||
|
||||
public_ip = PublicIPAddress.create(
|
||||
self.apiclient,
|
||||
zoneid=self.zone.id,
|
||||
accountid=self.account.name,
|
||||
domainid=self.account.domainid,
|
||||
vpcid=self.vpc.id,
|
||||
)
|
||||
|
||||
self.logger.debug(
|
||||
"Creating LB rule on tier-1 (networkid=%s) using public IP %s",
|
||||
self.tier1.id,
|
||||
public_ip.ipaddress.ipaddress,
|
||||
)
|
||||
lb_rule_tier1 = LoadBalancerRule.create(
|
||||
self.apiclient,
|
||||
self.services["lbrule"],
|
||||
ipaddressid=public_ip.ipaddress.id,
|
||||
accountid=self.account.name,
|
||||
vpcid=self.vpc.id,
|
||||
networkid=self.tier1.id,
|
||||
domainid=self.account.domainid,
|
||||
)
|
||||
self.assertIsNotNone(lb_rule_tier1, "LB rule creation on tier-1 failed")
|
||||
lb_rule_tier1.assign(self.apiclient, [self.vm1])
|
||||
|
||||
self.logger.debug(
|
||||
"Creating Port Forwarding rule on tier-2 (networkid=%s) "
|
||||
"using the same public IP %s – should succeed with conserve mode",
|
||||
self.tier2.id,
|
||||
public_ip.ipaddress.ipaddress,
|
||||
)
|
||||
try:
|
||||
nat_rule = NATRule.create(
|
||||
self.apiclient,
|
||||
self.vm2,
|
||||
self.services["natrule"],
|
||||
ipaddressid=public_ip.ipaddress.id,
|
||||
vpcid=self.vpc.id,
|
||||
networkid=self.tier2.id,
|
||||
)
|
||||
self.assertIsNotNone(
|
||||
nat_rule,
|
||||
"Port Forwarding rule creation on tier-2 failed unexpectedly",
|
||||
)
|
||||
except CloudstackAPIException as e:
|
||||
self.fail(
|
||||
"Expected cross-tier Port Forwarding rule to succeed with "
|
||||
"conserveMode=True, but got exception: %s" % e
|
||||
)
|
||||
|
||||
@attr(tags=["advanced", "advancedns", "smoke"], required_hardware="false")
|
||||
def test_02_vpc_conserve_mode_reuse_source_nat_ip_address(self):
|
||||
"""With VPC conserve mode enabled, a NAT rule can be created on a VPC tier (conserve mode enabled)
|
||||
with a source NAT IP address
|
||||
"""
|
||||
source_nat_ip_resp = list_publicIP(
|
||||
self.apiclient,
|
||||
vpcid=self.vpc.id,
|
||||
listall=True,
|
||||
issourcenat=True
|
||||
)
|
||||
|
||||
source_nat_ip = source_nat_ip_resp[0]
|
||||
|
||||
self.logger.debug(
|
||||
"Creating Port Forwarding rule on tier-2 (networkid=%s) "
|
||||
"using the source NAT public IP %s – should succeed with conserve mode",
|
||||
self.tier1.id,
|
||||
source_nat_ip.ipaddress,
|
||||
)
|
||||
try:
|
||||
nat_rule = NATRule.create(
|
||||
self.apiclient,
|
||||
self.vm2,
|
||||
self.services["natrule"],
|
||||
ipaddressid=source_nat_ip.id,
|
||||
vpcid=self.vpc.id,
|
||||
networkid=self.tier2.id,
|
||||
)
|
||||
self.assertIsNotNone(
|
||||
nat_rule,
|
||||
"Port Forwarding rule creation on tier-2 failed unexpectedly",
|
||||
)
|
||||
self.logger.debug(
|
||||
"Creating LB rule on tier-1 (networkid=%s) "
|
||||
"using the source NAT public IP %s – should succeed with conserve mode",
|
||||
self.tier1.id,
|
||||
source_nat_ip.ipaddress,
|
||||
)
|
||||
lb_rule_tier1 = LoadBalancerRule.create(
|
||||
self.apiclient,
|
||||
self.services["lbrule"],
|
||||
ipaddressid=source_nat_ip.id,
|
||||
accountid=self.account.name,
|
||||
vpcid=self.vpc.id,
|
||||
networkid=self.tier2.id,
|
||||
domainid=self.account.domainid,
|
||||
)
|
||||
self.assertIsNotNone(lb_rule_tier1, "LB rule creation on tier-2 failed")
|
||||
lb_rule_tier1.assign(self.apiclient, [self.vm2])
|
||||
except CloudstackAPIException as e:
|
||||
self.fail(
|
||||
"Expected multiple rules on VPC Source NAT IP to succeed with "
|
||||
"conserveMode=True, but got exception: %s" % e
|
||||
)
|
||||
|
|
@ -5227,6 +5227,8 @@ class VpcOffering:
|
|||
cmd.networkmode = services["networkmode"]
|
||||
if "routingmode" in services:
|
||||
cmd.routingmode = services["routingmode"]
|
||||
if "conservemode" in services:
|
||||
cmd.conservemode = services["conservemode"]
|
||||
return VpcOffering(apiclient.createVPCOffering(cmd).__dict__)
|
||||
|
||||
def update(self, apiclient, name=None, displaytext=None, state=None):
|
||||
|
|
|
|||
|
|
@ -508,7 +508,7 @@ export default {
|
|||
searchFilters: ['name', 'zoneid', 'domainid'],
|
||||
resourceType: 'VpcOffering',
|
||||
columns: ['name', 'state', 'displaytext', 'domain', 'zone', 'order'],
|
||||
details: ['name', 'id', 'displaytext', 'internetprotocol', 'distributedvpcrouter', 'tags', 'routingmode', 'specifyasnumber', 'service', 'fornsx', 'networkmode', 'domain', 'zone', 'created'],
|
||||
details: ['name', 'id', 'displaytext', 'internetprotocol', 'distributedvpcrouter', 'tags', 'routingmode', 'specifyasnumber', 'service', 'fornsx', 'networkmode', 'conservemode', 'domain', 'zone', 'created'],
|
||||
related: [{
|
||||
name: 'vpc',
|
||||
title: 'label.vpc',
|
||||
|
|
|
|||
|
|
@ -487,10 +487,10 @@
|
|||
>
|
||||
<div @keyup.ctrl.enter="handleAddNewRule">
|
||||
<span
|
||||
v-if="'vpcid' in resource && !('associatednetworkid' in resource)">
|
||||
v-if="'vpcid' in resource && (!('associatednetworkid' in resource) || vpcConserveMode)">
|
||||
<strong>{{ $t('label.select.tier') }} </strong>
|
||||
<a-select
|
||||
v-focus="'vpcid' in resource && !('associatednetworkid' in resource)"
|
||||
v-focus="'vpcid' in resource && (!('associatednetworkid' in resource) || vpcConserveMode)"
|
||||
v-model:value="selectedTier"
|
||||
@change="fetchVirtualMachines()"
|
||||
:placeholder="$t('label.select.tier')"
|
||||
|
|
@ -1022,7 +1022,8 @@ export default {
|
|||
urlpath: '/'
|
||||
},
|
||||
healthMonitorLoading: false,
|
||||
isNetrisZone: false
|
||||
isNetrisZone: false,
|
||||
vpcConserveMode: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -1079,10 +1080,24 @@ export default {
|
|||
})
|
||||
},
|
||||
fetchData () {
|
||||
this.fetchVpc()
|
||||
this.fetchListTiers()
|
||||
this.fetchLBRules()
|
||||
this.fetchZone()
|
||||
},
|
||||
fetchVpc () {
|
||||
if (!this.resource.vpcid) {
|
||||
return
|
||||
}
|
||||
this.vpcConserveMode = false
|
||||
getAPI('listVPCs', {
|
||||
id: this.resource.vpcid
|
||||
}).then(json => {
|
||||
this.vpcConserveMode = json.listvpcsresponse?.vpc?.[0].vpcofferingconservemode || false
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
})
|
||||
},
|
||||
fetchListTiers () {
|
||||
this.tiers.loading = true
|
||||
|
||||
|
|
@ -1830,7 +1845,7 @@ export default {
|
|||
|
||||
getAPI('listNics', {
|
||||
virtualmachineid: e.target.value,
|
||||
networkid: ('vpcid' in this.resource && !('associatednetworkid' in this.resource)) ? this.selectedTier : this.resource.associatednetworkid
|
||||
networkid: ('vpcid' in this.resource && (!('associatednetworkid' in this.resource) || this.vpcConserveMode)) ? this.selectedTier : this.resource.associatednetworkid
|
||||
}).then(response => {
|
||||
if (!response || !response.listnicsresponse || !response.listnicsresponse.nic[0]) return
|
||||
const newItem = []
|
||||
|
|
@ -1850,7 +1865,7 @@ export default {
|
|||
this.vmCount = 0
|
||||
this.vms = []
|
||||
this.addVmModalLoading = true
|
||||
const networkId = ('vpcid' in this.resource && !('associatednetworkid' in this.resource)) ? this.selectedTier : this.resource.associatednetworkid
|
||||
const networkId = ('vpcid' in this.resource && (!('associatednetworkid' in this.resource) || this.vpcConserveMode)) ? this.selectedTier : this.resource.associatednetworkid
|
||||
if (!networkId) {
|
||||
this.addVmModalLoading = false
|
||||
return
|
||||
|
|
|
|||
|
|
@ -216,10 +216,10 @@
|
|||
@cancel="closeModal">
|
||||
<div v-ctrl-enter="addRule">
|
||||
<span
|
||||
v-if="'vpcid' in resource && !('associatednetworkid' in resource)">
|
||||
v-if="'vpcid' in resource && (!('associatednetworkid' in resource) || vpcConserveMode)">
|
||||
<strong>{{ $t('label.select.tier') }} </strong>
|
||||
<a-select
|
||||
:v-focus="'vpcid' in resource && !('associatednetworkid' in resource)"
|
||||
v-focus="'vpcid' in resource && (!('associatednetworkid' in resource) || vpcConserveMode)"
|
||||
v-model:value="selectedTier"
|
||||
@change="fetchVirtualMachines()"
|
||||
:placeholder="$t('label.select.tier')"
|
||||
|
|
@ -467,7 +467,8 @@ export default {
|
|||
vmPageSize: 10,
|
||||
vmCount: 0,
|
||||
searchQuery: null,
|
||||
cidrlist: ''
|
||||
cidrlist: '',
|
||||
vpcConserveMode: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
@ -504,13 +505,24 @@ export default {
|
|||
})
|
||||
},
|
||||
fetchData () {
|
||||
this.fetchVpc()
|
||||
this.fetchListTiers()
|
||||
this.fetchPFRules()
|
||||
},
|
||||
fetchListTiers () {
|
||||
if ('vpcid' in this.resource && 'associatednetworkid' in this.resource) {
|
||||
fetchVpc () {
|
||||
if (!this.resource.vpcid) {
|
||||
return
|
||||
}
|
||||
this.vpcConserveMode = false
|
||||
getAPI('listVPCs', {
|
||||
id: this.resource.vpcid
|
||||
}).then(json => {
|
||||
this.vpcConserveMode = json.listvpcsresponse?.vpc?.[0].vpcofferingconservemode || false
|
||||
}).catch(error => {
|
||||
this.$notifyError(error)
|
||||
})
|
||||
},
|
||||
fetchListTiers () {
|
||||
this.selectedTier = null
|
||||
this.tiers.loading = true
|
||||
getAPI('listNetworks', {
|
||||
|
|
@ -630,7 +642,7 @@ export default {
|
|||
if (this.loading) return
|
||||
this.loading = true
|
||||
this.addVmModalVisible = false
|
||||
const networkId = ('vpcid' in this.resource && !('associatednetworkid' in this.resource)) ? this.selectedTier : this.resource.associatednetworkid
|
||||
const networkId = ('vpcid' in this.resource && (!('associatednetworkid' in this.resource) || this.vpcConserveMode)) ? this.selectedTier : this.resource.associatednetworkid
|
||||
postAPI('createPortForwardingRule', {
|
||||
...this.newRule,
|
||||
ipaddressid: this.resource.id,
|
||||
|
|
@ -788,7 +800,7 @@ export default {
|
|||
this.newRule.virtualmachineid = e.target.value
|
||||
getAPI('listNics', {
|
||||
virtualmachineid: e.target.value,
|
||||
networkId: ('vpcid' in this.resource && !('associatednetworkid' in this.resource)) ? this.selectedTier : this.resource.associatednetworkid
|
||||
networkid: ('vpcid' in this.resource && (!('associatednetworkid' in this.resource) || this.vpcConserveMode)) ? this.selectedTier : this.resource.associatednetworkid
|
||||
}).then(response => {
|
||||
if (!response.listnicsresponse.nic || response.listnicsresponse.nic.length < 1) return
|
||||
const nic = response.listnicsresponse.nic[0]
|
||||
|
|
@ -808,7 +820,7 @@ export default {
|
|||
this.vmCount = 0
|
||||
this.vms = []
|
||||
this.addVmModalLoading = true
|
||||
const networkId = ('vpcid' in this.resource && !('associatednetworkid' in this.resource)) ? this.selectedTier : this.resource.associatednetworkid
|
||||
const networkId = ('vpcid' in this.resource && (!('associatednetworkid' in this.resource) || this.vpcConserveMode)) ? this.selectedTier : this.resource.associatednetworkid
|
||||
if (!networkId) {
|
||||
this.addVmModalLoading = false
|
||||
return
|
||||
|
|
|
|||
|
|
@ -135,8 +135,10 @@ export default {
|
|||
return
|
||||
}
|
||||
if (this.resource && this.resource.vpcid) {
|
||||
// VPC IPs with source nat have only VPN
|
||||
if (this.resource.issourcenat) {
|
||||
const vpc = await this.fetchVpc()
|
||||
|
||||
// VPC IPs with source nat have only VPN when VPC offering conserve mode = false
|
||||
if (this.resource.issourcenat && vpc?.vpcofferingconservemode === false) {
|
||||
this.tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'vpn'))
|
||||
return
|
||||
}
|
||||
|
|
@ -154,7 +156,12 @@ export default {
|
|||
|
||||
const network = await this.fetchNetwork()
|
||||
if (network && network.networkofferingconservemode) {
|
||||
this.tabs = tabs
|
||||
// VPC IPs with source nat have only VPN when VPC offering conserve mode = false
|
||||
if (this.resource.issourcenat && vpc?.vpcofferingconservemode === false) {
|
||||
this.tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'vpn'))
|
||||
} else {
|
||||
this.tabs = tabs
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
|
|
@ -193,6 +200,21 @@ export default {
|
|||
fetchAction () {
|
||||
this.actions = this.$route.meta.actions || []
|
||||
},
|
||||
fetchVpc () {
|
||||
if (!this.resource.vpcid) {
|
||||
return null
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
getAPI('listVPCs', {
|
||||
id: this.resource.vpcid
|
||||
}).then(json => {
|
||||
const vpc = json.listvpcsresponse?.vpc?.[0] || null
|
||||
resolve(vpc)
|
||||
}).catch(e => {
|
||||
reject(e)
|
||||
})
|
||||
})
|
||||
},
|
||||
fetchNetwork () {
|
||||
if (!this.resource.associatednetworkid) {
|
||||
return null
|
||||
|
|
|
|||
|
|
@ -194,6 +194,14 @@
|
|||
</a-select-option>
|
||||
</a-select>
|
||||
</a-form-item>
|
||||
<a-form-item
|
||||
name="conservemode"
|
||||
ref="conservemode">
|
||||
<template #label>
|
||||
<tooltip-label :title="$t('label.conservemode')" :tooltip="apiParams.conservemode.description"/>
|
||||
</template>
|
||||
<a-switch v-model:checked="form.conservemode" />
|
||||
</a-form-item>
|
||||
<a-form-item name="ispublic" ref="ispublic" :label="$t('label.ispublic')" v-if="isAdmin()">
|
||||
<a-switch v-model:checked="form.ispublic" />
|
||||
</a-form-item>
|
||||
|
|
@ -282,7 +290,6 @@ export default {
|
|||
return {
|
||||
selectedDomains: [],
|
||||
selectedZones: [],
|
||||
isConserveMode: true,
|
||||
internetProtocolValue: 'ipv4',
|
||||
domains: [],
|
||||
domainLoading: false,
|
||||
|
|
@ -328,7 +335,8 @@ export default {
|
|||
description: 'Netris',
|
||||
enabled: true
|
||||
},
|
||||
nsxSupportedServicesMap: {}
|
||||
nsxSupportedServicesMap: {},
|
||||
conservemode: false
|
||||
}
|
||||
},
|
||||
beforeCreate () {
|
||||
|
|
@ -719,6 +727,7 @@ export default {
|
|||
params.provider = 'Netris'
|
||||
}
|
||||
params.networkmode = values.networkmode
|
||||
params.conservemode = values.conservemode
|
||||
if (!values.forVpc) {
|
||||
params.specifyasnumber = values.specifyasnumber
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue