Skip to content

Commit 37bb24f

Browse files
committed
Merge branch '4.19'
2 parents 4d370a3 + c795547 commit 37bb24f

File tree

30 files changed

+1723
-193
lines changed

30 files changed

+1723
-193
lines changed

api/src/main/java/org/apache/cloudstack/api/command/user/vm/ListVMsCmd.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,8 @@ public class ListVMsCmd extends BaseListRetrieveOnlyResourceCountCmd implements
9696
@Parameter(name = ApiConstants.DETAILS,
9797
type = CommandType.LIST,
9898
collectionType = CommandType.STRING,
99-
description = "comma separated list of host details requested, "
100-
+ "value can be a list of [all, group, nics, stats, secgrp, tmpl, servoff, diskoff, iso, volume, min, affgrp]."
99+
description = "comma separated list of vm details requested, "
100+
+ "value can be a list of [all, group, nics, stats, secgrp, tmpl, servoff, diskoff, backoff, iso, volume, min, affgrp]."
101101
+ " If no parameter is passed in, the details will be defaulted to all")
102102
private List<String> viewDetails;
103103

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//
2+
// Licensed to the Apache Software Foundation (ASF) under one
3+
// or more contributor license agreements. See the NOTICE file
4+
// distributed with this work for additional information
5+
// regarding copyright ownership. The ASF licenses this file
6+
// to you under the Apache License, Version 2.0 (the
7+
// "License"); you may not use this file except in compliance
8+
// with the License. You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing,
13+
// software distributed under the License is distributed on an
14+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
// KIND, either express or implied. See the License for the
16+
// specific language governing permissions and limitations
17+
// under the License.
18+
//
19+
20+
package org.apache.cloudstack.backup;
21+
22+
import com.cloud.agent.api.Command;
23+
24+
public class PrepareForBackupRestorationCommand extends Command {
25+
26+
private String vmName;
27+
28+
protected PrepareForBackupRestorationCommand() {
29+
}
30+
31+
public PrepareForBackupRestorationCommand(String vmName) {
32+
this.vmName = vmName;
33+
}
34+
35+
public String getVmName() {
36+
return vmName;
37+
}
38+
39+
@Override
40+
public boolean executeInSequence() {
41+
return true;
42+
}
43+
}

engine/schema/src/main/java/org/apache/cloudstack/backup/BackupVO.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717

1818
package org.apache.cloudstack.backup;
1919

20+
import com.cloud.utils.db.GenericDao;
21+
2022
import java.util.Date;
2123
import java.util.UUID;
2224

@@ -55,6 +57,9 @@ public class BackupVO implements Backup {
5557
@Temporal(value = TemporalType.DATE)
5658
private Date date;
5759

60+
@Column(name = GenericDao.REMOVED_COLUMN)
61+
private Date removed;
62+
5863
@Column(name = "size")
5964
private Long size;
6065

@@ -196,4 +201,12 @@ public Class<?> getEntityType() {
196201
public String getName() {
197202
return null;
198203
}
204+
205+
public Date getRemoved() {
206+
return removed;
207+
}
208+
209+
public void setRemoved(Date removed) {
210+
this.removed = removed;
211+
}
199212
}

plugins/backup/veeam/pom.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,21 @@
2828
</parent>
2929

3030
<dependencies>
31+
<dependency>
32+
<groupId>org.apache.cloudstack</groupId>
33+
<artifactId>cloud-core</artifactId>
34+
<version>${project.version}</version>
35+
</dependency>
36+
<dependency>
37+
<groupId>org.apache.cloudstack</groupId>
38+
<artifactId>cloud-engine-api</artifactId>
39+
<version>${project.version}</version>
40+
</dependency>
41+
<dependency>
42+
<groupId>org.apache.cloudstack</groupId>
43+
<artifactId>cloud-engine-components-api</artifactId>
44+
<version>${project.version}</version>
45+
</dependency>
3146
<dependency>
3247
<groupId>org.apache.cloudstack</groupId>
3348
<artifactId>cloud-plugin-hypervisor-vmware</artifactId>

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

Lines changed: 66 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929

3030
import javax.inject.Inject;
3131

32+
import org.apache.cloudstack.api.ApiCommandResourceType;
3233
import org.apache.cloudstack.api.InternalIdentity;
3334
import org.apache.cloudstack.backup.Backup.Metric;
3435
import org.apache.cloudstack.backup.dao.BackupDao;
@@ -40,11 +41,17 @@
4041
import org.apache.commons.lang3.BooleanUtils;
4142
import 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;
4349
import com.cloud.hypervisor.Hypervisor;
4450
import com.cloud.dc.VmwareDatacenter;
4551
import com.cloud.hypervisor.vmware.VmwareDatacenterZoneMap;
4652
import com.cloud.dc.dao.VmwareDatacenterDao;
4753
import com.cloud.hypervisor.vmware.dao.VmwareDatacenterZoneMapDao;
54+
import com.cloud.user.User;
4855
import com.cloud.utils.Pair;
4956
import com.cloud.utils.component.AdapterBase;
5057
import com.cloud.utils.db.Transaction;
@@ -53,6 +60,7 @@
5360
import com.cloud.utils.exception.CloudRuntimeException;
5461
import com.cloud.vm.VMInstanceVO;
5562
import com.cloud.vm.VirtualMachine;
63+
import com.cloud.vm.VirtualMachineManager;
5664
import com.cloud.vm.dao.VMInstanceDao;
5765

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

Comments
 (0)