Skip to content

Commit 6fe60d6

Browse files
SadiJrJoaoJandre
authored andcommitted
Validate failure state in Veeam restore process
1 parent 8b02624 commit 6fe60d6

File tree

2 files changed

+81
-1
lines changed

2 files changed

+81
-1
lines changed

plugins/backup/veeam/src/main/java/org/apache/cloudstack/backup/veeam/VeeamClient.java

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,26 @@ private boolean checkTaskStatus(final HttpResponse response) throws IOException
345345
String type = pair.second();
346346
String path = url.replace(apiURI.toString(), "");
347347
if (type.equals("RestoreSession")) {
348-
return checkIfRestoreSessionFinished(type, path);
348+
for (int j = 0; j < restoreTimeout; j++) {
349+
HttpResponse relatedResponse = get(path);
350+
RestoreSession session = parseRestoreSessionResponse(relatedResponse);
351+
if (session.getResult().equals("Success")) {
352+
return true;
353+
}
354+
if (session.getResult().equalsIgnoreCase("Failed")) {
355+
String sessionUid = session.getUid();
356+
LOG.error(String.format("Failed to restore backup [%s] of VM [%s] due to [%s].",
357+
sessionUid, session.getVmDisplayName(),
358+
getRestoreVmErrorDescription(StringUtils.substringAfterLast(sessionUid, ":"))));
359+
throw new CloudRuntimeException(String.format("Restore job [%s] failed.", sessionUid));
360+
}
361+
LOG.debug(String.format("Waiting %s seconds, out of a total of %s seconds, for the backup process to finish.", j, restoreTimeout));
362+
try {
363+
Thread.sleep(1000);
364+
} catch (InterruptedException ignored) {
365+
}
366+
}
367+
throw new CloudRuntimeException("Related job type: " + type + " was not successful");
349368
}
350369
}
351370
return true;
@@ -930,6 +949,29 @@ public Pair<Boolean, String> restoreVMToDifferentLocation(String restorePointId,
930949
return new Pair<>(result.first(), restoreLocation);
931950
}
932951

952+
/**
953+
* Tries to retrieve the error's descripton of the Veeam restore task that errored.
954+
* @param uid Session uid in Veeam of restore process;
955+
* @return the description found in Veeam about the cause of error in restore process.
956+
*/
957+
protected String getRestoreVmErrorDescription(String uid) {
958+
LOG.debug(String.format("Trying to find cause of error in restore process [%s].", uid));
959+
List<String> cmds = Arrays.asList(
960+
String.format("$restoreUid = '%s'", uid),
961+
"$restore = Get-VBRRestoreSession -Id $restoreUid",
962+
"if ($restore) {",
963+
"Write-Output $restore.Description",
964+
"} else {",
965+
"Write-Output 'Cannot find restore session with provided uid $restoreUid'",
966+
"}"
967+
);
968+
Pair<Boolean, String> result = executePowerShellCommands(cmds);
969+
if (result != null && result.first()) {
970+
return result.second();
971+
}
972+
return String.format("Failed to get description of failed restore session [%s]. Please contact an administrator.", uid);
973+
}
974+
933975
private boolean isLegacyServer() {
934976
return this.veeamServerVersion != null && (this.veeamServerVersion > 0 && this.veeamServerVersion < 11);
935977
}

plugins/backup/veeam/src/test/java/org/apache/cloudstack/backup/veeam/VeeamClientTest.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ public class VeeamClientTest {
5858
private VeeamClient mockClient;
5959
private static final SimpleDateFormat newDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
6060

61+
private VeeamClient mock = Mockito.mock(VeeamClient.class);
62+
6163
@Rule
6264
public WireMockRule wireMockRule = new WireMockRule(9399);
6365

@@ -170,6 +172,42 @@ public void checkIfRestoreSessionFinishedTestTimeoutException() throws IOExcepti
170172
Mockito.verify(mockClient, times(10)).get(Mockito.anyString());
171173
}
172174

175+
@Test
176+
public void getRestoreVmErrorDescriptionTestFindErrorDescription() {
177+
Pair<Boolean, String> response = new Pair<>(true, "Example of error description found in Veeam.");
178+
Mockito.when(mock.getRestoreVmErrorDescription("uuid")).thenCallRealMethod();
179+
Mockito.when(mock.executePowerShellCommands(Mockito.any())).thenReturn(response);
180+
String result = mock.getRestoreVmErrorDescription("uuid");
181+
Assert.assertEquals("Example of error description found in Veeam.", result);
182+
}
183+
184+
@Test
185+
public void getRestoreVmErrorDescriptionTestNotFindErrorDescription() {
186+
Pair<Boolean, String> response = new Pair<>(true, "Cannot find restore session with provided uid uuid");
187+
Mockito.when(mock.getRestoreVmErrorDescription("uuid")).thenCallRealMethod();
188+
Mockito.when(mock.executePowerShellCommands(Mockito.any())).thenReturn(response);
189+
String result = mock.getRestoreVmErrorDescription("uuid");
190+
Assert.assertEquals("Cannot find restore session with provided uid uuid", result);
191+
}
192+
193+
@Test
194+
public void getRestoreVmErrorDescriptionTestWhenPowerShellOutputIsNull() {
195+
Mockito.when(mock.getRestoreVmErrorDescription("uuid")).thenCallRealMethod();
196+
Mockito.when(mock.executePowerShellCommands(Mockito.any())).thenReturn(null);
197+
String result = mock.getRestoreVmErrorDescription("uuid");
198+
Assert.assertEquals("Failed to get description of failed restore session [uuid]. Please contact an administrator.", result);
199+
}
200+
201+
@Test
202+
public void getRestoreVmErrorDescriptionTestWhenPowerShellOutputIsFalse() {
203+
Pair<Boolean, String> response = new Pair<>(false, null);
204+
Mockito.when(mock.getRestoreVmErrorDescription("uuid")).thenCallRealMethod();
205+
Mockito.when(mock.executePowerShellCommands(Mockito.any())).thenReturn(response);
206+
String result = mock.getRestoreVmErrorDescription("uuid");
207+
Assert.assertEquals("Failed to get description of failed restore session [uuid]. Please contact an administrator.", result);
208+
}
209+
210+
173211
private void verifyBackupMetrics(Map<String, Backup.Metric> metrics) {
174212
Assert.assertEquals(2, metrics.size());
175213

0 commit comments

Comments
 (0)