Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions api/src/main/java/com/cloud/network/vpc/VpcOffering.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,6 @@ public enum State {
NetworkOffering.RoutingMode getRoutingMode();

Boolean isSpecifyAsNumber();

boolean isConserveMode();
}
Original file line number Diff line number Diff line change
Expand Up @@ -980,6 +980,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";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,7 @@ public long getNetworkId() {
IpAddress ip = _entityMgr.findById(IpAddress.class, getIpAddressId());
Long ntwkId = null;

if (ip.getAssociatedWithNetworkId() != null) {
if (ip.getVpcId() == null && ip.getAssociatedWithNetworkId() != null) {
ntwkId = ip.getAssociatedWithNetworkId();
} else {
ntwkId = networkId;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -197,6 +201,10 @@ public void setDisplayText(final String displayText) {
this.displayText = displayText;
}

public void setVpcOfferingConserveMode(Boolean vpcOfferingConserveMode) {
this.vpcOfferingConserveMode = vpcOfferingConserveMode;
}

public void setCreated(final Date created) {
this.created = created;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@
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);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
Expand Down Expand Up @@ -242,4 +245,13 @@ public Boolean isSpecifyAsNumber() {
public void setSpecifyAsNumber(Boolean specifyAsNumber) {
this.specifyAsNumber = specifyAsNumber;
}

@Override
public boolean isConserveMode() {
return conserveMode;
}

public void setConserveMode(boolean conserveMode) {
this.conserveMode = conserveMode;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -87,3 +87,5 @@ CALL `cloud`.`INSERT_EXTENSION_DETAIL_IF_NOT_EXISTS`('MaaS', 'orchestratorrequir

CALL `cloud`.`IDEMPOTENT_DROP_UNIQUE_KEY`('counter', 'uc_counter__provider__source__value');
CALL `cloud`.`IDEMPOTENT_ADD_UNIQUE_KEY`('cloud.counter', 'uc_counter__provider__source__value__removed', '(provider, source, value, removed)');

CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vpc_offerings','conserve_mode', 'tinyint(1) unsigned NULL DEFAULT 1');
Original file line number Diff line number Diff line change
Expand Up @@ -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`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -363,7 +363,7 @@ private LoadBalancer handleCreateLoadBalancerRuleWithLock(final CreateLoadBalanc
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) {
Expand Down
1 change: 1 addition & 0 deletions server/src/main/java/com/cloud/api/ApiResponseHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -3499,6 +3499,7 @@ public VpcResponse createVpcResponse(ResponseView view, Vpc vpc) {
if (voff != null) {
response.setVpcOfferingId(voff.getUuid());
response.setVpcOfferingName(voff.getName());
response.setVpcOfferingConserveMode(voff.isConserveMode());
}
response.setCidr(vpc.getCidr());
response.setRestartRequired(vpc.isRestartRequired());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
}

Expand Down Expand Up @@ -178,6 +181,11 @@ public Boolean isSpecifyAsNumber() {
return specifyAsNumber;
}

@Override
public boolean isConserveMode() {
return conserveMode;
}

public void setSpecifyAsNumber(Boolean specifyAsNumber) {
this.specifyAsNumber = specifyAsNumber;
}
Expand Down
14 changes: 13 additions & 1 deletion server/src/main/java/com/cloud/network/IpAddressManagerImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -1543,6 +1543,14 @@ public IPAddressVO doInTransaction(TransactionStatus status) throws Insufficient
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);
Expand Down Expand Up @@ -1723,7 +1731,11 @@ protected boolean isSourceNatAvailableForNetwork(Account owner, IPAddressVO ipTo
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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -395,6 +395,12 @@ public void detectRulesConflict(FirewallRule newRule) throws NetworkRuleConflict
assert (rules.size() >= 1);
}

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());
}
boolean isNewRuleOnVpcNetwork = newRuleNetwork.getVpcId() != null;

for (FirewallRuleVO rule : rules) {
if (rule.getId() == newRule.getId()) {
continue; // Skips my own rule.
Expand Down Expand Up @@ -442,8 +448,8 @@ public void detectRulesConflict(FirewallRule newRule) throws NetworkRuleConflict
}
}

// 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) {
// Checking if the rule applied is to the same network that is passed in the rule. (except for VPC networks)
if (!isNewRuleOnVpcNetwork && 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());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1761,7 +1761,7 @@ public LoadBalancer createPublicLoadBalancerRule(String xId, String name, String
}

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) {
Expand Down Expand Up @@ -1824,7 +1824,7 @@ private String validateCidr(String cidr) {
@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);
}
Expand Down Expand Up @@ -1853,7 +1853,7 @@ public LoadBalancer createPublicLoadBalancer(final String xId, final String name

_accountMgr.checkAccess(caller.getCallingAccount(), null, true, ipAddr);

final Long networkId = ipAddr.getAssociatedWithNetworkId();
final Long networkId = ipAddr.getVpcId() == null ? ipAddr.getAssociatedWithNetworkId() : networkIdParam;
if (networkId == null) {
InvalidParameterValueException ex =
new InvalidParameterValueException("Unable to create load balancer rule ; specified sourceip id is not associated with any network");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
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;
Expand All @@ -43,6 +45,7 @@
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;
Expand Down Expand Up @@ -76,6 +79,8 @@ public class FirewallManagerTest {
IpAddressManager _ipAddrMgr;
@Mock
FirewallRulesDao _firewallDao;
@Mock
NetworkDao _networkDao;

@Spy
@InjectMocks
Expand Down Expand Up @@ -196,6 +201,10 @@ public void testDetectRulesConflict() {
FirewallRule newRule4 = new FirewallRuleVO("newRule4", 3L, 15, 25, "TCP", 1, 2, 1, Purpose.Firewall, sString, dString2, null, null,
null, FirewallRule.TrafficType.Egress);

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);
Expand Down
12 changes: 6 additions & 6 deletions ui/src/views/network/LoadBalancing.vue
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@
{{ $t('label.add') }}
</a-button>
</div>
<div class="form__item" v-else-if="newRule.autoscale === 'yes' && ('vpcid' in this.resource && !this.associatednetworkid)">
<div class="form__item" v-else-if="newRule.autoscale === 'yes' && ('vpcid' in this.resource)">
<div class="form__label" style="white-space: nowrap;">{{ $t('label.select.tier') }}</div>
<a-button :disabled="!('createLoadBalancerRule' in $store.getters.apis)" type="primary" @click="handleOpenAddNetworkModal">
{{ $t('label.add') }}
Expand Down Expand Up @@ -487,10 +487,10 @@
>
<div @keyup.ctrl.enter="handleAddNewRule">
<span
v-if="'vpcid' in resource && !('associatednetworkid' in resource)">
v-if="'vpcid' in resource">
<strong>{{ $t('label.select.tier') }} </strong>
<a-select
v-focus="'vpcid' in resource && !('associatednetworkid' in resource)"
v-focus="'vpcid' in resource"
v-model:value="selectedTier"
@change="fetchVirtualMachines()"
:placeholder="$t('label.select.tier')"
Expand Down Expand Up @@ -1830,7 +1830,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) ? this.selectedTier : this.resource.associatednetworkid
}).then(response => {
if (!response || !response.listnicsresponse || !response.listnicsresponse.nic[0]) return
const newItem = []
Expand All @@ -1850,7 +1850,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) ? this.selectedTier : this.resource.associatednetworkid
if (!networkId) {
this.addVmModalLoading = false
return
Expand Down Expand Up @@ -1999,7 +1999,7 @@ export default {
}

const networkId = this.selectedTierForAutoScaling != null ? this.selectedTierForAutoScaling
: ('vpcid' in this.resource && !('associatednetworkid' in this.resource)) ? this.selectedTier : this.resource.associatednetworkid
: ('vpcid' in this.resource) ? this.selectedTier : this.resource.associatednetworkid
postAPI('createLoadBalancerRule', {
openfirewall: false,
networkid: networkId,
Expand Down
13 changes: 5 additions & 8 deletions ui/src/views/network/PortForwarding.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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">
<strong>{{ $t('label.select.tier') }} </strong>
<a-select
:v-focus="'vpcid' in resource && !('associatednetworkid' in resource)"
:v-focus="'vpcid' in resource"
v-model:value="selectedTier"
@change="fetchVirtualMachines()"
:placeholder="$t('label.select.tier')"
Expand Down Expand Up @@ -508,9 +508,6 @@ export default {
this.fetchPFRules()
},
fetchListTiers () {
if ('vpcid' in this.resource && 'associatednetworkid' in this.resource) {
return
}
this.selectedTier = null
this.tiers.loading = true
getAPI('listNetworks', {
Expand Down Expand Up @@ -630,7 +627,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) ? this.selectedTier : this.resource.associatednetworkid
postAPI('createPortForwardingRule', {
...this.newRule,
ipaddressid: this.resource.id,
Expand Down Expand Up @@ -788,7 +785,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) ? this.selectedTier : this.resource.associatednetworkid
}).then(response => {
if (!response.listnicsresponse.nic || response.listnicsresponse.nic.length < 1) return
const nic = response.listnicsresponse.nic[0]
Expand All @@ -808,7 +805,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) ? this.selectedTier : this.resource.associatednetworkid
if (!networkId) {
this.addVmModalLoading = false
return
Expand Down
12 changes: 5 additions & 7 deletions ui/src/views/network/PublicIpResource.vue
Original file line number Diff line number Diff line change
Expand Up @@ -135,12 +135,6 @@ export default {
return
}
if (this.resource && this.resource.vpcid) {
// VPC IPs with source nat have only VPN
if (this.resource.issourcenat) {
this.tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'vpn'))
return
}

// VPC IPs with static nat have nothing
if (this.resource.isstaticnat) {
if (this.resource.virtualmachinetype === 'DomainRouter') {
Expand All @@ -153,9 +147,13 @@ export default {
let tabs = this.$route.meta.tabs.filter(tab => tab.name !== 'firewall')

const network = await this.fetchNetwork()
if (network && network.networkofferingconservemode) {
if ((network && network.networkofferingconservemode) || !network && this.resource.issourcenat) {
this.tabs = tabs
return
} else if (this.resource.issourcenat) {
// VPC IPs with Source Nat have only VPN when conserve_mode = false
this.tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'vpn'))
return
}

this.portFWRuleCount = await this.fetchPortFWRule()
Expand Down
Loading