From 3fd969bc411519d5561b73f6f9db7ba3bb274bf4 Mon Sep 17 00:00:00 2001 From: nvazquez Date: Tue, 27 Jan 2026 02:00:20 -0300 Subject: [PATCH] Fixes --- .../META-INF/db/schema-42100to42200.sql | 2 -- .../META-INF/db/schema-42210to42300.sql | 3 ++ .../network/firewall/FirewallManagerImpl.java | 21 ++++++++++++-- ui/src/views/network/LoadBalancing.vue | 29 ++++++++++++++----- ui/src/views/network/PortForwarding.vue | 27 +++++++++++++---- ui/src/views/network/PublicIpResource.vue | 12 ++++---- 6 files changed, 71 insertions(+), 23 deletions(-) diff --git a/engine/schema/src/main/resources/META-INF/db/schema-42100to42200.sql b/engine/schema/src/main/resources/META-INF/db/schema-42100to42200.sql index 4a5db563870..b523016aa3d 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-42100to42200.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-42100to42200.sql @@ -87,5 +87,3 @@ 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'); diff --git a/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql index d330ecd0c0d..67c8a3c8320 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql @@ -49,3 +49,6 @@ CREATE TABLE IF NOT EXISTS `cloud`.`webhook_filter` ( INDEX `i_webhook_filter__webhook_id`(`webhook_id`), CONSTRAINT `fk_webhook_filter__webhook_id` FOREIGN KEY(`webhook_id`) REFERENCES `webhook`(`id`) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; + +CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.vpc_offerings','conserve_mode', 'tinyint(1) unsigned NULL DEFAULT 0'); +UPDATE `cloud`.`vpc_offerings` SET conserve_mode=1 WHERE name='Default VPC offering'; diff --git a/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java b/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java index 5232fbd7f66..93035157e21 100644 --- a/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java +++ b/server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java @@ -30,6 +30,8 @@ import java.util.Set; import javax.inject.Inject; import javax.naming.ConfigurationException; +import com.cloud.network.vpc.VpcOfferingVO; +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; @@ -400,6 +404,11 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, throw new InvalidParameterValueException("Unable to create firewall rule as cannot find network by id=" + newRule.getNetworkId()); } boolean isNewRuleOnVpcNetwork = newRuleNetwork.getVpcId() != null; + boolean isVpcConserveModeEnabled = false; + if (isNewRuleOnVpcNetwork) { + VpcOfferingVO vpcOffering = vpcOfferingDao.findById(newRuleNetwork.getVpcId()); + isVpcConserveModeEnabled = vpcOffering != null && vpcOffering.isConserveMode(); + } for (FirewallRuleVO rule : rules) { if (rule.getId() == newRule.getId()) { @@ -448,9 +457,15 @@ public class FirewallManagerImpl extends ManagerBase implements FirewallService, } } - // 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()); + // Checking if the rule applied is to the same network that is passed in the rule. + // (except for VPCs with conserve mode = true) + if ((!isNewRuleOnVpcNetwork || !isVpcConserveModeEnabled) + && 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 (isNewRuleOnVpcNetwork) { + errMsg += String.format(" - VPC id=%s is not using conserve mode", newRuleNetwork.getVpcId()); + } + 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. diff --git a/ui/src/views/network/LoadBalancing.vue b/ui/src/views/network/LoadBalancing.vue index aac72b94184..2e47f702f7b 100644 --- a/ui/src/views/network/LoadBalancing.vue +++ b/ui/src/views/network/LoadBalancing.vue @@ -97,7 +97,7 @@ {{ $t('label.add') }} -
+
{{ $t('label.select.tier') }}
{{ $t('label.add') }} @@ -487,10 +487,10 @@ >
+ v-if="'vpcid' in resource && (!('associatednetworkid' in resource) || this.vpcConserveMode)"> {{ $t('label.select.tier') }} { + 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) ? 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) ? 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 @@ -1999,7 +2014,7 @@ export default { } const networkId = this.selectedTierForAutoScaling != null ? this.selectedTierForAutoScaling - : ('vpcid' in this.resource) ? this.selectedTier : this.resource.associatednetworkid + : ('vpcid' in this.resource && !('associatednetworkid' in this.resource)) ? this.selectedTier : this.resource.associatednetworkid postAPI('createLoadBalancerRule', { openfirewall: false, networkid: networkId, diff --git a/ui/src/views/network/PortForwarding.vue b/ui/src/views/network/PortForwarding.vue index 471f94d6995..d53511dc48b 100644 --- a/ui/src/views/network/PortForwarding.vue +++ b/ui/src/views/network/PortForwarding.vue @@ -216,10 +216,10 @@ @cancel="closeModal">
+ v-if="'vpcid' in resource && (!('associatednetworkid' in resource) || this.vpcConserveMode)"> {{ $t('label.select.tier') }} { + this.vpcConserveMode = json.listvpcsresponse?.vpc?.[0].vpcofferingconservemode || false + }).catch(error => { + this.$notifyError(error) + }) + }, fetchListTiers () { this.selectedTier = null this.tiers.loading = true @@ -627,7 +642,7 @@ export default { if (this.loading) return this.loading = true this.addVmModalVisible = false - const networkId = ('vpcid' 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, @@ -785,7 +800,7 @@ export default { this.newRule.virtualmachineid = e.target.value getAPI('listNics', { virtualmachineid: e.target.value, - networkId: ('vpcid' 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] @@ -805,7 +820,7 @@ export default { this.vmCount = 0 this.vms = [] this.addVmModalLoading = true - const networkId = ('vpcid' 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 diff --git a/ui/src/views/network/PublicIpResource.vue b/ui/src/views/network/PublicIpResource.vue index 82511dfadf6..6ca7a2c0d47 100644 --- a/ui/src/views/network/PublicIpResource.vue +++ b/ui/src/views/network/PublicIpResource.vue @@ -147,13 +147,15 @@ export default { let tabs = this.$route.meta.tabs.filter(tab => tab.name !== 'firewall') const network = await this.fetchNetwork() - if ((network && network.networkofferingconservemode) || !network && this.resource.issourcenat) { + if (network && network.networkofferingconservemode) { 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 + } else { + // VPC IPs with source nat have only VPN when conserve mode = false + if (this.resource.issourcenat) { + this.tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'vpn')) + return + } } this.portFWRuleCount = await this.fetchPortFWRule()