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


##########
engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java:
##########
@@ -448,39 +451,71 @@ public void check() {
                 throw new CloudRuntimeException("Unable to acquire lock to 
check for database integrity.");
             }
 
-            try {
-                initializeDatabaseEncryptors();
+            // not sure about the right moment to do this yet
+            checkIfStandalone();
+            doUpgrades(lock);
+        } finally {
+            lock.releaseRef();
+        }
+    }
+    private void checkIfStandalone() throws CloudRuntimeException {
+        boolean standalone = Transaction.execute(new TransactionCallback<>() {
+            @Override
+            public Boolean doInTransaction(TransactionStatus status) {
+                String sql = "SELECT COUNT(*) FROM `cloud`.`management_server` 
WHERE `status` = 'UP'";
+                try (Connection conn  = 
TransactionLegacy.getStandaloneConnection();
+                     PreparedStatement pstmt = conn.prepareStatement(sql);
+                     ResultSet rs = pstmt.executeQuery()) {
+                    if (rs.next()) {
+                        int count = rs.getInt(1);
+                        return count <= 1;
+                    }
+                } catch (SQLException e) {
+                    String errorMessage = "Unable to check if the management 
server is running in standalone mode.";
+                    LOGGER.error(errorMessage, e);
+                    throw new CloudRuntimeException(errorMessage, e);
+                }
+                return true;
+            }
+        });
+        if (! standalone) {
+            String msg = "CloudStack is running multiple management servers 
and attempting to upgrade. Upgrades can only be run in standalone mode. 
Skipping database upgrade check.";

Review Comment:
   The error message is misleading. It says "Skipping database upgrade check" 
but the code is actually throwing an exception which will abort the upgrade 
process, not skip it. 
   
   Consider revising the message to something like: "CloudStack is running 
multiple management servers. Database upgrades can only be performed in 
standalone mode. Aborting upgrade."
   ```suggestion
               String msg = "CloudStack is running multiple management servers. 
Database upgrades can only be performed in standalone mode. Aborting upgrade.";
   ```



##########
engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java:
##########
@@ -448,39 +451,71 @@ public void check() {
                 throw new CloudRuntimeException("Unable to acquire lock to 
check for database integrity.");
             }
 
-            try {
-                initializeDatabaseEncryptors();
+            // not sure about the right moment to do this yet

Review Comment:
   This comment should be removed before merging. It indicates uncertainty 
about the implementation ("not sure about the right moment to do this yet"), 
which suggests the code may need further review or testing before being 
production-ready.
   ```suggestion
   
   ```



##########
engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java:
##########
@@ -448,39 +451,71 @@ public void check() {
                 throw new CloudRuntimeException("Unable to acquire lock to 
check for database integrity.");
             }
 
-            try {
-                initializeDatabaseEncryptors();
+            // not sure about the right moment to do this yet
+            checkIfStandalone();
+            doUpgrades(lock);
+        } finally {
+            lock.releaseRef();
+        }
+    }
+    private void checkIfStandalone() throws CloudRuntimeException {
+        boolean standalone = Transaction.execute(new TransactionCallback<>() {
+            @Override
+            public Boolean doInTransaction(TransactionStatus status) {
+                String sql = "SELECT COUNT(*) FROM `cloud`.`management_server` 
WHERE `status` = 'UP'";
+                try (Connection conn  = 
TransactionLegacy.getStandaloneConnection();
+                     PreparedStatement pstmt = conn.prepareStatement(sql);
+                     ResultSet rs = pstmt.executeQuery()) {
+                    if (rs.next()) {
+                        int count = rs.getInt(1);
+                        return count <= 1;
+                    }
+                } catch (SQLException e) {
+                    String errorMessage = "Unable to check if the management 
server is running in standalone mode.";
+                    LOGGER.error(errorMessage, e);
+                    throw new CloudRuntimeException(errorMessage, e);
+                }
+                return true;
+            }
+        });

Review Comment:
   The `Transaction.execute()` wrapper is unnecessary here. The code inside the 
callback is obtaining its own standalone connection via 
`TransactionLegacy.getStandaloneConnection()`, which means the transaction 
context provided by `Transaction.execute()` is not being used. 
   
   Consider simplifying this to directly execute the query without the 
Transaction.execute wrapper, or use the TransactionStatus parameter properly if 
transaction management is needed.
   ```suggestion
           String sql = "SELECT COUNT(*) FROM `cloud`.`management_server` WHERE 
`status` = 'UP'";
           boolean standalone = true;
           try (Connection conn  = TransactionLegacy.getStandaloneConnection();
                PreparedStatement pstmt = conn.prepareStatement(sql);
                ResultSet rs = pstmt.executeQuery()) {
               if (rs.next()) {
                   int count = rs.getInt(1);
                   standalone = count <= 1;
               }
           } catch (SQLException e) {
               String errorMessage = "Unable to check if the management server 
is running in standalone mode.";
               LOGGER.error(errorMessage, e);
               throw new CloudRuntimeException(errorMessage, e);
           }
   ```



##########
engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java:
##########
@@ -448,39 +451,71 @@ public void check() {
                 throw new CloudRuntimeException("Unable to acquire lock to 
check for database integrity.");
             }
 
-            try {
-                initializeDatabaseEncryptors();
+            // not sure about the right moment to do this yet
+            checkIfStandalone();
+            doUpgrades(lock);
+        } finally {
+            lock.releaseRef();
+        }
+    }
+    private void checkIfStandalone() throws CloudRuntimeException {
+        boolean standalone = Transaction.execute(new TransactionCallback<>() {
+            @Override
+            public Boolean doInTransaction(TransactionStatus status) {
+                String sql = "SELECT COUNT(*) FROM `cloud`.`management_server` 
WHERE `status` = 'UP'";
+                try (Connection conn  = 
TransactionLegacy.getStandaloneConnection();
+                     PreparedStatement pstmt = conn.prepareStatement(sql);
+                     ResultSet rs = pstmt.executeQuery()) {
+                    if (rs.next()) {
+                        int count = rs.getInt(1);
+                        return count <= 1;
+                    }
+                } catch (SQLException e) {
+                    String errorMessage = "Unable to check if the management 
server is running in standalone mode.";
+                    LOGGER.error(errorMessage, e);
+                    throw new CloudRuntimeException(errorMessage, e);
+                }
+                return true;
+            }
+        });
+        if (! standalone) {
+            String msg = "CloudStack is running multiple management servers 
and attempting to upgrade. Upgrades can only be run in standalone mode. 
Skipping database upgrade check.";
+            LOGGER.info(msg);

Review Comment:
   The log level should be `LOGGER.error()` instead of `LOGGER.info()` since an 
exception is being thrown immediately after. This is an error condition, not 
informational.
   ```suggestion
               LOGGER.error(msg);
   ```



##########
engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java:
##########
@@ -448,39 +451,71 @@ public void check() {
                 throw new CloudRuntimeException("Unable to acquire lock to 
check for database integrity.");
             }
 
-            try {
-                initializeDatabaseEncryptors();
+            // not sure about the right moment to do this yet
+            checkIfStandalone();
+            doUpgrades(lock);
+        } finally {
+            lock.releaseRef();
+        }
+    }
+    private void checkIfStandalone() throws CloudRuntimeException {
+        boolean standalone = Transaction.execute(new TransactionCallback<>() {
+            @Override
+            public Boolean doInTransaction(TransactionStatus status) {
+                String sql = "SELECT COUNT(*) FROM `cloud`.`management_server` 
WHERE `status` = 'UP'";
+                try (Connection conn  = 
TransactionLegacy.getStandaloneConnection();
+                     PreparedStatement pstmt = conn.prepareStatement(sql);
+                     ResultSet rs = pstmt.executeQuery()) {
+                    if (rs.next()) {
+                        int count = rs.getInt(1);
+                        return count <= 1;
+                    }
+                } catch (SQLException e) {
+                    String errorMessage = "Unable to check if the management 
server is running in standalone mode.";
+                    LOGGER.error(errorMessage, e);
+                    throw new CloudRuntimeException(errorMessage, e);
+                }
+                return true;
+            }
+        });
+        if (! standalone) {
+            String msg = "CloudStack is running multiple management servers 
and attempting to upgrade. Upgrades can only be run in standalone mode. 
Skipping database upgrade check.";
+            LOGGER.info(msg);
+            throw new CloudRuntimeException(msg);
+        }
+    }

Review Comment:
   The new `checkIfStandalone()` method lacks test coverage. Consider adding 
unit tests to verify:
   1. The behavior when no management servers are running (count = 0)
   2. The behavior when exactly one management server is running (count = 1)  
   3. The behavior when multiple management servers are running (count > 1)
   4. The behavior when a SQLException occurs during the check
   
   This is particularly important since this check prevents upgrades from 
proceeding when multiple servers are detected.



##########
engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java:
##########
@@ -448,39 +451,71 @@ public void check() {
                 throw new CloudRuntimeException("Unable to acquire lock to 
check for database integrity.");
             }
 
-            try {
-                initializeDatabaseEncryptors();
+            // not sure about the right moment to do this yet
+            checkIfStandalone();
+            doUpgrades(lock);
+        } finally {
+            lock.releaseRef();
+        }
+    }
+    private void checkIfStandalone() throws CloudRuntimeException {
+        boolean standalone = Transaction.execute(new TransactionCallback<>() {
+            @Override
+            public Boolean doInTransaction(TransactionStatus status) {
+                String sql = "SELECT COUNT(*) FROM `cloud`.`management_server` 
WHERE `status` = 'UP'";
+                try (Connection conn  = 
TransactionLegacy.getStandaloneConnection();
+                     PreparedStatement pstmt = conn.prepareStatement(sql);
+                     ResultSet rs = pstmt.executeQuery()) {
+                    if (rs.next()) {
+                        int count = rs.getInt(1);
+                        return count <= 1;
+                    }

Review Comment:
   The logic `count <= 1` may be problematic. If the count is 0, it means no 
management servers are registered as 'UP' in the database, including the 
current server executing this check. This could indicate:
   1. The current server hasn't registered itself yet in the management_server 
table
   2. A database connectivity or query issue
   
   Consider whether the check should fail if count is 0, or if this scenario is 
expected during startup. The condition might be more accurate as `count == 1` 
with explicit handling for the count == 0 case.
   ```suggestion
                           if (count == 1) {
                               return true;
                           } else if (count == 0) {
                               String errorMessage = "No management servers are 
registered as 'UP' in the database. This may indicate a startup issue or a 
database connectivity problem.";
                               LOGGER.error(errorMessage);
                               throw new CloudRuntimeException(errorMessage);
                           } else {
                               return false;
                           }
   ```



##########
engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java:
##########
@@ -448,39 +451,71 @@ public void check() {
                 throw new CloudRuntimeException("Unable to acquire lock to 
check for database integrity.");
             }
 
-            try {
-                initializeDatabaseEncryptors();
+            // not sure about the right moment to do this yet
+            checkIfStandalone();

Review Comment:
   If `checkIfStandalone()` throws an exception, the database lock will remain 
held (not unlocked) even though the reference is released in the finally block. 
This could prevent other processes from acquiring the lock.
   
   Consider ensuring `lock.unlock()` is called in all error paths, or move 
`checkIfStandalone()` inside `doUpgrades()` so it's protected by the same 
try-finally that handles `lock.unlock()`.
   ```suggestion
   
   ```



##########
engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java:
##########
@@ -448,39 +451,71 @@ public void check() {
                 throw new CloudRuntimeException("Unable to acquire lock to 
check for database integrity.");
             }
 
-            try {
-                initializeDatabaseEncryptors();
+            // not sure about the right moment to do this yet
+            checkIfStandalone();
+            doUpgrades(lock);
+        } finally {
+            lock.releaseRef();
+        }
+    }
+    private void checkIfStandalone() throws CloudRuntimeException {
+        boolean standalone = Transaction.execute(new TransactionCallback<>() {
+            @Override
+            public Boolean doInTransaction(TransactionStatus status) {
+                String sql = "SELECT COUNT(*) FROM `cloud`.`management_server` 
WHERE `status` = 'UP'";
+                try (Connection conn  = 
TransactionLegacy.getStandaloneConnection();

Review Comment:
   [nitpick] Extra whitespace after `conn` before the closing parenthesis. 
Should be `Connection conn = TransactionLegacy.getStandaloneConnection();` for 
consistency.
   ```suggestion
                   try (Connection conn = 
TransactionLegacy.getStandaloneConnection();
   ```



##########
engine/schema/src/main/java/com/cloud/upgrade/DatabaseUpgradeChecker.java:
##########
@@ -448,39 +451,71 @@ public void check() {
                 throw new CloudRuntimeException("Unable to acquire lock to 
check for database integrity.");
             }
 
-            try {
-                initializeDatabaseEncryptors();
+            // not sure about the right moment to do this yet
+            checkIfStandalone();
+            doUpgrades(lock);
+        } finally {
+            lock.releaseRef();
+        }
+    }
+    private void checkIfStandalone() throws CloudRuntimeException {

Review Comment:
   [nitpick] Consider renaming this method to be more descriptive of what it 
does, such as `checkNoOtherManagementServersRunning()` or 
`validateSingleManagementServerMode()`. The current name `checkIfStandalone()` 
doesn't clearly indicate that it throws an exception on failure rather than 
returning a boolean result.
   ```suggestion
               validateSingleManagementServerMode();
               doUpgrades(lock);
           } finally {
               lock.releaseRef();
           }
       }
       private void validateSingleManagementServerMode() throws 
CloudRuntimeException {
   ```



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