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


##########
engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade42210to42300.java:
##########
@@ -42,4 +50,126 @@ public InputStream[] getPrepareScripts() {
 
         return new InputStream[] {script};
     }
+
+    @Override
+    public void performDataMigration(Connection conn) {
+        updateNetworkDefaultOfferingsForVPCWithFirewallService(conn);
+        updateVpcOfferingsWithFirewallService(conn);
+    }
+
+    private void 
updateNetworkDefaultOfferingsForVPCWithFirewallService(Connection conn) {
+        logger.debug("Updating default Network offerings for VPC to add 
Firewall service with VpcVirtualRouter provider");
+
+        final List<String> defaultVpcOfferingUniqueNames = Arrays.asList(
+                NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks,
+                
NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksNoLB,
+                
NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB,
+                NetworkOffering.DEFAULT_NAT_NSX_OFFERING_FOR_VPC,
+                NetworkOffering.DEFAULT_ROUTED_NSX_OFFERING_FOR_VPC,
+                NetworkOffering.DEFAULT_NAT_NSX_OFFERING_FOR_VPC_WITH_ILB,
+                NetworkOffering.DEFAULT_ROUTED_NETRIS_OFFERING_FOR_VPC,
+                NetworkOffering.DEFAULT_NAT_NETRIS_OFFERING_FOR_VPC
+        );
+
+        try {
+            for (String uniqueName : defaultVpcOfferingUniqueNames) {
+                try (PreparedStatement pstmt = conn.prepareStatement("SELECT 
id FROM `cloud`.`network_offerings` WHERE unique_name = ?")) {
+                    pstmt.setString(1, uniqueName);
+                    try (ResultSet rs = pstmt.executeQuery()) {
+                        if (!rs.next()) {
+                            continue;
+                        }
+                        long offeringId = rs.getLong(1);
+                        // Insert into ntwk_offering_service_map
+                        try (PreparedStatement insertOfferingPstmt = 
conn.prepareStatement(
+                                "INSERT IGNORE INTO 
`cloud`.`ntwk_offering_service_map` " +
+                                        "(network_offering_id, service, 
provider, created) " +
+                                        "VALUES (?, 'Firewall', 
'VpcVirtualRouter', now())")) {
+                            insertOfferingPstmt.setLong(1, offeringId);
+                            insertOfferingPstmt.executeUpdate();
+                        }
+                        // Update existing networks (ntwk_service_map)
+                        try (PreparedStatement selectNetworksPstmt = 
conn.prepareStatement(
+                                "SELECT id FROM `cloud`.`networks` WHERE 
network_offering_id = ?")) {
+                            selectNetworksPstmt.setLong(1, offeringId);
+                            try (ResultSet networksRs = 
selectNetworksPstmt.executeQuery()) {
+                                while (networksRs.next()) {
+                                    long networkId = networksRs.getLong(1);
+                                    try (PreparedStatement insertService = 
conn.prepareStatement(
+                                            "INSERT INGORE INTO 
`cloud`.`ntwk_service_map` " +

Review Comment:
   The SQL statement string has a typo: `INSERT INGORE` should be `INSERT 
IGNORE`. As written, this migration will fail at runtime when updating 
`ntwk_service_map`.
   ```suggestion
                                               "INSERT IGNORE INTO 
`cloud`.`ntwk_service_map` " +
   ```



##########
ui/src/views/network/PublicIpResource.vue:
##########
@@ -135,22 +135,39 @@ export default {
         return
       }
       if (this.resource && this.resource.vpcid) {
-        // VPC IPs with source nat have only VPN
+        // VPC IPs with source nat have VPN and Firewall (firewall only if 
associatednetworkid present)
         if (this.resource.issourcenat) {
-          this.tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab 
=> tab.name === 'vpn'))
+          let tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab 
=> tab.name === 'vpn'))
+          if (this.resource.associatednetworkid) {
+            tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => 
['vpn', 'firewall'].includes(tab.name)))
+          }
+          this.tabs = tabs
           return
         }
 
-        // VPC IPs with static nat have nothing
+        // VPC IPs with static nat have firewall (only if associatednetworkid 
present)
         if (this.resource.isstaticnat) {
           if (this.resource.virtualmachinetype === 'DomainRouter') {
-            this.tabs = 
this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'vpn'))
+            let tabs = 
this.defaultTabs.concat(this.$route.meta.tabs.filter(tab => tab.name === 'vpn'))
+            if (this.resource.associatednetworkid) {
+              tabs = this.defaultTabs.concat(this.$route.meta.tabs.filter(tab 
=> ['vpn', 'firewall'].includes(tab.name)))
+            }
+            this.tabs = tabs

Review Comment:
   The updated comment says “VPC IPs with static nat have firewall…”, but in 
the `virtualmachinetype === 'DomainRouter'` branch the code still only adds the 
`vpn` tab unless `associatednetworkid` is present. Either adjust the comment to 
match the actual behavior, or update the tab logic to reflect the intended UX.



##########
engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java:
##########
@@ -327,7 +327,10 @@ protected void executeProcedureScripts() {
             Connection conn = txn.getConnection();
 
             for (String filePath : filesPathUnderViewsDirectory) {
-                LOGGER.debug("Executing PROCEDURE script [{}].", filePath);
+                LOGGER.debug(String.format("Executing PROCEDURE script [%s].", 
filePath));
+                if (filePath.startsWith("/")) {
+                    filePath = filePath.substring(1);
+                }
 
                 InputStream viewScript = 
Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath);

Review Comment:
   `getResourceAsStream(filePath)` can return null; `runScript(conn, 
viewScript)` will then throw a `NullPointerException` (not caught in 
`runScript`). Add a null check and throw a `CloudRuntimeException` that 
includes the resolved `filePath` to make failures actionable.
   ```suggestion
                   InputStream viewScript = 
Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath);
                   if (viewScript == null) {
                       String message = String.format("Unable to find PROCEDURE 
script resource [%s] on the classpath.", filePath);
                       LOGGER.error(message);
                       throw new CloudRuntimeException(message);
                   }
   ```



##########
engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java:
##########
@@ -439,7 +442,10 @@ protected void executeViewScripts() {
             Connection conn = txn.getConnection();
 
             for (String filePath : filesPathUnderViewsDirectory) {
-                LOGGER.debug("Executing VIEW script [{}].", filePath);
+                LOGGER.debug(String.format("Executing VIEW script [%s].", 
filePath));
+                if (filePath.startsWith("/")) {
+                    filePath = filePath.substring(1);
+                }
 

Review Comment:
   Same as above: `String.format` eagerly builds the message even when debug 
logging is disabled. Prefer SLF4J parameterized logging 
(`LOGGER.debug("Executing VIEW script [{}].", filePath)`) and consider logging 
the normalized path if that’s what is executed.
   ```suggestion
                   if (filePath.startsWith("/")) {
                       filePath = filePath.substring(1);
                   }
   
                   LOGGER.debug("Executing VIEW script [{}].", filePath);
   ```



##########
engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java:
##########
@@ -439,7 +442,10 @@ protected void executeViewScripts() {
             Connection conn = txn.getConnection();
 
             for (String filePath : filesPathUnderViewsDirectory) {
-                LOGGER.debug("Executing VIEW script [{}].", filePath);
+                LOGGER.debug(String.format("Executing VIEW script [%s].", 
filePath));
+                if (filePath.startsWith("/")) {
+                    filePath = filePath.substring(1);
+                }
 
                 InputStream viewScript = 
Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath);

Review Comment:
   Same null-safety issue for view scripts: if `getResourceAsStream(filePath)` 
returns null, `runScript` will NPE. Add an explicit null check and fail with a 
clear exception that includes the script path.
   ```suggestion
                   InputStream viewScript = 
Thread.currentThread().getContextClassLoader().getResourceAsStream(filePath);
                   if (viewScript == null) {
                       String message = String.format("VIEW script resource 
[%s] could not be found on the classpath.", filePath);
                       LOGGER.error(message);
                       throw new CloudRuntimeException(message);
                   }
   ```



##########
engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java:
##########
@@ -327,7 +327,10 @@ protected void executeProcedureScripts() {
             Connection conn = txn.getConnection();
 
             for (String filePath : filesPathUnderViewsDirectory) {
-                LOGGER.debug("Executing PROCEDURE script [{}].", filePath);
+                LOGGER.debug(String.format("Executing PROCEDURE script [%s].", 
filePath));

Review Comment:
   Avoid `String.format` inside `LOGGER.debug(...)` here: it eagerly allocates 
even when debug logging is disabled and bypasses SLF4J parameterized logging. 
Prefer `LOGGER.debug("Executing PROCEDURE script [{}].", filePath)` (and 
similarly after normalizing `filePath` if you want the logged value to match 
what is executed).
   ```suggestion
                   LOGGER.debug("Executing PROCEDURE script [{}].", filePath);
   ```



##########
ui/src/views/offering/AddVpcOffering.vue:
##########
@@ -525,6 +525,12 @@ export default {
             { name: 'ConfigDrive' }
           ]
         })
+        services.push({
+          name: 'Firewall',
+          provider: [
+            { name: 'VpcVirtualRouter' }
+          ]
+        })

Review Comment:
   `Firewall` is only added to the services list for the non-NSX/non-Netris 
path. Since the backend changes add Firewall support to VPC offerings 
(including NSX/Netris VPC offerings via `VpcVirtualRouter`), the UI should also 
include the `Firewall` service in the NSX and Netris branches; otherwise those 
offerings can’t be configured with Firewall from the UI.



-- 
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