Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
ecc953f
pom.xml: add veeam
weizhouapache Oct 20, 2023
7bd8562
Veeam: import powershell module which is available since Veeam 11
weizhouapache Oct 25, 2023
1459cc4
Veeam: silently ignore the warning messages when import Veeam module
weizhouapache Oct 25, 2023
8ea34d6
Veeam: fix issue when assign vm to backup offerings
weizhouapache Oct 25, 2023
7a3ddf7
Veeam: add marvin test
weizhouapache Oct 26, 2023
3672104
veeam: force delete backup
weizhouapache Oct 27, 2023
02c04b2
backup: enable group-delete action on UI
weizhouapache Nov 2, 2023
3756420
veeam: fix authorization failure in veeam 12a
weizhouapache Nov 3, 2023
08d8725
veeam: update integration test
weizhouapache Nov 3, 2023
5601116
veeam: fix exception if backup name has space
weizhouapache Nov 3, 2023
108d296
veeam: remove offering as last step in cleanup
weizhouapache Nov 4, 2023
6007808
veeam: add zone setting backup.plugin.veeam.version
weizhouapache Nov 4, 2023
a2265cb
veeam: fix update integration test
weizhouapache Nov 4, 2023
574672b
veeam: fix backup metrics in veeam12
weizhouapache Nov 6, 2023
b7f3252
veeam: remove RestorePoint/RestorePoints class
weizhouapache Nov 7, 2023
a457a11
veeam: add integration/marvin for backup schedule
weizhouapache Nov 7, 2023
bd8d331
veeam: add integration/marvin for restoreVolumeFromBackupAndAttachToVM
weizhouapache Nov 14, 2023
82337b1
veeam: fix EOF test/integration/smoke/test_backup_recovery_veeam.py
weizhouapache Nov 14, 2023
706ab9e
veeam: consider that powershell commands return null
weizhouapache Nov 15, 2023
2a1b23d
veeam: update default veeam.version to null and use VeeamAPI by default
weizhouapache Nov 15, 2023
c91cd61
veeam: update integration test as Daan comments
weizhouapache Nov 15, 2023
1d6d9d5
veeam: reformat commands in getBackupMetricsLegacy method
weizhouapache Nov 16, 2023
33fccda
Veeam: get server version via PS commands
weizhouapache Nov 16, 2023
7473e64
veeam: honor global/zone setting backup.plugin.veeam.version
weizhouapache Nov 16, 2023
ea59349
Veeam: add unit tests for getVeeamServerVersion
weizhouapache Nov 16, 2023
722b35e
plugins/pom.xml: remove backup/veeam as it depends on cloud-plugin-hy…
weizhouapache Nov 16, 2023
617a4c2
Veeam: update unit tests
weizhouapache Dec 8, 2023
ea84af9
[Veeam] restored VMs without NICs (#6282)
SadiJr Jul 3, 2023
2818366
veeam: fix inconsistent display in popup and vm details
weizhouapache Jan 5, 2024
6f021b7
Veeam: add interval type for backup schedules
weizhouapache Jan 9, 2024
bb0ec5e
veeam: support datetime without milliseconds
weizhouapache Jan 9, 2024
abec342
veeam: add event when backup is started/completed
weizhouapache Jan 10, 2024
5935410
veeam: add events when restoring backup is started/completed or fail
weizhouapache Jan 10, 2024
d392a6b
veeam: throw exception if restore session fails
weizhouapache Jan 10, 2024
597897d
veeam: set default value of backup.plugin.veeam.version to 0
weizhouapache Jan 11, 2024
00e8d2f
backup: add removed to BackupVO
weizhouapache Jan 15, 2024
3392552
veeam: add zone settings for polling veeam task
weizhouapache Jan 15, 2024
9d7d5fd
veeam: fix check task interval
weizhouapache Jan 15, 2024
6013e54
veeam: Prepare for restoring VM on VMware
weizhouapache Jan 18, 2024
f1386b8
veeam: remove CBT info from vmdk for all disks as the first disk migh…
weizhouapache Jan 18, 2024
1670f86
veeam: remove CBT info only if restore backup fails
weizhouapache Jan 18, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ public class ListVMsCmd extends BaseListTaggedResourcesCmd implements UserCmd {
@Parameter(name = ApiConstants.DETAILS,
type = CommandType.LIST,
collectionType = CommandType.STRING,
description = "comma separated list of host details requested, "
+ "value can be a list of [all, group, nics, stats, secgrp, tmpl, servoff, diskoff, iso, volume, min, affgrp]."
description = "comma separated list of vm details requested, "
+ "value can be a list of [all, group, nics, stats, secgrp, tmpl, servoff, diskoff, backoff, iso, volume, min, affgrp]."
+ " If no parameter is passed in, the details will be defaulted to all")
private List<String> viewDetails;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
//

package org.apache.cloudstack.backup;

import com.cloud.agent.api.Command;

public class PrepareForBackupRestorationCommand extends Command {

private String vmName;

protected PrepareForBackupRestorationCommand() {
}

public PrepareForBackupRestorationCommand(String vmName) {
this.vmName = vmName;
}

public String getVmName() {
return vmName;
}

@Override
public boolean executeInSequence() {
return true;
}
}
12 changes: 12 additions & 0 deletions engine/schema/src/main/java/com/cloud/vm/NicVO.java
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@
import javax.persistence.Table;
import javax.persistence.Transient;

import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;

import com.cloud.network.Networks.AddressFormat;
import com.cloud.network.Networks.Mode;
import com.cloud.utils.db.GenericDao;
Expand Down Expand Up @@ -399,6 +402,15 @@ public void setNsxLogicalSwitchPortUuid(String nsxLogicalSwitchPortUuid) {
}

@Override
public int hashCode() {
return new HashCodeBuilder(17, 31).append(id).toHashCode();
}

@Override
public boolean equals(Object obj) {
return EqualsBuilder.reflectionEquals(this, obj);
}

public Integer getMtu() {
return mtu;
}
Expand Down
2 changes: 2 additions & 0 deletions engine/schema/src/main/java/com/cloud/vm/dao/NicDao.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ public interface NicDao extends GenericDao<NicVO, Long> {

NicVO findByMacAddress(String macAddress);

NicVO findByNetworkIdAndMacAddressIncludingRemoved(long networkId, String mac);

List<NicVO> findNicsByIpv6GatewayIpv6CidrAndReserver(String ipv6Gateway, String ipv6Cidr, String reserverName);

NicVO findByIpAddressAndVmType(String ip, VirtualMachine.Type vmType);
Expand Down
8 changes: 8 additions & 0 deletions engine/schema/src/main/java/com/cloud/vm/dao/NicDaoImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -217,6 +217,14 @@ public NicVO findByNetworkIdAndMacAddress(long networkId, String mac) {
return findOneBy(sc);
}

@Override
public NicVO findByNetworkIdAndMacAddressIncludingRemoved(long networkId, String mac) {
SearchCriteria<NicVO> sc = AllFieldsSearch.create();
sc.setParameters("network", networkId);
sc.setParameters("macAddress", mac);
return findOneIncludingRemovedBy(sc);
}

@Override
public NicVO findDefaultNicForVM(long instanceId) {
SearchCriteria<NicVO> sc = AllFieldsSearch.create();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@

package org.apache.cloudstack.backup;

import com.cloud.utils.db.GenericDao;

import java.util.Date;
import java.util.UUID;

import javax.persistence.Column;
Expand Down Expand Up @@ -51,6 +54,9 @@ public class BackupVO implements Backup {
@Column(name = "date")
private String date;

@Column(name = GenericDao.REMOVED_COLUMN)
private Date removed;

@Column(name = "size")
private Long size;

Expand Down Expand Up @@ -192,4 +198,12 @@ public Class<?> getEntityType() {
public String getName() {
return null;
}

public Date getRemoved() {
return removed;
}

public void setRemoved(Date removed) {
this.removed = removed;
}
}
15 changes: 15 additions & 0 deletions plugins/backup/veeam/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,21 @@
</parent>

<dependencies>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-engine-components-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-hypervisor-vmware</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

import javax.inject.Inject;

import org.apache.cloudstack.api.ApiCommandResourceType;
import org.apache.cloudstack.api.InternalIdentity;
import org.apache.cloudstack.backup.Backup.Metric;
import org.apache.cloudstack.backup.dao.BackupDao;
Expand All @@ -40,11 +41,17 @@
import org.apache.commons.lang3.BooleanUtils;
import org.apache.log4j.Logger;

import com.cloud.agent.AgentManager;
import com.cloud.agent.api.Answer;
import com.cloud.event.ActionEventUtils;
import com.cloud.event.EventTypes;
import com.cloud.event.EventVO;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.vmware.VmwareDatacenter;
import com.cloud.hypervisor.vmware.VmwareDatacenterZoneMap;
import com.cloud.hypervisor.vmware.dao.VmwareDatacenterDao;
import com.cloud.hypervisor.vmware.dao.VmwareDatacenterZoneMapDao;
import com.cloud.user.User;
import com.cloud.utils.Pair;
import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.db.Transaction;
Expand All @@ -53,6 +60,7 @@
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachineManager;
import com.cloud.vm.dao.VMInstanceDao;

public class VeeamBackupProvider extends AdapterBase implements BackupProvider, Configurable {
Expand All @@ -64,6 +72,10 @@ public class VeeamBackupProvider extends AdapterBase implements BackupProvider,
"backup.plugin.veeam.url", "https://localhost:9398/api/",
"The Veeam backup and recovery URL.", true, ConfigKey.Scope.Zone);

public ConfigKey<Integer> VeeamVersion = new ConfigKey<>("Advanced", Integer.class,
"backup.plugin.veeam.version", "0",
"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);

private ConfigKey<String> VeeamUsername = new ConfigKey<>("Advanced", String.class,
"backup.plugin.veeam.username", "administrator",
"The Veeam backup and recovery username.", true, ConfigKey.Scope.Zone);
Expand All @@ -81,6 +93,12 @@ public class VeeamBackupProvider extends AdapterBase implements BackupProvider,
private static ConfigKey<Integer> VeeamRestoreTimeout = new ConfigKey<>("Advanced", Integer.class, "backup.plugin.veeam.restore.timeout", "600",
"The Veeam B&R API restore backup timeout in seconds.", true, ConfigKey.Scope.Zone);

private static ConfigKey<Integer> VeeamTaskPollInterval = new ConfigKey<>("Advanced", Integer.class, "backup.plugin.veeam.task.poll.interval", "5",
"The time interval in seconds when the management server polls for Veeam task status.", true, ConfigKey.Scope.Zone);

private static ConfigKey<Integer> VeeamTaskPollMaxRetry = new ConfigKey<>("Advanced", Integer.class, "backup.plugin.veeam.task.poll.max.retry", "120",
"The max number of retrying times when the management server polls for Veeam task status.", true, ConfigKey.Scope.Zone);

@Inject
private VmwareDatacenterZoneMapDao vmwareDatacenterZoneMapDao;
@Inject
Expand All @@ -89,11 +107,16 @@ public class VeeamBackupProvider extends AdapterBase implements BackupProvider,
private BackupDao backupDao;
@Inject
private VMInstanceDao vmInstanceDao;
@Inject
private AgentManager agentMgr;
@Inject
private VirtualMachineManager virtualMachineManager;

protected VeeamClient getClient(final Long zoneId) {
try {
return new VeeamClient(VeeamUrl.valueIn(zoneId), VeeamUsername.valueIn(zoneId), VeeamPassword.valueIn(zoneId),
VeeamValidateSSLSecurity.valueIn(zoneId), VeeamApiRequestTimeout.valueIn(zoneId), VeeamRestoreTimeout.valueIn(zoneId));
return new VeeamClient(VeeamUrl.valueIn(zoneId), VeeamVersion.valueIn(zoneId), VeeamUsername.valueIn(zoneId), VeeamPassword.valueIn(zoneId),
VeeamValidateSSLSecurity.valueIn(zoneId), VeeamApiRequestTimeout.valueIn(zoneId), VeeamRestoreTimeout.valueIn(zoneId),
VeeamTaskPollInterval.valueIn(zoneId), VeeamTaskPollMaxRetry.valueIn(zoneId));
} catch (URISyntaxException e) {
throw new CloudRuntimeException("Failed to parse Veeam API URL: " + e.getMessage());
} catch (NoSuchAlgorithmException | KeyManagementException e) {
Expand Down Expand Up @@ -234,7 +257,36 @@ public boolean deleteBackup(Backup backup, boolean forced) {
@Override
public boolean restoreVMFromBackup(VirtualMachine vm, Backup backup) {
final String restorePointId = backup.getExternalId();
return getClient(vm.getDataCenterId()).restoreFullVM(vm.getInstanceName(), restorePointId);
try {
return getClient(vm.getDataCenterId()).restoreFullVM(vm.getInstanceName(), restorePointId);
} catch (Exception ex) {
LOG.error(String.format("Failed to restore Full VM due to: %s. Retrying after some preparation", ex.getMessage()));
prepareForBackupRestoration(vm);
return getClient(vm.getDataCenterId()).restoreFullVM(vm.getInstanceName(), restorePointId);
}
}

private void prepareForBackupRestoration(VirtualMachine vm) {
if (!Hypervisor.HypervisorType.VMware.equals(vm.getHypervisorType())) {
return;
}
LOG.info("Preparing for restoring VM " + vm);
PrepareForBackupRestorationCommand command = new PrepareForBackupRestorationCommand(vm.getInstanceName());
Long hostId = virtualMachineManager.findClusterAndHostIdForVm(vm.getId()).second();
if (hostId == null) {
throw new CloudRuntimeException("Cannot find a host to prepare for restoring VM " + vm);
}
try {
Answer answer = agentMgr.easySend(hostId, command);
if (answer != null && answer.getResult()) {
LOG.info("Succeeded to prepare for restoring VM " + vm);
} else {
throw new CloudRuntimeException(String.format("Failed to prepare for restoring VM %s. details: %s", vm,
(answer != null ? answer.getDetails() : null)));
}
} catch (Exception e) {
throw new CloudRuntimeException(String.format("Failed to prepare for restoring VM %s due to exception %s", vm, e));
}
}

@Override
Expand Down Expand Up @@ -330,6 +382,10 @@ public void doInTransactionWithoutResult(TransactionStatus status) {
+ "domain_id: %s, zone_id: %s].", backup.getUuid(), backup.getVmId(), backup.getExternalId(), backup.getType(), backup.getDate(),
backup.getBackupOfferingId(), backup.getAccountId(), backup.getDomainId(), backup.getZoneId()));
backupDao.persist(backup);

ActionEventUtils.onCompletedActionEvent(User.UID_SYSTEM, vm.getAccountId(), EventVO.LEVEL_INFO, EventTypes.EVENT_VM_BACKUP_CREATE,
String.format("Created backup %s for VM ID: %s", backup.getUuid(), vm.getUuid()),
vm.getId(), ApiCommandResourceType.VirtualMachine.toString(),0);
}
}
for (final Long backupIdToRemove : removeList) {
Expand All @@ -349,11 +405,14 @@ public String getConfigComponentName() {
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey[]{
VeeamUrl,
VeeamVersion,
VeeamUsername,
VeeamPassword,
VeeamValidateSSLSecurity,
VeeamApiRequestTimeout,
VeeamRestoreTimeout
VeeamRestoreTimeout,
VeeamTaskPollInterval,
VeeamTaskPollMaxRetry
};
}

Expand Down
Loading