2929
3030import javax .inject .Inject ;
3131
32+ import org .apache .cloudstack .api .ApiCommandResourceType ;
3233import org .apache .cloudstack .api .InternalIdentity ;
3334import org .apache .cloudstack .backup .Backup .Metric ;
3435import org .apache .cloudstack .backup .dao .BackupDao ;
4041import org .apache .commons .lang3 .BooleanUtils ;
4142import org .apache .log4j .Logger ;
4243
44+ import com .cloud .agent .AgentManager ;
45+ import com .cloud .agent .api .Answer ;
46+ import com .cloud .event .ActionEventUtils ;
47+ import com .cloud .event .EventTypes ;
48+ import com .cloud .event .EventVO ;
4349import com .cloud .hypervisor .Hypervisor ;
4450import com .cloud .dc .VmwareDatacenter ;
4551import com .cloud .hypervisor .vmware .VmwareDatacenterZoneMap ;
4652import com .cloud .dc .dao .VmwareDatacenterDao ;
4753import com .cloud .hypervisor .vmware .dao .VmwareDatacenterZoneMapDao ;
54+ import com .cloud .user .User ;
4855import com .cloud .utils .Pair ;
4956import com .cloud .utils .component .AdapterBase ;
5057import com .cloud .utils .db .Transaction ;
5360import com .cloud .utils .exception .CloudRuntimeException ;
5461import com .cloud .vm .VMInstanceVO ;
5562import com .cloud .vm .VirtualMachine ;
63+ import com .cloud .vm .VirtualMachineManager ;
5664import com .cloud .vm .dao .VMInstanceDao ;
5765
5866public class VeeamBackupProvider extends AdapterBase implements BackupProvider , Configurable {
@@ -64,6 +72,10 @@ public class VeeamBackupProvider extends AdapterBase implements BackupProvider,
6472 "backup.plugin.veeam.url" , "https://localhost:9398/api/" ,
6573 "The Veeam backup and recovery URL." , true , ConfigKey .Scope .Zone );
6674
75+ public ConfigKey <Integer > VeeamVersion = new ConfigKey <>("Advanced" , Integer .class ,
76+ "backup.plugin.veeam.version" , "0" ,
77+ "The version of Veeam backup and recovery. CloudStack will get Veeam server version via PowerShell commands if it is 0 or not set" , true , ConfigKey .Scope .Zone );
78+
6779 private ConfigKey <String > VeeamUsername = new ConfigKey <>("Advanced" , String .class ,
6880 "backup.plugin.veeam.username" , "administrator" ,
6981 "The Veeam backup and recovery username." , true , ConfigKey .Scope .Zone );
@@ -81,6 +93,12 @@ public class VeeamBackupProvider extends AdapterBase implements BackupProvider,
8193 private static ConfigKey <Integer > VeeamRestoreTimeout = new ConfigKey <>("Advanced" , Integer .class , "backup.plugin.veeam.restore.timeout" , "600" ,
8294 "The Veeam B&R API restore backup timeout in seconds." , true , ConfigKey .Scope .Zone );
8395
96+ private static ConfigKey <Integer > VeeamTaskPollInterval = new ConfigKey <>("Advanced" , Integer .class , "backup.plugin.veeam.task.poll.interval" , "5" ,
97+ "The time interval in seconds when the management server polls for Veeam task status." , true , ConfigKey .Scope .Zone );
98+
99+ private static ConfigKey <Integer > VeeamTaskPollMaxRetry = new ConfigKey <>("Advanced" , Integer .class , "backup.plugin.veeam.task.poll.max.retry" , "120" ,
100+ "The max number of retrying times when the management server polls for Veeam task status." , true , ConfigKey .Scope .Zone );
101+
84102 @ Inject
85103 private VmwareDatacenterZoneMapDao vmwareDatacenterZoneMapDao ;
86104 @ Inject
@@ -89,11 +107,16 @@ public class VeeamBackupProvider extends AdapterBase implements BackupProvider,
89107 private BackupDao backupDao ;
90108 @ Inject
91109 private VMInstanceDao vmInstanceDao ;
110+ @ Inject
111+ private AgentManager agentMgr ;
112+ @ Inject
113+ private VirtualMachineManager virtualMachineManager ;
92114
93115 protected VeeamClient getClient (final Long zoneId ) {
94116 try {
95- return new VeeamClient (VeeamUrl .valueIn (zoneId ), VeeamUsername .valueIn (zoneId ), VeeamPassword .valueIn (zoneId ),
96- VeeamValidateSSLSecurity .valueIn (zoneId ), VeeamApiRequestTimeout .valueIn (zoneId ), VeeamRestoreTimeout .valueIn (zoneId ));
117+ return new VeeamClient (VeeamUrl .valueIn (zoneId ), VeeamVersion .valueIn (zoneId ), VeeamUsername .valueIn (zoneId ), VeeamPassword .valueIn (zoneId ),
118+ VeeamValidateSSLSecurity .valueIn (zoneId ), VeeamApiRequestTimeout .valueIn (zoneId ), VeeamRestoreTimeout .valueIn (zoneId ),
119+ VeeamTaskPollInterval .valueIn (zoneId ), VeeamTaskPollMaxRetry .valueIn (zoneId ));
97120 } catch (URISyntaxException e ) {
98121 throw new CloudRuntimeException ("Failed to parse Veeam API URL: " + e .getMessage ());
99122 } catch (NoSuchAlgorithmException | KeyManagementException e ) {
@@ -189,6 +212,7 @@ public boolean removeVMFromBackupOffering(final VirtualMachine vm) {
189212 LOG .warn ("Failed to remove Veeam job and backup for job: " + clonedJobName );
190213 throw new CloudRuntimeException ("Failed to delete Veeam B&R job and backup, an operation may be in progress. Please try again after some time." );
191214 }
215+ client .syncBackupRepository ();
192216 return true ;
193217 }
194218
@@ -222,6 +246,8 @@ public boolean deleteBackup(Backup backup, boolean forced) {
222246 return false ;
223247 }
224248
249+ client .syncBackupRepository ();
250+
225251 List <Backup > allBackups = backupDao .listByVmId (backup .getZoneId (), backup .getVmId ());
226252 for (Backup b : allBackups ) {
227253 if (b .getId () != backup .getId ()) {
@@ -234,7 +260,36 @@ public boolean deleteBackup(Backup backup, boolean forced) {
234260 @ Override
235261 public boolean restoreVMFromBackup (VirtualMachine vm , Backup backup ) {
236262 final String restorePointId = backup .getExternalId ();
237- return getClient (vm .getDataCenterId ()).restoreFullVM (vm .getInstanceName (), restorePointId );
263+ try {
264+ return getClient (vm .getDataCenterId ()).restoreFullVM (vm .getInstanceName (), restorePointId );
265+ } catch (Exception ex ) {
266+ LOG .error (String .format ("Failed to restore Full VM due to: %s. Retrying after some preparation" , ex .getMessage ()));
267+ prepareForBackupRestoration (vm );
268+ return getClient (vm .getDataCenterId ()).restoreFullVM (vm .getInstanceName (), restorePointId );
269+ }
270+ }
271+
272+ private void prepareForBackupRestoration (VirtualMachine vm ) {
273+ if (!Hypervisor .HypervisorType .VMware .equals (vm .getHypervisorType ())) {
274+ return ;
275+ }
276+ LOG .info ("Preparing for restoring VM " + vm );
277+ PrepareForBackupRestorationCommand command = new PrepareForBackupRestorationCommand (vm .getInstanceName ());
278+ Long hostId = virtualMachineManager .findClusterAndHostIdForVm (vm .getId ()).second ();
279+ if (hostId == null ) {
280+ throw new CloudRuntimeException ("Cannot find a host to prepare for restoring VM " + vm );
281+ }
282+ try {
283+ Answer answer = agentMgr .easySend (hostId , command );
284+ if (answer != null && answer .getResult ()) {
285+ LOG .info ("Succeeded to prepare for restoring VM " + vm );
286+ } else {
287+ throw new CloudRuntimeException (String .format ("Failed to prepare for restoring VM %s. details: %s" , vm ,
288+ (answer != null ? answer .getDetails () : null )));
289+ }
290+ } catch (Exception e ) {
291+ throw new CloudRuntimeException (String .format ("Failed to prepare for restoring VM %s due to exception %s" , vm , e ));
292+ }
238293 }
239294
240295 @ Override
@@ -330,6 +385,10 @@ public void doInTransactionWithoutResult(TransactionStatus status) {
330385 + "domain_id: %s, zone_id: %s]." , backup .getUuid (), backup .getVmId (), backup .getExternalId (), backup .getType (), backup .getDate (),
331386 backup .getBackupOfferingId (), backup .getAccountId (), backup .getDomainId (), backup .getZoneId ()));
332387 backupDao .persist (backup );
388+
389+ ActionEventUtils .onCompletedActionEvent (User .UID_SYSTEM , vm .getAccountId (), EventVO .LEVEL_INFO , EventTypes .EVENT_VM_BACKUP_CREATE ,
390+ String .format ("Created backup %s for VM ID: %s" , backup .getUuid (), vm .getUuid ()),
391+ vm .getId (), ApiCommandResourceType .VirtualMachine .toString (),0 );
333392 }
334393 }
335394 for (final Long backupIdToRemove : removeList ) {
@@ -349,11 +408,14 @@ public String getConfigComponentName() {
349408 public ConfigKey <?>[] getConfigKeys () {
350409 return new ConfigKey []{
351410 VeeamUrl ,
411+ VeeamVersion ,
352412 VeeamUsername ,
353413 VeeamPassword ,
354414 VeeamValidateSSLSecurity ,
355415 VeeamApiRequestTimeout ,
356- VeeamRestoreTimeout
416+ VeeamRestoreTimeout ,
417+ VeeamTaskPollInterval ,
418+ VeeamTaskPollMaxRetry
357419 };
358420 }
359421
0 commit comments