This is an automated email from the ASF dual-hosted git repository.

sureshanaparti pushed a commit to branch 4.19
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/4.19 by this push:
     new 7f0d9a03045 [Veeam] Check for failures in the restore process (#7224)
7f0d9a03045 is described below

commit 7f0d9a03045af506ea9f37dc40eec45bbeeb174f
Author: SadiJr <[email protected]>
AuthorDate: Tue Jun 25 16:11:38 2024 -0300

    [Veeam] Check for failures in the restore process (#7224)
    
    * Validate failure state in Veeam restore process
    
    * Address Daan review, and properly call method
    
    * Address bryan's reviews
    
    * remove return
    
    Co-authored-by: SadiJr <[email protected]>
    Co-authored-by: João Jandre <[email protected]>
---
 .../cloudstack/backup/veeam/VeeamClient.java       | 43 ++++++++++++++++++++--
 .../cloudstack/backup/veeam/VeeamClientTest.java   | 40 +++++++++++++++++++-
 2 files changed, 78 insertions(+), 5 deletions(-)

diff --git 
a/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/veeam/VeeamClient.java
 
b/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/veeam/VeeamClient.java
index 701c45f1a9d..befeb231015 100644
--- 
a/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/veeam/VeeamClient.java
+++ 
b/plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/veeam/VeeamClient.java
@@ -345,7 +345,7 @@ public class VeeamClient {
                         String type = pair.second();
                         String path = url.replace(apiURI.toString(), "");
                         if (type.equals("RestoreSession")) {
-                            return checkIfRestoreSessionFinished(type, path);
+                            checkIfRestoreSessionFinished(type, path);
                         }
                     }
                     return true;
@@ -361,17 +361,29 @@ public class VeeamClient {
         return false;
     }
 
-    protected boolean checkIfRestoreSessionFinished(String type, String path) 
throws IOException {
-        for (int j = 0; j < this.restoreTimeout; j++) {
+
+    /**
+     * Checks the status of the restore session. Checked states are "Success" 
and "Failure".<br/>
+     * There is also a timeout defined in the global configuration, 
backup.plugin.veeam.restore.timeout,<br/>
+     * that is used to wait for the restore to complete before throwing a 
{@link CloudRuntimeException}.
+     */
+    protected void checkIfRestoreSessionFinished(String type, String path) 
throws IOException {
+        for (int j = 0; j < restoreTimeout; j++) {
             HttpResponse relatedResponse = get(path);
             RestoreSession session = 
parseRestoreSessionResponse(relatedResponse);
             if (session.getResult().equals("Success")) {
-                return true;
+                return;
             }
+
             if (session.getResult().equalsIgnoreCase("Failed")) {
                 String sessionUid = session.getUid();
+                LOG.error(String.format("Failed to restore backup [%s] of VM 
[%s] due to [%s].",
+                        sessionUid, session.getVmDisplayName(),
+                        
getRestoreVmErrorDescription(StringUtils.substringAfterLast(sessionUid, ":"))));
                 throw new CloudRuntimeException(String.format("Restore job 
[%s] failed.", sessionUid));
             }
+            LOG.debug(String.format("Waiting %s seconds, out of a total of %s 
seconds, for the restore backup process to finish.", j, restoreTimeout));
+
             try {
                 Thread.sleep(1000);
             } catch (InterruptedException ignored) {
@@ -930,6 +942,29 @@ public class VeeamClient {
         return new Pair<>(result.first(), restoreLocation);
     }
 
+    /**
+     * Tries to retrieve the error's description of the Veeam restore task 
that resulted in an error.
+     * @param uid Session uid in Veeam of the restore process;
+     * @return the description found in Veeam about the cause of error in the 
restore process.
+     */
+    protected String getRestoreVmErrorDescription(String uid) {
+        LOG.debug(String.format("Trying to find the cause of error in the 
restore process [%s].", uid));
+        List<String> cmds = Arrays.asList(
+                String.format("$restoreUid = '%s'", uid),
+                "$restore = Get-VBRRestoreSession -Id $restoreUid",
+                "if ($restore) {",
+                    "Write-Output $restore.Description",
+                "} else {",
+                    "Write-Output 'Cannot find restore session with provided 
uid $restoreUid'",
+                "}"
+        );
+        Pair<Boolean, String> result = executePowerShellCommands(cmds);
+        if (result != null && result.first()) {
+            return result.second();
+        }
+        return String.format("Failed to get the description of the failed 
restore session [%s]. Please contact an administrator.", uid);
+    }
+
     private boolean isLegacyServer() {
         return this.veeamServerVersion != null && (this.veeamServerVersion > 0 
&& this.veeamServerVersion < 11);
     }
diff --git 
a/plugins/backup/veeam/src/test/java/org/apache/cloudstack/backup/veeam/VeeamClientTest.java
 
b/plugins/backup/veeam/src/test/java/org/apache/cloudstack/backup/veeam/VeeamClientTest.java
index 06804d68da2..26b2449b0fe 100644
--- 
a/plugins/backup/veeam/src/test/java/org/apache/cloudstack/backup/veeam/VeeamClientTest.java
+++ 
b/plugins/backup/veeam/src/test/java/org/apache/cloudstack/backup/veeam/VeeamClientTest.java
@@ -58,6 +58,8 @@ public class VeeamClientTest {
     private VeeamClient mockClient;
     private static final SimpleDateFormat newDateFormat = new 
SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
 
+    private VeeamClient mock = Mockito.mock(VeeamClient.class);
+
     @Rule
     public WireMockRule wireMockRule = new WireMockRule(9399);
 
@@ -161,7 +163,7 @@ public class VeeamClientTest {
             
Mockito.when(mockClient.get(Mockito.anyString())).thenReturn(httpResponse);
             
Mockito.when(mockClient.parseRestoreSessionResponse(httpResponse)).thenReturn(restoreSession);
             Mockito.when(restoreSession.getResult()).thenReturn("No Success");
-            
Mockito.when(mockClient.checkIfRestoreSessionFinished(Mockito.eq("RestoreTest"),
 Mockito.eq("any"))).thenCallRealMethod();
+            
Mockito.doCallRealMethod().when(mockClient).checkIfRestoreSessionFinished(Mockito.eq("RestoreTest"),
 Mockito.eq("any"));
             mockClient.checkIfRestoreSessionFinished("RestoreTest", "any");
             fail();
         } catch (Exception e) {
@@ -170,6 +172,42 @@ public class VeeamClientTest {
         Mockito.verify(mockClient, times(10)).get(Mockito.anyString());
     }
 
+    @Test
+    public void getRestoreVmErrorDescriptionTestFindErrorDescription() {
+        Pair<Boolean, String> response = new Pair<>(true, "Example of error 
description found in Veeam.");
+        
Mockito.when(mock.getRestoreVmErrorDescription("uuid")).thenCallRealMethod();
+        
Mockito.when(mock.executePowerShellCommands(Mockito.any())).thenReturn(response);
+        String result = mock.getRestoreVmErrorDescription("uuid");
+        Assert.assertEquals("Example of error description found in Veeam.", 
result);
+    }
+
+    @Test
+    public void getRestoreVmErrorDescriptionTestNotFindErrorDescription() {
+        Pair<Boolean, String> response = new Pair<>(true, "Cannot find restore 
session with provided uid uuid");
+        
Mockito.when(mock.getRestoreVmErrorDescription("uuid")).thenCallRealMethod();
+        
Mockito.when(mock.executePowerShellCommands(Mockito.any())).thenReturn(response);
+        String result = mock.getRestoreVmErrorDescription("uuid");
+        Assert.assertEquals("Cannot find restore session with provided uid 
uuid", result);
+    }
+
+    @Test
+    public void getRestoreVmErrorDescriptionTestWhenPowerShellOutputIsNull() {
+        
Mockito.when(mock.getRestoreVmErrorDescription("uuid")).thenCallRealMethod();
+        
Mockito.when(mock.executePowerShellCommands(Mockito.any())).thenReturn(null);
+        String result = mock.getRestoreVmErrorDescription("uuid");
+        Assert.assertEquals("Failed to get the description of the failed 
restore session [uuid]. Please contact an administrator.", result);
+    }
+
+    @Test
+    public void getRestoreVmErrorDescriptionTestWhenPowerShellOutputIsFalse() {
+        Pair<Boolean, String> response = new Pair<>(false, null);
+        
Mockito.when(mock.getRestoreVmErrorDescription("uuid")).thenCallRealMethod();
+        
Mockito.when(mock.executePowerShellCommands(Mockito.any())).thenReturn(response);
+        String result = mock.getRestoreVmErrorDescription("uuid");
+        Assert.assertEquals("Failed to get the description of the failed 
restore session [uuid]. Please contact an administrator.", result);
+    }
+
+
     private void verifyBackupMetrics(Map<String, Backup.Metric> metrics) {
         Assert.assertEquals(2, metrics.size());
 

Reply via email to