Copilot commented on code in PR #12706:
URL: https://github.com/apache/cloudstack/pull/12706#discussion_r3225843519


##########
server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java:
##########
@@ -198,25 +198,62 @@ public FirewallRule createEgressFirewallRule(FirewallRule 
rule) throws NetworkRu
         if (sourceCidrs != null && !sourceCidrs.isEmpty())
         Collections.replaceAll(sourceCidrs, "0.0.0.0/0", network.getCidr());
 
-        return createFirewallRule(null, caller, rule.getXid(), 
rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(), 
sourceCidrs, rule.getDestinationCidrList(),
-                rule.getIcmpCode(), rule.getIcmpType(), null, rule.getType(), 
rule.getNetworkId(), rule.getTrafficType(), rule.isDisplay());
+        return createFirewallRuleForNonVPC(null, caller, rule.getXid(), 
rule.getSourcePortStart(), rule.getSourcePortEnd(), rule.getProtocol(), 
sourceCidrs,
+                rule.getDestinationCidrList(), rule.getIcmpCode(), 
rule.getIcmpType(), null, rule.getType(), rule.getNetworkId(), 
rule.getTrafficType(), rule.isDisplay());
     }
 
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_FIREWALL_OPEN, eventDescription 
= "creating firewall rule", create = true)
     public FirewallRule createIngressFirewallRule(FirewallRule rule) throws 
NetworkRuleConflictException {
-         Account caller = CallContext.current().getCallingAccount();
+        Account caller = CallContext.current().getCallingAccount();
         Long sourceIpAddressId = rule.getSourceIpAddressId();
+        IPAddressVO sourceIp = getSourceIpForIngressRule(sourceIpAddressId);
+

Review Comment:
   `createIngressFirewallRule` dereferences `sourceIp` without checking for 
null. Since `getSourceIpForIngressRule` returns null when `sourceIpAddressId` 
is null (or when the IP cannot be found), this can throw a NullPointerException 
at `sourceIp.getVpcId()`. Please add validation/error handling for 
missing/invalid source IP before branching on VPC vs isolated handling.
   



##########
server/src/main/java/com/cloud/network/firewall/FirewallManagerImpl.java:
##########
@@ -283,6 +320,158 @@ protected FirewallRule createFirewallRule(final Long 
ipAddrId, Account caller, f
         }
     }
 
+    @DB
+    protected FirewallRule createFirewallRuleForVpc(final Long ipAddrId, 
Account caller, final String xId, final Integer portStart, final Integer 
portEnd, final String protocol,
+                                                    final List<String> 
sourceCidrList, final List<String> destCidrList, final Integer icmpCode, final 
Integer icmpType,
+                                                    final Long relatedRuleId, 
final FirewallRuleType type, final Long vpcId,
+                                                    final 
FirewallRule.TrafficType trafficType, final Boolean forDisplay) throws 
NetworkRuleConflictException {
+        IPAddressVO ipAddress = null;
+        try {
+            Long resolvedVpcId = vpcId;
+            if (ipAddrId != null) {
+                ipAddress = _ipAddressDao.acquireInLockTable(ipAddrId);
+                if (ipAddress == null) {
+                    throw new InvalidParameterValueException("Unable to create 
firewall rule; " + "couldn't locate IP address by id in the system");
+                }
+                resolvedVpcId = resolvedVpcId != null ? resolvedVpcId : 
ipAddress.getVpcId();
+            }
+
+            if (resolvedVpcId == null) {
+                throw new InvalidParameterValueException("Unable to create VPC 
firewall rule; couldn't locate VPC id");
+            }
+
+            validateFirewallRuleForVpc(caller, ipAddress, portStart, portEnd, 
protocol, Purpose.Firewall, type, resolvedVpcId, trafficType);
+
+            if (!protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO) && (icmpCode 
!= null || icmpType != null)) {
+                throw new InvalidParameterValueException("Can specify icmpCode 
and icmpType for ICMP protocol only");
+            }
+
+            if (protocol.equalsIgnoreCase(NetUtils.ICMP_PROTO) && (portStart 
!= null || portEnd != null)) {
+                throw new InvalidParameterValueException("Can't specify 
start/end port when protocol is ICMP");
+            }
+
+            Long accountId = null;
+            Long domainId = null;
+
+            if (ipAddress != null) {
+                accountId = ipAddress.getAllocatedToAccountId();
+                domainId = ipAddress.getAllocatedInDomainId();
+            } else {
+                Vpc vpc = _vpcMgr.getActiveVpc(resolvedVpcId);
+                if (vpc == null) {
+                    throw new InvalidParameterValueException("Unable to create 
VPC firewall rule; couldn't locate VPC by id=" + resolvedVpcId);
+                }
+                accountId = vpc.getAccountId();
+                domainId = vpc.getDomainId();
+            }
+
+            final Long accountIdFinal = accountId;
+            final Long domainIdFinal = domainId;
+            final Long resolvedNetworkIdFinal = null;
+            final Long resolvedVpcIdFinal = resolvedVpcId;
+            return 
Transaction.execute((TransactionCallbackWithException<FirewallRuleVO, 
NetworkRuleConflictException>) status -> {
+                FirewallRuleVO newRule = new FirewallRuleVO(xId, ipAddrId, 
portStart, portEnd, protocol.toLowerCase(), resolvedNetworkIdFinal, 
accountIdFinal, domainIdFinal, Purpose.Firewall,
+                        sourceCidrList, destCidrList, icmpCode, icmpType, 
relatedRuleId, trafficType);
+                newRule.setVpcId(resolvedVpcIdFinal);
+                newRule.setType(type);

Review Comment:
   `createFirewallRuleForVpc` persists a `FirewallRuleVO` with `network_id` set 
to null (`resolvedNetworkIdFinal = null`). The DB schema defines 
`firewall_rules.network_id` as `NOT NULL` (see `setup/db/create-schema.sql`), 
so this insert will fail at runtime. Either persist a valid networkId for VPC 
firewall rules (e.g., derived from the source IP’s `sourceNetworkId`) or update 
the schema/constraints accordingly (including upgrade paths).



##########
server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java:
##########
@@ -7223,10 +7223,12 @@ public NetworkOffering createNetworkOffering(final 
NetworkOfferingBaseCmd cmd) {
             }
 
             if (forVpc == null) {
-                if (service == Service.SecurityGroup || service == 
Service.Firewall) {
+                if (service == Service.SecurityGroup) {
                     forVpc = false;
                 } else if (service == Service.NetworkACL) {
                     forVpc = true;
+                } else if (service == Service.Firewall) {
+                    forVpc = true;

Review Comment:
   When `forVpc` is not explicitly provided, the inference now sets `forVpc = 
true` as soon as the service list contains `Service.Firewall`. Since Firewall 
is also valid for non-VPC (isolated) offerings, this can misclassify offerings 
and change API behavior for callers that omit `forVpc`. Consider inferring 
`forVpc` only from VPC-specific services (e.g. `NetworkACL`) or requiring 
`forVpc` to be explicitly set when the service mix is ambiguous.
   



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to