CloudStack Backup & Recovery Framework (#3553)

This commit is contained in:
Rohit Yadav 2020-03-03 17:57:58 +05:30 committed by GitHub
parent 4e3f7c2d65
commit 318924d801
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
136 changed files with 11074 additions and 112 deletions

View File

@ -46,6 +46,7 @@ env:
smoke/test_affinity_groups
smoke/test_affinity_groups_projects
smoke/test_async_job
smoke/test_backup_recovery_dummy
smoke/test_create_list_domain_account_project
smoke/test_create_network
smoke/test_deploy_vgpu_enabled_vm

View File

@ -478,6 +478,17 @@ public class EventTypes {
public static final String EVENT_VM_SNAPSHOT_OFF_PRIMARY = "VMSNAPSHOT.OFF_PRIMARY";
public static final String EVENT_VM_SNAPSHOT_REVERT = "VMSNAPSHOT.REVERTTO";
// Backup and Recovery events
public static final String EVENT_VM_BACKUP_IMPORT_OFFERING = "BACKUP.IMPORT.OFFERING";
public static final String EVENT_VM_BACKUP_OFFERING_ASSIGN = "BACKUP.OFFERING.ASSIGN";
public static final String EVENT_VM_BACKUP_OFFERING_REMOVE = "BACKUP.OFFERING.REMOVE";
public static final String EVENT_VM_BACKUP_CREATE = "BACKUP.CREATE";
public static final String EVENT_VM_BACKUP_RESTORE = "BACKUP.RESTORE";
public static final String EVENT_VM_BACKUP_DELETE = "BACKUP.DELETE";
public static final String EVENT_VM_BACKUP_RESTORE_VOLUME_TO_VM = "BACKUP.RESTORE.VOLUME.TO.VM";
public static final String EVENT_VM_BACKUP_SCHEDULE_CONFIGURE = "BACKUP.SCHEDULE.CONFIGURE";
public static final String EVENT_VM_BACKUP_SCHEDULE_DELETE = "BACKUP.SCHEDULE.DELETE";
// external network device events
public static final String EVENT_EXTERNAL_NVP_CONTROLLER_ADD = "PHYSICAL.NVPCONTROLLER.ADD";
public static final String EVENT_EXTERNAL_NVP_CONTROLLER_DELETE = "PHYSICAL.NVPCONTROLLER.DELETE";

View File

@ -19,13 +19,14 @@ package com.cloud.hypervisor;
import java.util.List;
import java.util.Map;
import com.cloud.storage.StoragePool;
import org.apache.cloudstack.backup.Backup;
import org.apache.cloudstack.framework.config.ConfigKey;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.to.NicTO;
import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.storage.StoragePool;
import com.cloud.utils.Pair;
import com.cloud.utils.component.Adapter;
import com.cloud.vm.NicProfile;
@ -86,6 +87,11 @@ public interface HypervisorGuru extends Adapter {
Map<String, String> getClusterSettings(long vmId);
VirtualMachine importVirtualMachineFromBackup(long zoneId, long domainId, long accountId, long userId,
String vmInternalName, Backup backup) throws Exception;
boolean attachRestoredVolumeToVirtualMachine(long zoneId, String location, Backup.VolumeInfo volumeInfo,
VirtualMachine vm, long poolId, Backup backup) throws Exception;
/**
* Will generate commands to migrate a vm to a pool. For now this will only work for stopped VMs on Vmware.
*

View File

@ -29,6 +29,7 @@ public interface ResourceTag extends ControlledEntity, Identity, InternalIdentit
ISO(true, false),
Volume(true, true),
Snapshot(true, false),
Backup(true, false),
Network(true, true),
Nic(false, true),
LoadBalancer(true, true),

View File

@ -16,18 +16,21 @@
// under the License.
package com.cloud.vm;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.api.Displayable;
import org.apache.cloudstack.backup.Backup;
import org.apache.cloudstack.kernel.Partition;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.utils.fsm.StateMachine2;
import com.cloud.utils.fsm.StateMachine2.Transition;
import com.cloud.utils.fsm.StateMachine2.Transition.Impact;
import com.cloud.utils.fsm.StateObject;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.api.Displayable;
import org.apache.cloudstack.kernel.Partition;
import java.util.Arrays;
import java.util.Date;
import java.util.Map;
/**
* VirtualMachine describes the properties held by a virtual machine
@ -319,6 +322,12 @@ public interface VirtualMachine extends RunningOn, ControlledEntity, Partition,
Long getDiskOfferingId();
Long getBackupOfferingId();
String getBackupExternalId();
List<Backup.VolumeInfo> getBackupVolumeList();
Type getType();
HypervisorType getHypervisorType();

View File

@ -23,6 +23,7 @@ public enum ApiCommandJobType {
Volume,
ConsoleProxy,
Snapshot,
Backup,
Template,
Iso,
SystemVm,

View File

@ -33,6 +33,9 @@ public class ApiConstants {
public static final String APPLIED = "applied";
public static final String LIST_LB_VMIPS = "lbvmips";
public static final String AVAILABLE = "available";
public static final String BACKUP_ID = "backupid";
public static final String BACKUP_OFFERING_NAME = "backupofferingname";
public static final String BACKUP_OFFERING_ID = "backupofferingid";
public static final String BITS = "bits";
public static final String BOOTABLE = "bootable";
public static final String BIND_DN = "binddn";
@ -144,6 +147,7 @@ public class ApiConstants {
public static final String EXTRA_DHCP_OPTION_NAME = "extradhcpoptionname";
public static final String EXTRA_DHCP_OPTION_CODE = "extradhcpoptioncode";
public static final String EXTRA_DHCP_OPTION_VALUE = "extradhcpvalue";
public static final String EXTERNAL = "external";
public static final String FENCE = "fence";
public static final String FETCH_LATEST = "fetchlatest";
public static final String FIRSTNAME = "firstname";
@ -366,6 +370,7 @@ public class ApiConstants {
public static final String VALUE = "value";
public static final String VIRTUAL_MACHINE_ID = "virtualmachineid";
public static final String VIRTUAL_MACHINE_IDS = "virtualmachineids";
public static final String VIRTUAL_MACHINE_NAME = "virtualmachinename";
public static final String VIRTUAL_MACHINE_ID_IP = "vmidipmap";
public static final String VIRTUAL_MACHINE_COUNT = "virtualmachinecount";
public static final String USAGE_ID = "usageid";
@ -385,6 +390,7 @@ public class ApiConstants {
public static final String VNET = "vnet";
public static final String IS_VOLATILE = "isvolatile";
public static final String VOLUME_ID = "volumeid";
public static final String VOLUMES = "volumes";
public static final String ZONE = "zone";
public static final String ZONE_ID = "zoneid";
public static final String ZONE_NAME = "zonename";
@ -531,6 +537,7 @@ public class ApiConstants {
public static final String REQUIRED = "required";
public static final String RESTART_REQUIRED = "restartrequired";
public static final String ALLOW_USER_CREATE_PROJECTS = "allowusercreateprojects";
public static final String ALLOW_USER_DRIVEN_BACKUPS = "allowuserdrivenbackups";
public static final String CONSERVE_MODE = "conservemode";
public static final String TRAFFIC_TYPE_IMPLEMENTOR = "traffictypeimplementor";
public static final String KEYWORD = "keyword";
@ -780,7 +787,7 @@ public class ApiConstants {
}
public enum VMDetails {
all, group, nics, stats, secgrp, tmpl, servoff, diskoff, iso, volume, min, affgrp;
all, group, nics, stats, secgrp, tmpl, servoff, diskoff, backoff, iso, volume, min, affgrp;
}
public enum DomainDetails {

View File

@ -0,0 +1,49 @@
// 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.api;
import java.util.ArrayList;
import java.util.List;
import org.apache.cloudstack.api.response.BackupOfferingResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.backup.BackupOffering;
import org.apache.cloudstack.context.CallContext;
public abstract class BaseBackupListCmd extends BaseListCmd {
protected void setupResponseBackupOfferingsList(final List<BackupOffering> offerings, final Integer count) {
final ListResponse<BackupOfferingResponse> response = new ListResponse<>();
final List<BackupOfferingResponse> responses = new ArrayList<>();
for (final BackupOffering offering : offerings) {
if (offering == null) {
continue;
}
BackupOfferingResponse backupOfferingResponse = _responseGenerator.createBackupOfferingResponse(offering);
responses.add(backupOfferingResponse);
}
response.setResponses(responses, count);
response.setResponseName(getCommandName());
setResponseObject(response);
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
}

View File

@ -22,8 +22,6 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.cloudstack.api.response.RouterHealthCheckResultResponse;
import org.apache.cloudstack.management.ManagementServerHost;
import org.apache.cloudstack.affinity.AffinityGroup;
import org.apache.cloudstack.affinity.AffinityGroupResponse;
import org.apache.cloudstack.api.ApiConstants.HostDetails;
@ -36,6 +34,8 @@ import org.apache.cloudstack.api.response.AsyncJobResponse;
import org.apache.cloudstack.api.response.AutoScalePolicyResponse;
import org.apache.cloudstack.api.response.AutoScaleVmGroupResponse;
import org.apache.cloudstack.api.response.AutoScaleVmProfileResponse;
import org.apache.cloudstack.api.response.BackupOfferingResponse;
import org.apache.cloudstack.api.response.BackupScheduleResponse;
import org.apache.cloudstack.api.response.CapacityResponse;
import org.apache.cloudstack.api.response.ClusterResponse;
import org.apache.cloudstack.api.response.ConditionResponse;
@ -88,6 +88,7 @@ import org.apache.cloudstack.api.response.RemoteAccessVpnResponse;
import org.apache.cloudstack.api.response.ResourceCountResponse;
import org.apache.cloudstack.api.response.ResourceLimitResponse;
import org.apache.cloudstack.api.response.ResourceTagResponse;
import org.apache.cloudstack.api.response.RouterHealthCheckResultResponse;
import org.apache.cloudstack.api.response.SSHKeyPairResponse;
import org.apache.cloudstack.api.response.SecurityGroupResponse;
import org.apache.cloudstack.api.response.ServiceOfferingResponse;
@ -111,6 +112,7 @@ import org.apache.cloudstack.api.response.UpgradeRouterTemplateResponse;
import org.apache.cloudstack.api.response.UsageRecordResponse;
import org.apache.cloudstack.api.response.UserResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.api.response.VMSnapshotResponse;
import org.apache.cloudstack.api.response.VirtualRouterProviderResponse;
import org.apache.cloudstack.api.response.VlanIpRangeResponse;
@ -119,7 +121,11 @@ import org.apache.cloudstack.api.response.VpcOfferingResponse;
import org.apache.cloudstack.api.response.VpcResponse;
import org.apache.cloudstack.api.response.VpnUsersResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.backup.BackupOffering;
import org.apache.cloudstack.backup.Backup;
import org.apache.cloudstack.backup.BackupSchedule;
import org.apache.cloudstack.config.Configuration;
import org.apache.cloudstack.management.ManagementServerHost;
import org.apache.cloudstack.network.lb.ApplicationLoadBalancerRule;
import org.apache.cloudstack.region.PortableIp;
import org.apache.cloudstack.region.PortableIpRange;
@ -467,6 +473,12 @@ public interface ResponseGenerator {
SSHKeyPairResponse createSSHKeyPairResponse(SSHKeyPair sshkeyPair, boolean privatekey);
BackupResponse createBackupResponse(Backup backup);
BackupScheduleResponse createBackupScheduleResponse(BackupSchedule backup);
BackupOfferingResponse createBackupOfferingResponse(BackupOffering policy);
ManagementServerResponse createManagementResponse(ManagementServerHost mgmt);
List<RouterHealthCheckResultResponse> createHealthCheckResponse(VirtualMachine router, List<RouterHealthCheckResult> healthCheckResults);

View File

@ -0,0 +1,92 @@
// 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.api.command.admin.backup;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.BackupOfferingResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.context.CallContext;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
@APICommand(name = DeleteBackupOfferingCmd.APINAME,
description = "Deletes a backup offering",
responseObject = SuccessResponse.class, since = "4.14.0",
authorized = {RoleType.Admin})
public class DeleteBackupOfferingCmd extends BaseCmd {
public static final String APINAME = "deleteBackupOffering";
@Inject
private BackupManager backupManager;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
////////////////////////////////////////////////////
@Parameter(name = ApiConstants.ID,
type = CommandType.UUID,
entityType = BackupOfferingResponse.class,
required = true,
description = "ID of the backup offering")
private Long id;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getId() {
return id;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
if (backupManager.deleteBackupOffering(getId())) {
SuccessResponse response = new SuccessResponse(getCommandName());
setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Unable to remove backup offering: " + getId());
}
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
}

View File

@ -0,0 +1,145 @@
// 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.api.command.admin.backup;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.BackupOfferingResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.backup.BackupOffering;
import org.apache.cloudstack.context.CallContext;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.utils.exception.CloudRuntimeException;
@APICommand(name = ImportBackupOfferingCmd.APINAME,
description = "Imports a backup offering using a backup provider",
responseObject = BackupOfferingResponse.class, since = "4.14.0",
authorized = {RoleType.Admin})
public class ImportBackupOfferingCmd extends BaseAsyncCmd {
public static final String APINAME = "importBackupOffering";
@Inject
private BackupManager backupManager;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
////////////////////////////////////////////////////
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true,
description = "the name of the backup offering")
private String name;
@Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, required = true,
description = "the description of the backup offering")
private String description;
@Parameter(name = ApiConstants.EXTERNAL_ID,
type = CommandType.STRING,
required = true,
description = "The backup offering ID (from backup provider side)")
private String externalId;
@Parameter(name = ApiConstants.ZONE_ID, type = BaseCmd.CommandType.UUID, entityType = ZoneResponse.class,
description = "The zone ID", required = true)
private Long zoneId;
@Parameter(name = ApiConstants.ALLOW_USER_DRIVEN_BACKUPS, type = CommandType.BOOLEAN,
description = "Whether users are allowed to create adhoc backups and backup schedules", required = true)
private Boolean userDrivenBackups;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public String getName() {
return name;
}
public String getExternalId() {
return externalId;
}
public Long getZoneId() {
return zoneId;
}
public String getDescription() {
return description;
}
public Boolean getUserDrivenBackups() {
return userDrivenBackups == null ? false : userDrivenBackups;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
try {
BackupOffering policy = backupManager.importBackupOffering(this);
if (policy != null) {
BackupOfferingResponse response = _responseGenerator.createBackupOfferingResponse(policy);
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add a backup offering");
}
} catch (InvalidParameterValueException e) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, e.getMessage());
} catch (CloudRuntimeException e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
@Override
public String getEventType() {
return EventTypes.EVENT_VM_BACKUP_IMPORT_OFFERING;
}
@Override
public String getEventDescription() {
return "Importing backup offering: " + name + " (external ID: " + externalId + ") on zone ID " + zoneId ;
}
}

View File

@ -0,0 +1,94 @@
// 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.api.command.admin.backup;
import java.util.List;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseBackupListCmd;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.BackupOfferingResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.backup.BackupOffering;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.utils.exception.CloudRuntimeException;
@APICommand(name = ListBackupProviderOfferingsCmd.APINAME,
description = "Lists external backup offerings of the provider",
responseObject = BackupOfferingResponse.class, since = "4.14.0",
authorized = {RoleType.Admin})
public class ListBackupProviderOfferingsCmd extends BaseBackupListCmd {
public static final String APINAME = "listBackupProviderOfferings";
@Inject
private BackupManager backupManager;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.ZONE_ID, type = BaseCmd.CommandType.UUID, entityType = ZoneResponse.class,
required = true, description = "The zone ID")
private Long zoneId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getZoneId() {
return zoneId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
private void validateParameters() {
if (getZoneId() == null) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, "Please provide a valid zone ID ");
}
}
@Override
public void execute() throws ResourceUnavailableException, ServerApiException, ConcurrentOperationException {
validateParameters();
try {
final List<BackupOffering> backupOfferings = backupManager.listBackupProviderOfferings(getZoneId());
setupResponseBackupOfferingsList(backupOfferings, backupOfferings.size());
} catch (InvalidParameterValueException e) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, e.getMessage());
} catch (CloudRuntimeException e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + RESPONSE_SUFFIX;
}
}

View File

@ -0,0 +1,98 @@
// 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.api.command.admin.backup;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.BackupProviderResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.backup.BackupProvider;
import com.cloud.user.Account;
@APICommand(name = ListBackupProvidersCmd.APINAME,
description = "Lists Backup and Recovery providers",
responseObject = BackupProviderResponse.class, since = "4.14.0",
authorized = {RoleType.Admin})
public class ListBackupProvidersCmd extends BaseCmd {
public static final String APINAME = "listBackupProviders";
@Inject
private BackupManager backupManager;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "List Backup and Recovery provider by name")
private String name;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public String getName() {
return name;
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
private void setupResponse(final List<BackupProvider> providers) {
final ListResponse<BackupProviderResponse> response = new ListResponse<>();
final List<BackupProviderResponse> responses = new ArrayList<>();
for (final BackupProvider provider : providers) {
if (provider == null || (getName() != null && !provider.getName().equals(getName()))) {
continue;
}
final BackupProviderResponse backupProviderResponse = new BackupProviderResponse();
backupProviderResponse.setName(provider.getName());
backupProviderResponse.setDescription(provider.getDescription());
backupProviderResponse.setObjectName("providers");
responses.add(backupProviderResponse);
}
response.setResponses(responses);
response.setResponseName(getCommandName());
setResponseObject(response);
}
@Override
public void execute() {
List<BackupProvider> providers = backupManager.listBackupProviders();
setupResponse(providers);
}
}

View File

@ -0,0 +1,122 @@
// 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.api.command.user.backup;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.BackupOfferingResponse;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.context.CallContext;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
@APICommand(name = AssignVirtualMachineToBackupOfferingCmd.APINAME,
description = "Assigns a VM to a backup offering",
responseObject = BackupResponse.class, since = "4.14.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class AssignVirtualMachineToBackupOfferingCmd extends BaseAsyncCmd {
public static final String APINAME = "assignVirtualMachineToBackupOffering";
@Inject
private BackupManager backupManager;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
type = CommandType.UUID,
entityType = UserVmResponse.class,
required = true,
description = "ID of the virtual machine")
private Long vmId;
@Parameter(name = ApiConstants.BACKUP_OFFERING_ID,
type = CommandType.UUID,
entityType = BackupOfferingResponse.class,
required = true,
description = "ID of the backup offering")
private Long offeringId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getVmId() {
return vmId;
}
public Long getOfferingId() {
return offeringId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
try {
boolean result = backupManager.assignVMToBackupOffering(getVmId(), getOfferingId());
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add VM to backup offering");
}
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
@Override
public String getEventType() {
return EventTypes.EVENT_VM_BACKUP_OFFERING_ASSIGN;
}
@Override
public String getEventDescription() {
return "Assigning VM to backup offering ID: " + offeringId;
}
}

View File

@ -0,0 +1,126 @@
// 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.api.command.user.backup;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandJobType;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCreateCmd;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.context.CallContext;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.utils.exception.CloudRuntimeException;
@APICommand(name = CreateBackupCmd.APINAME,
description = "Create VM backup",
responseObject = SuccessResponse.class, since = "4.14.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class CreateBackupCmd extends BaseAsyncCreateCmd {
public static final String APINAME = "createBackup";
@Inject
private BackupManager backupManager;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
type = CommandType.UUID,
entityType = UserVmResponse.class,
required = true,
description = "ID of the VM")
private Long vmId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getVmId() {
return vmId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
try {
boolean result = backupManager.createBackup(getVmId());
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
throw new CloudRuntimeException("Error while creating backup of VM");
}
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
}
@Override
public ApiCommandJobType getInstanceType() {
return ApiCommandJobType.Backup;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
@Override
public String getEventType() {
return EventTypes.EVENT_VM_BACKUP_CREATE;
}
@Override
public String getEventDescription() {
return "Creating backup for VM " + vmId;
}
@Override
public void create() throws ResourceAllocationException {
}
@Override
public Long getEntityId() {
return vmId;
}
}

View File

@ -0,0 +1,128 @@
// 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.api.command.user.backup;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.api.response.BackupScheduleResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.backup.BackupSchedule;
import org.apache.cloudstack.context.CallContext;
import com.cloud.utils.DateUtil;
import com.cloud.utils.exception.CloudRuntimeException;
@APICommand(name = CreateBackupScheduleCmd.APINAME,
description = "Creates a user-defined VM backup schedule",
responseObject = BackupResponse.class, since = "4.14.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class CreateBackupScheduleCmd extends BaseCmd {
public static final String APINAME = "createBackupSchedule";
@Inject
private BackupManager backupManager;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
type = CommandType.UUID,
entityType = UserVmResponse.class,
required = true,
description = "ID of the VM for which schedule is to be defined")
private Long vmId;
@Parameter(name = ApiConstants.INTERVAL_TYPE,
type = CommandType.STRING,
required = true,
description = "valid values are HOURLY, DAILY, WEEKLY, and MONTHLY")
private String intervalType;
@Parameter(name = ApiConstants.SCHEDULE,
type = CommandType.STRING,
required = true,
description = "custom backup schedule, the format is:"
+ "for HOURLY MM*, for DAILY MM:HH*, for WEEKLY MM:HH:DD (1-7)*, for MONTHLY MM:HH:DD (1-28)")
private String schedule;
@Parameter(name = ApiConstants.TIMEZONE,
type = CommandType.STRING,
required = true,
description = "Specifies a timezone for this command. For more information on the timezone parameter, see TimeZone Format.")
private String timezone;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getVmId() {
return vmId;
}
public DateUtil.IntervalType getIntervalType() {
return DateUtil.IntervalType.getIntervalType(intervalType);
}
public String getSchedule() {
return schedule;
}
public String getTimezone() {
return timezone;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() throws ServerApiException {
try {
BackupSchedule schedule = backupManager.configureBackupSchedule(this);
if (schedule != null) {
BackupScheduleResponse response = _responseGenerator.createBackupScheduleResponse(schedule);
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
throw new CloudRuntimeException("Error while creating backup schedule of VM");
}
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
}

View File

@ -0,0 +1,111 @@
// 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.api.command.user.backup;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.context.CallContext;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.utils.exception.CloudRuntimeException;
@APICommand(name = DeleteBackupCmd.APINAME,
description = "Delete VM backup",
responseObject = SuccessResponse.class, since = "4.14.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class DeleteBackupCmd extends BaseAsyncCmd {
public static final String APINAME = "deleteBackup";
@Inject
private BackupManager backupManager;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.ID,
type = CommandType.UUID,
entityType = BackupResponse.class,
required = true,
description = "id of the VM backup")
private Long backupId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getId() {
return backupId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
try {
boolean result = backupManager.deleteBackup(backupId);
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
throw new CloudRuntimeException("Error while deleting backup of VM");
}
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
@Override
public String getEventType() {
return EventTypes.EVENT_VM_BACKUP_DELETE;
}
@Override
public String getEventDescription() {
return "Deleting backup ID " + backupId;
}
}

View File

@ -0,0 +1,99 @@
// 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.api.command.user.backup;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.context.CallContext;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.utils.exception.CloudRuntimeException;
@APICommand(name = DeleteBackupScheduleCmd.APINAME,
description = "Deletes the backup schedule of a VM",
responseObject = SuccessResponse.class, since = "4.14.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class DeleteBackupScheduleCmd extends BaseCmd {
public static final String APINAME = "deleteBackupSchedule";
@Inject
private BackupManager backupManager;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
type = CommandType.UUID,
entityType = UserVmResponse.class,
required = true,
description = "ID of the VM")
private Long vmId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getVmId() {
return vmId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
try {
boolean result = backupManager.deleteBackupSchedule(getVmId());
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
throw new CloudRuntimeException("Failed to delete VM backup schedule");
}
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
}

View File

@ -0,0 +1,96 @@
// 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.api.command.user.backup;
import java.util.List;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseBackupListCmd;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.BackupOfferingResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.backup.BackupOffering;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.utils.Pair;
import com.cloud.utils.exception.CloudRuntimeException;
@APICommand(name = ListBackupOfferingsCmd.APINAME,
description = "Lists backup offerings",
responseObject = BackupOfferingResponse.class, since = "4.14.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class ListBackupOfferingsCmd extends BaseBackupListCmd {
public static final String APINAME = "listBackupOfferings";
@Inject
private BackupManager backupManager;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID, entityType = BackupOfferingResponse.class,
description = "The backup offering ID")
private Long offeringId;
@Parameter(name = ApiConstants.ZONE_ID, type = BaseCmd.CommandType.UUID, entityType = ZoneResponse.class,
description = "The zone ID")
private Long zoneId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getZoneId() {
return zoneId;
}
public Long getOfferingId() {
return offeringId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() throws ResourceUnavailableException, ServerApiException, ConcurrentOperationException {
try {
Pair<List<BackupOffering>, Integer> result = backupManager.listBackupOfferings(this);
setupResponseBackupOfferingsList(result.first(), result.second());
} catch (InvalidParameterValueException e) {
throw new ServerApiException(ApiErrorCode.PARAM_ERROR, e.getMessage());
} catch (CloudRuntimeException e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + RESPONSE_SUFFIX;
}
}

View File

@ -0,0 +1,100 @@
// 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.api.command.user.backup;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.BackupScheduleResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.backup.BackupSchedule;
import org.apache.cloudstack.context.CallContext;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.utils.exception.CloudRuntimeException;
@APICommand(name = ListBackupScheduleCmd.APINAME,
description = "List backup schedule of a VM",
responseObject = BackupScheduleResponse.class, since = "4.14.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class ListBackupScheduleCmd extends BaseCmd {
public static final String APINAME = "listBackupSchedule";
@Inject
private BackupManager backupManager;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
type = CommandType.UUID,
entityType = UserVmResponse.class,
required = true,
description = "ID of the VM")
private Long vmId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getVmId() {
return vmId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
try{
BackupSchedule schedule = backupManager.listBackupSchedule(getVmId());
if (schedule != null) {
BackupScheduleResponse response = _responseGenerator.createBackupScheduleResponse(schedule);
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
throw new CloudRuntimeException("No backup schedule exists for the VM");
}
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
}

View File

@ -0,0 +1,135 @@
// 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.api.command.user.backup;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.BaseListProjectAndAccountResourcesCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.backup.Backup;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.context.CallContext;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.utils.Pair;
@APICommand(name = ListBackupsCmd.APINAME,
description = "Lists VM backups",
responseObject = BackupResponse.class, since = "4.14.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class ListBackupsCmd extends BaseListProjectAndAccountResourcesCmd {
public static final String APINAME = "listBackups";
@Inject
private BackupManager backupManager;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.ID,
type = CommandType.UUID,
entityType = BackupResponse.class,
description = "id of the backup")
private Long id;
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
type = CommandType.UUID,
entityType = UserVmResponse.class,
description = "id of the VM")
private Long vmId;
@Parameter(name = ApiConstants.ZONE_ID,
type = CommandType.UUID,
entityType = ZoneResponse.class,
description = "list backups by zone id")
private Long zoneId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getId() {
return id;
}
public Long getVmId() {
return vmId;
}
public Long getZoneId() {
return zoneId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
protected void setupResponseBackupList(final List<Backup> backups, final Integer count) {
final List<BackupResponse> responses = new ArrayList<>();
for (Backup backup : backups) {
if (backup == null) {
continue;
}
BackupResponse backupResponse = _responseGenerator.createBackupResponse(backup);
responses.add(backupResponse);
}
final ListResponse<BackupResponse> response = new ListResponse<>();
response.setResponses(responses, count);
response.setResponseName(getCommandName());
setResponseObject(response);
}
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
try{
Pair<List<Backup>, Integer> result = backupManager.listBackups(this);
setupResponseBackupList(result.first(), result.second());
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
}

View File

@ -0,0 +1,118 @@
// 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.api.command.user.backup;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.context.CallContext;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
@APICommand(name = RemoveVirtualMachineFromBackupOfferingCmd.APINAME,
description = "Removes a VM from any existing backup offering",
responseObject = SuccessResponse.class, since = "4.14.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class RemoveVirtualMachineFromBackupOfferingCmd extends BaseAsyncCmd {
public static final String APINAME = "removeVirtualMachineFromBackupOffering";
@Inject
private BackupManager backupManager;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
type = CommandType.UUID,
entityType = UserVmResponse.class,
required = true,
description = "ID of the virtual machine")
private Long vmId;
@Parameter(name = ApiConstants.FORCED,
type = CommandType.BOOLEAN,
description = "Whether to force remove VM from the backup offering that may also delete VM backups.")
private Boolean forced;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getVmId() {
return vmId;
}
public boolean getForced() {
return forced == null ? false : forced;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
try {
boolean result = backupManager.removeVMFromBackupOffering(getVmId(), getForced());
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to remove VM from backup offering");
}
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
@Override
public String getEventType() {
return EventTypes.EVENT_VM_BACKUP_OFFERING_REMOVE;
}
@Override
public String getEventDescription() {
return "Removing VM ID" + vmId + " from backup offering";
}
}

View File

@ -0,0 +1,111 @@
// 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.api.command.user.backup;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.context.CallContext;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.utils.exception.CloudRuntimeException;
@APICommand(name = RestoreBackupCmd.APINAME,
description = "Restores an existing stopped or deleted VM using a VM backup",
responseObject = SuccessResponse.class, since = "4.14.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class RestoreBackupCmd extends BaseAsyncCmd {
public static final String APINAME = "restoreBackup";
@Inject
private BackupManager backupManager;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.ID,
type = CommandType.UUID,
entityType = BackupResponse.class,
required = true,
description = "ID of the backup")
private Long backupId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getBackupId() {
return backupId;
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
try {
boolean result = backupManager.restoreBackup(backupId);
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
throw new CloudRuntimeException("Error while restoring VM from backup");
}
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
@Override
public String getEventType() {
return EventTypes.EVENT_VM_BACKUP_RESTORE;
}
@Override
public String getEventDescription() {
return "Restoring VM from backup: " + backupId;
}
}

View File

@ -0,0 +1,133 @@
// 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.api.command.user.backup;
import javax.inject.Inject;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.context.CallContext;
import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.utils.exception.CloudRuntimeException;
@APICommand(name = RestoreVolumeFromBackupAndAttachToVMCmd.APINAME,
description = "Restore and attach a backed up volume to VM",
responseObject = SuccessResponse.class, since = "4.14.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class RestoreVolumeFromBackupAndAttachToVMCmd extends BaseAsyncCmd {
public static final String APINAME = "restoreVolumeFromBackupAndAttachToVM";
@Inject
private BackupManager backupManager;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.BACKUP_ID,
type = CommandType.UUID,
entityType = BackupResponse.class,
required = true,
description = "ID of the VM backup")
private Long backupId;
@Parameter(name = ApiConstants.VOLUME_ID,
type = CommandType.STRING,
required = true,
description = "ID of the volume backed up")
private String volumeUuid;
@Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID,
type = CommandType.UUID,
entityType = UserVmResponse.class,
required = true,
description = "id of the VM where to attach the restored volume")
private Long vmId;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public String getVolumeUuid() {
return volumeUuid;
}
public Long getVmId() {
return vmId;
}
public Long getBackupId() {
return backupId;
}
@Override
public String getCommandName() {
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
try {
boolean result = backupManager.restoreBackupVolumeAndAttachToVM(volumeUuid, backupId, vmId);
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
throw new CloudRuntimeException("Error restoring volume and attaching to VM");
}
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
}
@Override
public String getEventType() {
return EventTypes.EVENT_VM_BACKUP_RESTORE_VOLUME_TO_VM;
}
@Override
public String getEventDescription() {
return "Restoring volume "+ volumeUuid + " from backup " + backupId + " and attaching it to VM " + vmId;
}
}

View File

@ -0,0 +1,30 @@
// 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.api.command.user.backup;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.response.BackupResponse;
@APICommand(name = UpdateBackupScheduleCmd.APINAME,
description = "Updates a user-defined VM backup schedule",
responseObject = BackupResponse.class, since = "4.14.0",
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
public class UpdateBackupScheduleCmd extends CreateBackupScheduleCmd {
public static final String APINAME = "updateBackupSchedule";
}

View File

@ -0,0 +1,95 @@
// 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.api.response;
import java.util.Date;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.EntityReference;
import org.apache.cloudstack.backup.BackupOffering;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
@EntityReference(value = BackupOffering.class)
public class BackupOfferingResponse extends BaseResponse {
@SerializedName(ApiConstants.ID)
@Param(description = "ID of the backup offering")
private String id;
@SerializedName(ApiConstants.NAME)
@Param(description = "name for the backup offering")
private String name;
@SerializedName(ApiConstants.DESCRIPTION)
@Param(description = "description for the backup offering")
private String description;
@SerializedName(ApiConstants.EXTERNAL_ID)
@Param(description = "external ID on the provider side")
private String externalId;
@SerializedName(ApiConstants.ALLOW_USER_DRIVEN_BACKUPS)
@Param(description = "whether offering allows user driven ad-hoc/scheduled backups")
private Boolean userDrivenBackups;
@SerializedName(ApiConstants.ZONE_ID)
@Param(description = "zone ID")
private String zoneId;
@SerializedName(ApiConstants.ZONE_NAME)
@Param(description = "zone name")
private String zoneName;
@SerializedName(ApiConstants.CREATED)
@Param(description = "the date this backup offering was created")
private Date created;
public void setId(String id) {
this.id = id;
}
public void setExternalId(String externalId) {
this.externalId = externalId;
}
public void setName(String name) {
this.name = name;
}
public void setDescription(String description) {
this.description = description;
}
public void setUserDrivenBackups(Boolean userDrivenBackups) {
this.userDrivenBackups = userDrivenBackups;
}
public void setZoneId(String zoneId) {
this.zoneId = zoneId;
}
public void setZoneName(String zoneName) {
this.zoneName = zoneName;
}
public void setCreated(Date created) {
this.created = created;
}
}

View File

@ -0,0 +1,53 @@
// 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.api.response;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.EntityReference;
import org.apache.cloudstack.backup.BackupProvider;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
@EntityReference(BackupProvider.class)
public class BackupProviderResponse extends BaseResponse {
@SerializedName(ApiConstants.NAME)
@Param(description = "the CA service provider name")
private String name;
@SerializedName(ApiConstants.DESCRIPTION)
@Param(description = "the description of the CA service provider")
private String description;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
}

View File

@ -0,0 +1,246 @@
// 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.api.response;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.EntityReference;
import org.apache.cloudstack.backup.Backup;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
@EntityReference(value = Backup.class)
public class BackupResponse extends BaseResponse {
@SerializedName(ApiConstants.ID)
@Param(description = "ID of the VM backup")
private String id;
@SerializedName(ApiConstants.VIRTUAL_MACHINE_ID)
@Param(description = "ID of the VM")
private String vmId;
@SerializedName(ApiConstants.VIRTUAL_MACHINE_NAME)
@Param(description = "name of the VM")
private String vmName;
@SerializedName(ApiConstants.EXTERNAL_ID)
@Param(description = "external backup id")
private String externalId;
@SerializedName(ApiConstants.TYPE)
@Param(description = "backup type")
private String type;
@SerializedName(ApiConstants.CREATED)
@Param(description = "backup date")
private String date;
@SerializedName(ApiConstants.SIZE)
@Param(description = "backup size in bytes")
private Long size;
@SerializedName(ApiConstants.VIRTUAL_SIZE)
@Param(description = "backup protected (virtual) size in bytes")
private Long protectedSize;
@SerializedName(ApiConstants.STATUS)
@Param(description = "backup status")
private Backup.Status status;
@SerializedName(ApiConstants.VOLUMES)
@Param(description = "backed up volumes")
private String volumes;
@SerializedName(ApiConstants.BACKUP_OFFERING_ID)
@Param(description = "backup offering id")
private String backupOfferingId;
@SerializedName(ApiConstants.BACKUP_OFFERING_NAME)
@Param(description = "backup offering name")
private String backupOfferingName;
@SerializedName(ApiConstants.ACCOUNT_ID)
@Param(description = "account id")
private String accountId;
@SerializedName(ApiConstants.ACCOUNT)
@Param(description = "account name")
private String account;
@SerializedName(ApiConstants.DOMAIN_ID)
@Param(description = "domain id")
private String domainId;
@SerializedName(ApiConstants.DOMAIN)
@Param(description = "domain name")
private String domain;
@SerializedName(ApiConstants.ZONE_ID)
@Param(description = "zone id")
private String zoneId;
@SerializedName(ApiConstants.ZONE)
@Param(description = "zone name")
private String zone;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getVmId() {
return vmId;
}
public void setVmId(String vmId) {
this.vmId = vmId;
}
public String getVmName() {
return vmName;
}
public void setVmName(String vmName) {
this.vmName = vmName;
}
public String getExternalId() {
return externalId;
}
public void setExternalId(String externalId) {
this.externalId = externalId;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
public Long getSize() {
return size;
}
public void setSize(Long size) {
this.size = size;
}
public Long getProtectedSize() {
return protectedSize;
}
public void setProtectedSize(Long protectedSize) {
this.protectedSize = protectedSize;
}
public Backup.Status getStatus() {
return status;
}
public void setStatus(Backup.Status status) {
this.status = status;
}
public String getVolumes() {
return volumes;
}
public void setVolumes(String volumes) {
this.volumes = volumes;
}
public String getBackupOfferingId() {
return backupOfferingId;
}
public void setBackupOfferingId(String backupOfferingId) {
this.backupOfferingId = backupOfferingId;
}
public String getBackupOffering() {
return backupOfferingName;
}
public void setBackupOffering(String backupOfferingName) {
this.backupOfferingName = backupOfferingName;
}
public String getAccountId() {
return accountId;
}
public void setAccountId(String accountId) {
this.accountId = accountId;
}
public String getAccount() {
return account;
}
public void setAccount(String account) {
this.account = account;
}
public String getDomainId() {
return domainId;
}
public void setDomainId(String domainId) {
this.domainId = domainId;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
public String getZoneId() {
return zoneId;
}
public void setZoneId(String zoneId) {
this.zoneId = zoneId;
}
public String getZone() {
return zone;
}
public void setZone(String zone) {
this.zone = zone;
}
}

View File

@ -0,0 +1,66 @@
// 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.api.response;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.EntityReference;
import org.apache.cloudstack.backup.Backup;
import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
@EntityReference(value = Backup.RestorePoint.class)
public class BackupRestorePointResponse extends BaseResponse {
@SerializedName(ApiConstants.ID)
@Param(description = "external id of the restore point")
private String id;
@SerializedName(ApiConstants.CREATED)
@Param(description = "created time")
private String created;
@SerializedName(ApiConstants.TYPE)
@Param(description = "restore point type")
private String type;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCreated() {
return created;
}
public void setCreated(String created) {
this.created = created;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}

View File

@ -0,0 +1,91 @@
// 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.api.response;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.EntityReference;
import org.apache.cloudstack.backup.BackupSchedule;
import com.cloud.serializer.Param;
import com.cloud.utils.DateUtil;
import com.google.gson.annotations.SerializedName;
@EntityReference(value = BackupSchedule.class)
public class BackupScheduleResponse extends BaseResponse {
@SerializedName(ApiConstants.VIRTUAL_MACHINE_NAME)
@Param(description = "name of the VM")
private String vmName;
@SerializedName(ApiConstants.VIRTUAL_MACHINE_ID)
@Param(description = "ID of the VM")
private String vmId;
@SerializedName("schedule")
@Param(description = "time the backup is scheduled to be taken.")
private String schedule;
@SerializedName("intervaltype")
@Param(description = "the interval type of the backup schedule")
private DateUtil.IntervalType intervalType;
@SerializedName("timezone")
@Param(description = "the time zone of the backup schedule")
private String timezone;
public String getVmName() {
return vmName;
}
public void setVmName(String vmName) {
this.vmName = vmName;
}
public String getVmId() {
return vmId;
}
public void setVmId(String vmId) {
this.vmId = vmId;
}
public String getSchedule() {
return schedule;
}
public void setSchedule(String schedule) {
this.schedule = schedule;
}
public DateUtil.IntervalType getIntervalType() {
return intervalType;
}
public void setIntervalType(DateUtil.IntervalType intervalType) {
this.intervalType = intervalType;
}
public String getTimezone() {
return timezone;
}
public void setTimezone(String timezone) {
this.timezone = timezone;
}
}

View File

@ -156,6 +156,14 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
@Param(description = "the name of the disk offering of the virtual machine", since = "4.4")
private String diskOfferingName;
@SerializedName(ApiConstants.BACKUP_OFFERING_ID)
@Param(description = "the ID of the backup offering of the virtual machine", since = "4.14")
private String backupOfferingId;
@SerializedName(ApiConstants.BACKUP_OFFERING_NAME)
@Param(description = "the name of the backup offering of the virtual machine", since = "4.14")
private String backupOfferingName;
@SerializedName("forvirtualnetwork")
@Param(description = "the virtual network for the service offering")
private Boolean forVirtualNetwork;
@ -439,6 +447,14 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
return diskOfferingName;
}
public String getBackupOfferingId() {
return backupOfferingId;
}
public String getBackupOfferingName() {
return backupOfferingName;
}
public Boolean getForVirtualNetwork() {
return forVirtualNetwork;
}
@ -697,6 +713,14 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
this.diskOfferingName = diskOfferingName;
}
public void setBackupOfferingId(String backupOfferingId) {
this.backupOfferingId = backupOfferingId;
}
public void setBackupOfferingName(String backupOfferingName) {
this.backupOfferingName = backupOfferingName;
}
public void setCpuNumber(Integer cpuNumber) {
this.cpuNumber = cpuNumber;
}

View File

@ -0,0 +1,142 @@
//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
//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 org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
import com.cloud.storage.Volume;
import com.cloud.utils.StringUtils;
public interface Backup extends ControlledEntity, InternalIdentity, Identity {
enum Status {
Allocated, Queued, BackingUp, BackedUp, Error, Failed, Restoring, Removed, Expunged
}
class Metric {
private Long backupSize = 0L;
private Long dataSize = 0L;
public Metric(final Long backupSize, final Long dataSize) {
this.backupSize = backupSize;
this.dataSize = dataSize;
}
public Long getBackupSize() {
return backupSize;
}
public Long getDataSize() {
return dataSize;
}
public void setBackupSize(Long backupSize) {
this.backupSize = backupSize;
}
public void setDataSize(Long dataSize) {
this.dataSize = dataSize;
}
}
class RestorePoint {
private String id;
private String created;
private String type;
public RestorePoint(String id, String created, String type) {
this.id = id;
this.created = created;
this.type = type;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getCreated() {
return created;
}
public void setCreated(String created) {
this.created = created;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}
class VolumeInfo {
private String uuid;
private Volume.Type type;
private Long size;
private String path;
public VolumeInfo(String uuid, String path, Volume.Type type, Long size) {
this.uuid = uuid;
this.type = type;
this.size = size;
this.path = path;
}
public String getUuid() {
return uuid;
}
public Volume.Type getType() {
return type;
}
public void setType(Volume.Type type) {
this.type = type;
}
public String getPath() {
return path;
}
public Long getSize() {
return size;
}
@Override
public String toString() {
return StringUtils.join(":", uuid, path, type, size);
}
}
long getVmId();
String getExternalId();
String getType();
String getDate();
Backup.Status getStatus();
Long getSize();
Long getProtectedSize();
long getZoneId();
}

View File

@ -0,0 +1,140 @@
// 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 java.util.List;
import org.apache.cloudstack.api.command.admin.backup.ImportBackupOfferingCmd;
import org.apache.cloudstack.api.command.user.backup.CreateBackupScheduleCmd;
import org.apache.cloudstack.api.command.user.backup.ListBackupOfferingsCmd;
import org.apache.cloudstack.api.command.user.backup.ListBackupsCmd;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import com.cloud.utils.Pair;
import com.cloud.utils.component.Manager;
import com.cloud.utils.component.PluggableService;
/**
* Backup and Recover Manager Interface
*/
public interface BackupManager extends BackupService, Configurable, PluggableService, Manager {
ConfigKey<Boolean> BackupFrameworkEnabled = new ConfigKey<>("Advanced", Boolean.class,
"backup.framework.enabled",
"false",
"Is backup and recovery framework enabled.", true, ConfigKey.Scope.Zone);
ConfigKey<String> BackupProviderPlugin = new ConfigKey<>("Advanced", String.class,
"backup.framework.provider.plugin",
"dummy",
"The backup and recovery provider plugin.", true, ConfigKey.Scope.Zone);
ConfigKey<Long> BackupSyncPollingInterval = new ConfigKey<>("Advanced", Long.class,
"backup.framework.sync.interval",
"300",
"The backup and recovery background sync task polling interval in seconds.", true);
/**
* List backup provider offerings
* @param zoneId zone id
*/
List<BackupOffering> listBackupProviderOfferings(final Long zoneId);
/**
* Add a new Backup and Recovery policy to CloudStack by mapping an existing external backup offering to a name and description
* @param cmd import backup offering cmd
*/
BackupOffering importBackupOffering(final ImportBackupOfferingCmd cmd);
/**
* List backup offerings
* @param ListBackupOfferingsCmd API cmd
*/
Pair<List<BackupOffering>, Integer> listBackupOfferings(final ListBackupOfferingsCmd cmd);
/**
* Deletes a backup offering
*/
boolean deleteBackupOffering(final Long policyId);
/**
* Assigns a VM to a backup offering
* @param vmId
* @param offeringId
* @return
*/
boolean assignVMToBackupOffering(final Long vmId, final Long offeringId);
/**
* Removes a VM from a backup offering
* @param vmId
* @param forced
* @return
*/
boolean removeVMFromBackupOffering(final Long vmId, final boolean forced);
/**
* Creates or Updates a VM backup schedule
* @param cmd
* @return
*/
BackupSchedule configureBackupSchedule(CreateBackupScheduleCmd cmd);
/**
* Lists VM backup schedule for a VM
* @param vmId
* @return
*/
BackupSchedule listBackupSchedule(Long vmId);
/**
* Deletes VM backup schedule for a VM
* @param vmId
* @return
*/
boolean deleteBackupSchedule(Long vmId);
/**
* Creates backup of a VM
* @param vmId Virtual Machine ID
* @return returns operation success
*/
boolean createBackup(final Long vmId);
/**
* List existing backups for a VM
*/
Pair<List<Backup>, Integer> listBackups(final ListBackupsCmd cmd);
/**
* Restore a full VM from backup
*/
boolean restoreBackup(final Long backupId);
/**
* Restore a backed up volume and attach it to a VM
*/
boolean restoreBackupVolumeAndAttachToVM(final String backedUpVolumeUuid, final Long backupId, final Long vmId) throws Exception;
/**
* Deletes a backup
* @return returns operation success
*/
boolean deleteBackup(final Long backupId);
}

View File

@ -0,0 +1,32 @@
//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
//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 java.util.Date;
import org.apache.cloudstack.api.Identity;
import org.apache.cloudstack.api.InternalIdentity;
public interface BackupOffering extends InternalIdentity, Identity {
String getExternalId();
String getName();
String getDescription();
long getZoneId();
boolean isUserDrivenBackupAllowed();
String getProvider();
Date getCreated();
}

View File

@ -0,0 +1,111 @@
//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
//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 java.util.List;
import java.util.Map;
import com.cloud.utils.Pair;
import com.cloud.vm.VirtualMachine;
public interface BackupProvider {
/**
* Returns the unique name of the provider
* @return returns provider name
*/
String getName();
/**
* Returns description about the backup and recovery provider plugin
* @return returns description
*/
String getDescription();
/**
* Returns the list of existing backup policies on the provider
* @return backup policies list
*/
List<BackupOffering> listBackupOfferings(Long zoneId);
/**
* True if a backup offering exists on the backup provider
*/
boolean isValidProviderOffering(Long zoneId, String uuid);
/**
* Assign a VM to a backup offering or policy
* @param vm
* @param backup
* @param policy
* @return
*/
boolean assignVMToBackupOffering(VirtualMachine vm, BackupOffering backupOffering);
/**
* Removes a VM from a backup offering or policy
* @param vm
* @return
*/
boolean removeVMFromBackupOffering(VirtualMachine vm);
/**
* Whether the provide will delete backups on removal of VM from the offfering
* @return boolean result
*/
boolean willDeleteBackupsOnOfferingRemoval();
/**
* Starts and creates an adhoc backup process
* for a previously registered VM backup
* @param backup
* @return
*/
boolean takeBackup(VirtualMachine vm);
/**
* Delete an existing backup
* @param backup
* @return
*/
boolean deleteBackup(Backup backup);
/**
* Restore VM from backup
*/
boolean restoreVMFromBackup(VirtualMachine vm, Backup backup);
/**
* Restore a volume from a backup
*/
Pair<Boolean, String> restoreBackedUpVolume(Backup backup, String volumeUuid, String hostIp, String dataStoreUuid);
/**
* Returns backup metrics for a list of VMs in a zone
* @param zoneId
* @param vms
* @return
*/
Map<VirtualMachine, Backup.Metric> getBackupMetrics(Long zoneId, List<VirtualMachine> vms);
/**
* This method should reconcile and create backup entries for any backups created out-of-band
* @param vm
* @param metric
*/
void syncBackups(VirtualMachine vm, Backup.Metric metric);
}

View File

@ -0,0 +1,33 @@
// 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 java.util.Date;
import org.apache.cloudstack.api.InternalIdentity;
import com.cloud.utils.DateUtil;
public interface BackupSchedule extends InternalIdentity {
Long getVmId();
DateUtil.IntervalType getScheduleType();
String getSchedule();
String getTimezone();
Date getScheduledTimestamp();
Long getAsyncJobId();
}

View File

@ -0,0 +1,37 @@
//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
//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 java.util.List;
/**
* Backup and Recovery Services
*/
public interface BackupService {
/**
* Lists backup and recovery provider plugins
* @return list of providers
*/
List<BackupProvider> listBackupProviders();
/**
* Find backup provider by zone ID
* @param zoneId zone id
* @return backup provider
*/
BackupProvider getBackupProvider(final Long zoneId);
}

View File

@ -44,6 +44,7 @@ public class UsageTypes {
public static final int VM_SNAPSHOT = 25;
public static final int VOLUME_SECONDARY = 26;
public static final int VM_SNAPSHOT_ON_PRIMARY = 27;
public static final int BACKUP = 28;
public static List<UsageTypeResponse> listUsageTypes() {
List<UsageTypeResponse> responseList = new ArrayList<UsageTypeResponse>();
@ -68,6 +69,7 @@ public class UsageTypes {
responseList.add(new UsageTypeResponse(VM_SNAPSHOT, "VM Snapshot storage usage"));
responseList.add(new UsageTypeResponse(VOLUME_SECONDARY, "Volume on secondary storage usage"));
responseList.add(new UsageTypeResponse(VM_SNAPSHOT_ON_PRIMARY, "VM Snapshot on primary storage usage"));
responseList.add(new UsageTypeResponse(BACKUP, "Backup storage usage"));
return responseList;
}
}

View File

@ -478,6 +478,11 @@
<artifactId>cloud-plugin-integrations-prometheus-exporter</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-backup-dummy</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
@ -768,6 +773,33 @@
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/spring.schemas</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/services/com.sun.tools.xjc.Plugin</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/cxf/cxf.extension</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
<resource>META-INF/extensions.xml</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
<resource>META-INF/cxf/extensions.xml</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
<resource>META-INF/cxf/bus-extensions.txt</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
<resource>META-INF/cxf/bus-extensions.xml</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
<resource>META-INF/wsdl.plugin.xml</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
<resource>META-INF/tools.service.validator.xml</resource>
</transformer>
<transformer implementation="org.apache.maven.plugins.shade.resource.XmlAppendingTransformer">
<resource>META-INF/cxf/java2wsbeans.xml</resource>
</transformer>
</transformers>
<filters>
<filter>
@ -902,6 +934,16 @@
<artifactId>cloud-plugin-network-cisco-vnmc</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-api-vmware-sioc</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-backup-veeam</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</profile>
<profile>
@ -919,21 +961,6 @@
</dependency>
</dependencies>
</profile>
<profile>
<id>vmwaresioc</id>
<activation>
<property>
<name>noredist</name>
</property>
</activation>
<dependencies>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-api-vmware-sioc</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</profile>
<profile>
<id>quickcloud</id>
<activation>

View File

@ -0,0 +1,21 @@
#
# 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.
#
name=backup
parent=backend

View File

@ -0,0 +1,32 @@
<!--
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.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
>
<bean class="org.apache.cloudstack.spring.lifecycle.registry.RegistryLifecycle">
<property name="registry" ref="backupProvidersRegistry" />
<property name="typeClass" value="org.apache.cloudstack.backup.BackupProvider" />
</bean>
</beans>

View File

@ -328,4 +328,8 @@
class="org.apache.cloudstack.spring.lifecycle.registry.ExtensionRegistry">
</bean>
<bean id="backupProvidersRegistry"
class="org.apache.cloudstack.spring.lifecycle.registry.ExtensionRegistry">
</bean>
</beans>

View File

@ -121,6 +121,8 @@ public interface NetworkDao extends GenericDao<NetworkVO, Long>, StateDao<State,
List<NetworkVO> listNetworkVO(List<Long> idset);
NetworkVO findByVlan(String vlan);
List<NetworkVO> listByAccountIdNetworkName(long accountId, String name);
List<NetworkVO> listByPhysicalNetworkPvlan(long physicalNetworkId, String broadcastUri, Network.PVlanType pVlanType);

View File

@ -718,6 +718,14 @@ public class NetworkDaoImpl extends GenericDaoBase<NetworkVO, Long>implements Ne
return this.search(sc_2, searchFilter_2);
}
@Override
public NetworkVO findByVlan(String vlan) {
SearchCriteria<NetworkVO> sc = AllFieldsSearch.create();
sc.setParameters("broadcastType", BroadcastDomainType.Vlan);
sc.setParameters("broadcastUri", BroadcastDomainType.Vlan.toUri(vlan));
return findOneBy(sc);
}
@Override
public List<NetworkVO> listByAccountIdNetworkName(final long accountId, final String name) {
final SearchCriteria<NetworkVO> sc = AllFieldsSearch.create();

View File

@ -51,4 +51,6 @@ public interface ServiceOfferingDao extends GenericDao<ServiceOfferingVO, Long>
ServiceOfferingVO getComputeOffering(ServiceOfferingVO serviceOffering, Map<String, String> customParameters);
ServiceOfferingVO findDefaultSystemOffering(String offeringName, Boolean useLocalStorage);
List<ServiceOfferingVO> listPublicByCpuAndMemory(Integer cpus, Integer memory);
}

View File

@ -51,6 +51,7 @@ public class ServiceOfferingDaoImpl extends GenericDaoBase<ServiceOfferingVO, Lo
protected final SearchBuilder<ServiceOfferingVO> UniqueNameSearch;
protected final SearchBuilder<ServiceOfferingVO> ServiceOfferingsByKeywordSearch;
protected final SearchBuilder<ServiceOfferingVO> PublicCpuRamSearch;
public ServiceOfferingDaoImpl() {
super();
@ -64,6 +65,12 @@ public class ServiceOfferingDaoImpl extends GenericDaoBase<ServiceOfferingVO, Lo
ServiceOfferingsByKeywordSearch.or("name", ServiceOfferingsByKeywordSearch.entity().getName(), SearchCriteria.Op.EQ);
ServiceOfferingsByKeywordSearch.or("displayText", ServiceOfferingsByKeywordSearch.entity().getDisplayText(), SearchCriteria.Op.EQ);
ServiceOfferingsByKeywordSearch.done();
PublicCpuRamSearch = createSearchBuilder();
PublicCpuRamSearch.and("cpu", PublicCpuRamSearch.entity().getCpu(), SearchCriteria.Op.EQ);
PublicCpuRamSearch.and("ram", PublicCpuRamSearch.entity().getRamSize(), SearchCriteria.Op.EQ);
PublicCpuRamSearch.and("system_use", PublicCpuRamSearch.entity().isSystemUse(), SearchCriteria.Op.EQ);
PublicCpuRamSearch.done();
}
@Override
@ -246,4 +253,13 @@ public class ServiceOfferingDaoImpl extends GenericDaoBase<ServiceOfferingVO, Lo
}
return serviceOffering;
}
@Override
public List<ServiceOfferingVO> listPublicByCpuAndMemory(Integer cpus, Integer memory) {
SearchCriteria<ServiceOfferingVO> sc = PublicCpuRamSearch.create();
sc.setParameters("cpu", cpus);
sc.setParameters("ram", memory);
sc.setParameters("system_use", false);
return listBy(sc);
}
}

View File

@ -19,6 +19,7 @@ package com.cloud.storage.dao;
import java.util.List;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.Storage;
import com.cloud.utils.db.GenericDao;
public interface DiskOfferingDao extends GenericDao<DiskOfferingVO, Long> {
@ -31,4 +32,6 @@ public interface DiskOfferingDao extends GenericDao<DiskOfferingVO, Long> {
DiskOfferingVO persistDeafultDiskOffering(DiskOfferingVO offering);
List<DiskOfferingVO> listAllBySizeAndProvisioningType(long size, Storage.ProvisioningType provisioningType);
}

View File

@ -16,6 +16,10 @@
// under the License.
package com.cloud.storage.dao;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
@ -27,12 +31,15 @@ import org.springframework.stereotype.Component;
import com.cloud.offering.DiskOffering.Type;
import com.cloud.storage.DiskOfferingVO;
import com.cloud.storage.Storage;
import com.cloud.utils.db.Attribute;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.exception.CloudRuntimeException;
@Component
public class DiskOfferingDaoImpl extends GenericDaoBase<DiskOfferingVO, Long> implements DiskOfferingDao {
@ -43,7 +50,11 @@ public class DiskOfferingDaoImpl extends GenericDaoBase<DiskOfferingVO, Long> im
private final SearchBuilder<DiskOfferingVO> PrivateDiskOfferingSearch;
private final SearchBuilder<DiskOfferingVO> PublicDiskOfferingSearch;
protected final SearchBuilder<DiskOfferingVO> UniqueNameSearch;
private final String SizeDiskOfferingSearch = "SELECT * FROM disk_offering WHERE " +
"disk_size = ? AND provisioning_type = ? AND removed IS NULL";
private final Attribute _typeAttr;
protected final static long GB_UNIT_BYTES = 1024 * 1024 * 1024;
protected DiskOfferingDaoImpl() {
PrivateDiskOfferingSearch = createSearchBuilder();
@ -132,6 +143,36 @@ public class DiskOfferingDaoImpl extends GenericDaoBase<DiskOfferingVO, Long> im
}
}
protected long getClosestDiskSizeInGB(long sizeInBytes) {
if (sizeInBytes < 0) {
throw new CloudRuntimeException("Disk size should be greater than 0 bytes, received: " + sizeInBytes + " bytes");
}
return (long) Math.ceil(1.0 * sizeInBytes / GB_UNIT_BYTES);
}
@Override
public List<DiskOfferingVO> listAllBySizeAndProvisioningType(long size, Storage.ProvisioningType provisioningType) {
StringBuilder sql = new StringBuilder(SizeDiskOfferingSearch);
TransactionLegacy txn = TransactionLegacy.currentTxn();
List<DiskOfferingVO> offerings = new ArrayList<>();
try(PreparedStatement pstmt = txn.prepareStatement(sql.toString());){
if(pstmt != null) {
pstmt.setLong(1, size);
pstmt.setString(2, provisioningType.toString());
try(ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
offerings.add(toEntityBean(rs, false));
}
} catch (SQLException e) {
throw new CloudRuntimeException("Exception while listing disk offerings by size: " + e.getMessage(), e);
}
}
return offerings;
} catch (SQLException e) {
throw new CloudRuntimeException("Exception while listing disk offerings by size: " + e.getMessage(), e);
}
}
@Override
public boolean remove(Long id) {
DiskOfferingVO diskOffering = createForUpdate();

View File

@ -48,4 +48,8 @@ public interface VMTemplatePoolDao extends GenericDao<VMTemplateStoragePoolVO, L
boolean templateAvailable(long templateId, long poolId);
public VMTemplateStoragePoolVO findByHostTemplate(Long hostId, Long templateId);
VMTemplateStoragePoolVO findByPoolPath(Long poolId, String path);
List<VMTemplateStoragePoolVO> listByTemplatePath(String templatePath);
}

View File

@ -59,6 +59,7 @@ public class VMTemplatePoolDaoImpl extends GenericDaoBase<VMTemplateStoragePoolV
protected final SearchBuilder<VMTemplateStoragePoolVO> TemplateStatesSearch;
protected final SearchBuilder<VMTemplateStoragePoolVO> TemplatePoolStateSearch;
protected final SearchBuilder<VMTemplateStoragePoolVO> updateStateSearch;
protected final SearchBuilder<VMTemplateStoragePoolVO> templatePathSearch;
protected static final String UPDATE_TEMPLATE_HOST_REF = "UPDATE template_spool_ref SET download_state = ?, download_pct= ?, last_updated = ? "
+ ", error_str = ?, local_path = ?, job_id = ? " + "WHERE pool_id = ? and template_id = ?";
@ -114,6 +115,12 @@ public class VMTemplatePoolDaoImpl extends GenericDaoBase<VMTemplateStoragePoolV
updateStateSearch.and("state", updateStateSearch.entity().getState(), Op.EQ);
updateStateSearch.and("updatedCount", updateStateSearch.entity().getUpdatedCount(), Op.EQ);
updateStateSearch.done();
templatePathSearch = createSearchBuilder();
templatePathSearch.and("pool_id", templatePathSearch.entity().getPoolId(), Op.EQ);
templatePathSearch.and("local_path", templatePathSearch.entity().getLocalDownloadPath(), Op.EQ);
templatePathSearch.and("install_path", templatePathSearch.entity().getInstallPath(), Op.EQ);
templatePathSearch.done();
}
@Override
@ -260,6 +267,23 @@ public class VMTemplatePoolDaoImpl extends GenericDaoBase<VMTemplateStoragePoolV
return (result.size() == 0) ? null : result.get(1);
}
@Override
public VMTemplateStoragePoolVO findByPoolPath(Long poolId, String path) {
SearchCriteria<VMTemplateStoragePoolVO> sc = templatePathSearch.create();
sc.setParameters("local_path", path);
sc.setParameters("install_path", path);
sc.setParameters("pool_id", poolId);
return findOneBy(sc);
}
@Override
public List<VMTemplateStoragePoolVO> listByTemplatePath(String templatePath) {
SearchCriteria<VMTemplateStoragePoolVO> sc = templatePathSearch.create();
sc.setParameters("local_path", templatePath);
sc.setParameters("install_path", templatePath);
return listBy(sc);
}
@Override
public boolean updateState(State currentState, Event event, State nextState, DataObjectInStore vo, Object data) {
VMTemplateStoragePoolVO templatePool = (VMTemplateStoragePoolVO)vo;

View File

@ -46,6 +46,8 @@ public interface VolumeDao extends GenericDao<VolumeVO, Long>, StateDao<Volume.S
List<VolumeVO> findByInstanceAndType(long id, Volume.Type vType);
List<VolumeVO> findIncludingRemovedByInstanceAndType(long id, Volume.Type vType);
List<VolumeVO> findByInstanceIdAndPoolId(long instanceId, long poolId);
List<VolumeVO> findByInstanceIdDestroyed(long vmId);

View File

@ -190,6 +190,16 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
return listBy(sc);
}
@Override
public List<VolumeVO> findIncludingRemovedByInstanceAndType(long id, Type vType) {
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();
sc.setParameters("instanceId", id);
if (vType != null) {
sc.setParameters("vType", vType.toString());
}
return listIncludingRemovedBy(sc);
}
@Override
public List<VolumeVO> findByInstanceIdDestroyed(long vmId) {
SearchCriteria<VolumeVO> sc = AllFieldsSearch.create();

View File

@ -0,0 +1,172 @@
// 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 com.cloud.usage;
import java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import org.apache.cloudstack.api.InternalIdentity;
@Entity
@Table(name = "usage_backup")
public class UsageBackupVO implements InternalIdentity {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "zone_id")
private long zoneId;
@Column(name = "account_id")
private long accountId;
@Column(name = "domain_id")
private long domainId;
@Column(name = "vm_id")
private long vmId;
@Column(name = "backup_offering_id")
private long backupOfferingId;
@Column(name = "size")
private long size;
@Column(name = "protected_size")
private long protectedSize;
@Column(name = "created")
@Temporal(value = TemporalType.TIMESTAMP)
private Date created = null;
@Column(name = "removed")
@Temporal(value = TemporalType.TIMESTAMP)
private Date removed;
protected UsageBackupVO() {
}
public UsageBackupVO(long zoneId, long accountId, long domainId, long vmId, long backupOfferingId, Date created) {
this.zoneId = zoneId;
this.accountId = accountId;
this.domainId = domainId;
this.vmId = vmId;
this.backupOfferingId = backupOfferingId;
this.created = created;
}
public UsageBackupVO(long id, long zoneId, long accountId, long domainId, long vmId, long backupOfferingId, long size, long protectedSize, Date created, Date removed) {
this.id = id;
this.zoneId = zoneId;
this.accountId = accountId;
this.domainId = domainId;
this.vmId = vmId;
this.backupOfferingId = backupOfferingId;
this.size = size;
this.protectedSize = protectedSize;
this.created = created;
this.removed = removed;
}
@Override
public long getId() {
return id;
}
public long getZoneId() {
return zoneId;
}
public void setZoneId(long zoneId) {
this.zoneId = zoneId;
}
public long getAccountId() {
return accountId;
}
public void setAccountId(long accountId) {
this.accountId = accountId;
}
public long getDomainId() {
return domainId;
}
public void setDomainId(long domainId) {
this.domainId = domainId;
}
public long getVmId() {
return vmId;
}
public void setVmId(long vmId) {
this.vmId = vmId;
}
public long getBackupOfferingId() {
return backupOfferingId;
}
public void setBackupOfferingId(long backupOfferingId) {
this.backupOfferingId = backupOfferingId;
}
public long getSize() {
return size;
}
public void setSize(long size) {
this.size = size;
}
public long getProtectedSize() {
return protectedSize;
}
public void setProtectedSize(long protectedSize) {
this.protectedSize = protectedSize;
}
public Date getCreated() {
return created;
}
public void setCreated(Date created) {
this.created = created;
}
public Date getRemoved() {
return removed;
}
public void setRemoved(Date removed) {
this.removed = removed;
}
}

View File

@ -0,0 +1,33 @@
// 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 com.cloud.usage.dao;
import java.util.Date;
import java.util.List;
import org.apache.cloudstack.backup.Backup;
import com.cloud.usage.UsageBackupVO;
import com.cloud.utils.db.GenericDao;
import com.cloud.vm.VirtualMachine;
public interface UsageBackupDao extends GenericDao<UsageBackupVO, Long> {
void updateMetrics(VirtualMachine vm, Backup.Metric metric);
void removeUsage(Long accountId, Long zoneId, Long backupId);
List<UsageBackupVO> getUsageRecords(Long accountId, Date startDate, Date endDate);
}

View File

@ -0,0 +1,139 @@
// 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 com.cloud.usage.dao;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.TimeZone;
import org.apache.cloudstack.backup.Backup;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
import com.cloud.usage.UsageBackupVO;
import com.cloud.utils.DateUtil;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.QueryBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallback;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.db.TransactionStatus;
import com.cloud.vm.VirtualMachine;
@Component
public class UsageBackupDaoImpl extends GenericDaoBase<UsageBackupVO, Long> implements UsageBackupDao {
public static final Logger LOGGER = Logger.getLogger(UsageBackupDaoImpl.class);
protected static final String GET_USAGE_RECORDS_BY_ACCOUNT = "SELECT id, zone_id, account_id, domain_id, vm_id, backup_offering_id, size, protected_size, created, removed FROM cloud_usage.usage_backup WHERE " +
" account_id = ? AND ((removed IS NULL AND created <= ?) OR (created BETWEEN ? AND ?) OR (removed BETWEEN ? AND ?) " +
" OR ((created <= ?) AND (removed >= ?)))";
@Override
public void updateMetrics(final VirtualMachine vm, Backup.Metric metric) {
boolean result = Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<Boolean>() {
@Override
public Boolean doInTransaction(final TransactionStatus status) {
final QueryBuilder<UsageBackupVO> qb = QueryBuilder.create(UsageBackupVO.class);
qb.and(qb.entity().getVmId(), SearchCriteria.Op.EQ, vm.getId());
final UsageBackupVO entry = findOneBy(qb.create());
if (entry == null) {
return false;
}
entry.setSize(metric.getBackupSize());
entry.setProtectedSize(metric.getDataSize());
return update(entry.getId(), entry);
}
});
if (!result) {
LOGGER.trace("Failed to update backup metrics for VM ID: " + vm.getId());
}
}
@Override
public void removeUsage(Long accountId, Long zoneId, Long vmId) {
boolean result = Transaction.execute(TransactionLegacy.USAGE_DB, new TransactionCallback<Boolean>() {
@Override
public Boolean doInTransaction(final TransactionStatus status) {
final QueryBuilder<UsageBackupVO> qb = QueryBuilder.create(UsageBackupVO.class);
qb.and(qb.entity().getAccountId(), SearchCriteria.Op.EQ, accountId);
qb.and(qb.entity().getZoneId(), SearchCriteria.Op.EQ, zoneId);
qb.and(qb.entity().getVmId(), SearchCriteria.Op.EQ, vmId);
final UsageBackupVO entry = findOneBy(qb.create());
return remove(qb.create()) > 0;
}
});
if (!result) {
LOGGER.warn("Failed to remove usage entry for backup of VM ID: " + vmId);
}
}
@Override
public List<UsageBackupVO> getUsageRecords(Long accountId, Date startDate, Date endDate) {
List<UsageBackupVO> usageRecords = new ArrayList<UsageBackupVO>();
TransactionLegacy txn = TransactionLegacy.open(TransactionLegacy.USAGE_DB);
PreparedStatement pstmt;
try {
int i = 1;
pstmt = txn.prepareAutoCloseStatement(GET_USAGE_RECORDS_BY_ACCOUNT);
pstmt.setLong(i++, accountId);
pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), endDate));
pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), startDate));
pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), endDate));
pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), startDate));
pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), endDate));
pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), startDate));
pstmt.setString(i++, DateUtil.getDateDisplayString(TimeZone.getTimeZone("GMT"), endDate));
ResultSet rs = pstmt.executeQuery();
while (rs.next()) {
//id, zone_id, account_id, domain_id, vm_id, disk_offering_id, size, created, processed
Long id = Long.valueOf(rs.getLong(1));
Long zoneId = Long.valueOf(rs.getLong(2));
Long acctId = Long.valueOf(rs.getLong(3));
Long domId = Long.valueOf(rs.getLong(4));
Long vmId = Long.valueOf(rs.getLong(5));
Long backupOfferingId = Long.valueOf(rs.getLong(6));
Long size = Long.valueOf(rs.getLong(7));
Long pSize = Long.valueOf(rs.getLong(8));
Date createdDate = null;
Date removedDate = null;
String createdTS = rs.getString(9);
String removedTS = rs.getString(10);
if (createdTS != null) {
createdDate = DateUtil.parseDateString(s_gmtTimeZone, createdTS);
}
if (removedTS != null) {
removedDate = DateUtil.parseDateString(s_gmtTimeZone, removedTS);
}
usageRecords.add(new UsageBackupVO(id, zoneId, acctId, domId, vmId, backupOfferingId, size, pSize, createdDate, removedDate));
}
} catch (Exception e) {
txn.rollback();
LOGGER.warn("Error getting VM backup usage records", e);
} finally {
txn.close();
}
return usageRecords;
}
}

View File

@ -16,14 +16,14 @@
// under the License.
package com.cloud.vm;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.utils.db.Encrypt;
import com.cloud.utils.db.GenericDao;
import com.cloud.utils.db.StateMachine;
import com.cloud.utils.fsm.FiniteStateObject;
import com.cloud.vm.VirtualMachine.State;
import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
@ -39,11 +39,19 @@ import javax.persistence.TableGenerator;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Date;
import java.util.Map;
import java.util.UUID;
import org.apache.cloudstack.backup.Backup;
import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.utils.db.Encrypt;
import com.cloud.utils.db.GenericDao;
import com.cloud.utils.db.StateMachine;
import com.cloud.utils.fsm.FiniteStateObject;
import com.cloud.vm.VirtualMachine.State;
import com.google.common.base.Strings;
import com.google.gson.Gson;
@Entity
@Table(name = "vm_instance")
@ -186,6 +194,15 @@ public class VMInstanceVO implements VirtualMachine, FiniteStateObject<State, Vi
@Column(name = "power_host", updatable = true)
protected Long powerHostId;
@Column(name = "backup_offering_id")
protected Long backupOfferingId;
@Column(name = "backup_external_id")
protected String backupExternalId;
@Column(name = "backup_volumes")
protected String backupVolumes;
public VMInstanceVO(long id, long serviceOfferingId, String name, String instanceName, Type type, Long vmTemplateId, HypervisorType hypervisorType, long guestOSId,
long domainId, long accountId, long userId, boolean haEnabled) {
this.id = id;
@ -483,6 +500,10 @@ public class VMInstanceVO implements VirtualMachine, FiniteStateObject<State, Vi
this.details = details;
}
public void setRemoved(Date removed) {
this.removed = removed;
}
transient String toString;
@Override
@ -573,4 +594,38 @@ public class VMInstanceVO implements VirtualMachine, FiniteStateObject<State, Vi
public PartitionType partitionType() {
return PartitionType.VM;
}
public long getUserId() {
return userId;
}
@Override
public Long getBackupOfferingId() {
return backupOfferingId;
}
public void setBackupOfferingId(Long backupOfferingId) {
this.backupOfferingId = backupOfferingId;
}
@Override
public String getBackupExternalId() {
return backupExternalId;
}
public void setBackupExternalId(String backupExternalId) {
this.backupExternalId = backupExternalId;
}
@Override
public List<Backup.VolumeInfo> getBackupVolumeList() {
if (Strings.isNullOrEmpty(this.backupVolumes)) {
return Collections.emptyList();
}
return Arrays.asList(new Gson().fromJson(this.backupVolumes, Backup.VolumeInfo[].class));
}
public void setBackupVolumes(String backupVolumes) {
this.backupVolumes = backupVolumes;
}
}

View File

@ -86,4 +86,6 @@ public interface NicDao extends GenericDao<NicVO, Long> {
Long getPeerRouterId(String publicMacAddress, long routerId);
List<NicVO> listByVmIdAndKeyword(long instanceId, String keyword);
NicVO findByInstanceIdAndMacAddress(long instanceId, String macAddress);
}

View File

@ -364,4 +364,12 @@ public class NicDaoImpl extends GenericDaoBase<NicVO, Long> implements NicDao {
sc.setParameters("address", "%" + keyword + "%");
return listBy(sc);
}
@Override
public NicVO findByInstanceIdAndMacAddress(long instanceId, String macAddress) {
SearchCriteria<NicVO> sc = AllFieldsSearch.create();
sc.setParameters("instance", instanceId);
sc.setParameters("macAddress", macAddress);
return findOneBy(sc);
}
}

View File

@ -86,6 +86,8 @@ public interface VMInstanceDao extends GenericDao<VMInstanceVO, Long>, StateDao<
VMInstanceVO findVMByInstanceName(String name);
VMInstanceVO findVMByInstanceNameIncludingRemoved(String name);
VMInstanceVO findVMByHostName(String hostName);
void updateProxyId(long id, Long proxyId, Date time);
@ -114,6 +116,8 @@ public interface VMInstanceDao extends GenericDao<VMInstanceVO, Long>, StateDao<
List<VMInstanceVO> listVmsMigratingFromHost(Long hostId);
List<VMInstanceVO> listByZoneWithBackups(Long zoneId, Long backupOfferingId);
public Long countActiveByHostId(long hostId);
Pair<List<Long>, Map<Long, Double>> listClusterIdsInZoneByVmCount(long zoneId, long accountId);

View File

@ -94,6 +94,7 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
protected SearchBuilder<VMInstanceVO> HostAndStateSearch;
protected SearchBuilder<VMInstanceVO> StartingWithNoHostSearch;
protected SearchBuilder<VMInstanceVO> NotMigratingSearch;
protected SearchBuilder<VMInstanceVO> BackupSearch;
protected SearchBuilder<VMInstanceVO> LastHostAndStatesSearch;
@Inject
@ -288,6 +289,12 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
NotMigratingSearch.and("state", NotMigratingSearch.entity().getState(), Op.NEQ);
NotMigratingSearch.done();
BackupSearch = createSearchBuilder();
BackupSearch.and("zone_id", BackupSearch.entity().getDataCenterId(), Op.EQ);
BackupSearch.and("backup_offering_not_null", BackupSearch.entity().getBackupOfferingId(), Op.NNULL);
BackupSearch.and("backup_offering_id", BackupSearch.entity().getBackupOfferingId(), Op.EQ);
BackupSearch.done();
LastHostAndStatesSearch = createSearchBuilder();
LastHostAndStatesSearch.and("lastHost", LastHostAndStatesSearch.entity().getLastHostId(), Op.EQ);
LastHostAndStatesSearch.and("states", LastHostAndStatesSearch.entity().getState(), Op.IN);
@ -456,6 +463,13 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
return findOneBy(sc);
}
@Override
public VMInstanceVO findVMByInstanceNameIncludingRemoved(String name) {
SearchCriteria<VMInstanceVO> sc = InstanceNameSearch.create();
sc.setParameters("instanceName", name);
return findOneIncludingRemovedBy(sc);
}
@Override
public VMInstanceVO findVMByHostName(String hostName) {
SearchCriteria<VMInstanceVO> sc = HostNameSearch.create();
@ -591,6 +605,16 @@ public class VMInstanceDaoImpl extends GenericDaoBase<VMInstanceVO, Long> implem
return listBy(sc);
}
@Override
public List<VMInstanceVO> listByZoneWithBackups(Long zoneId, Long backupOfferingId) {
SearchCriteria<VMInstanceVO> sc = BackupSearch.create();
sc.setParameters("zone_id", zoneId);
if (backupOfferingId != null) {
sc.setParameters("backup_offering_id", backupOfferingId);
}
return listBy(sc);
}
@Override
public Long countActiveByHostId(long hostId) {
SearchCriteria<Long> sc = CountActiveByHost.create();

View File

@ -0,0 +1,126 @@
// 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 java.util.Date;
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
@Entity
@Table(name = "backup_offering")
public class BackupOfferingVO implements BackupOffering {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@Column(name = "uuid")
private String uuid;
@Column(name = "name")
private String name;
@Column(name = "description")
private String description;
@Column(name = "external_id")
private String externalId;
@Column(name = "zone_id")
private long zoneId;
@Column(name = "user_driven_backup")
private boolean userDrivenBackupAllowed;
@Column(name = "provider")
private String provider;
@Column(name = "created")
@Temporal(value = TemporalType.TIMESTAMP)
private Date created;
@Column(name = "removed")
@Temporal(value = TemporalType.TIMESTAMP)
private Date removed;
public BackupOfferingVO() {
this.uuid = UUID.randomUUID().toString();
}
public BackupOfferingVO(final long zoneId, final String externalId, final String provider, final String name, final String description, final boolean userDrivenBackupAllowed) {
this();
this.name = name;
this.description = description;
this.zoneId = zoneId;
this.provider = provider;
this.externalId = externalId;
this.userDrivenBackupAllowed = userDrivenBackupAllowed;
this.created = new Date();
}
public String getUuid() {
return uuid;
}
public long getId() {
return id;
}
public String getName() {
return name;
}
public String getExternalId() {
return externalId;
}
@Override
public long getZoneId() {
return zoneId;
}
@Override
public boolean isUserDrivenBackupAllowed() {
return userDrivenBackupAllowed;
}
public void setUserDrivenBackupAllowed(boolean userDrivenBackupAllowed) {
this.userDrivenBackupAllowed = userDrivenBackupAllowed;
}
@Override
public String getProvider() {
return provider;
}
public String getDescription() {
return description;
}
public Date getCreated() {
return created;
}
}

View File

@ -0,0 +1,124 @@
// 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 java.util.Date;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import com.cloud.utils.DateUtil;
@Entity
@Table(name = "backup_schedule")
public class BackupScheduleVO implements BackupSchedule {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@Column(name = "vm_id")
private Long vmId;
@Column(name = "schedule_type")
private Short scheduleType;
@Column(name = "schedule")
String schedule;
@Column(name = "timezone")
String timezone;
@Column(name = "scheduled_timestamp")
@Temporal(value = TemporalType.TIMESTAMP)
Date scheduledTimestamp;
@Column(name = "async_job_id")
Long asyncJobId;
public BackupScheduleVO() {
}
public BackupScheduleVO(Long vmId, DateUtil.IntervalType scheduleType, String schedule, String timezone, Date scheduledTimestamp) {
this.vmId = vmId;
this.scheduleType = (short) scheduleType.ordinal();
this.schedule = schedule;
this.timezone = timezone;
this.scheduledTimestamp = scheduledTimestamp;
}
@Override
public long getId() {
return id;
}
public Long getVmId() {
return vmId;
}
public void setVmId(Long vmId) {
this.vmId = vmId;
}
@Override
public DateUtil.IntervalType getScheduleType() {
return scheduleType == null ? null : DateUtil.getIntervalType(scheduleType);
}
public void setScheduleType(Short intervalType) {
this.scheduleType = intervalType;
}
public String getSchedule() {
return schedule;
}
public void setSchedule(String schedule) {
this.schedule = schedule;
}
public String getTimezone() {
return timezone;
}
public void setTimezone(String timezone) {
this.timezone = timezone;
}
public Date getScheduledTimestamp() {
return scheduledTimestamp;
}
public void setScheduledTimestamp(Date scheduledTimestamp) {
this.scheduledTimestamp = scheduledTimestamp;
}
public Long getAsyncJobId() {
return asyncJobId;
}
public void setAsyncJobId(Long asyncJobId) {
this.asyncJobId = asyncJobId;
}
}

View File

@ -0,0 +1,190 @@
//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
//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 java.util.UUID;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Table;
@Entity
@Table(name = "backups")
public class BackupVO implements Backup {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private long id;
@Column(name = "uuid")
private String uuid;
@Column(name = "vm_id")
private long vmId;
@Column(name = "external_id")
private String externalId;
@Column(name = "type")
private String backupType;
@Column(name = "date")
private String date;
@Column(name = "size")
private Long size;
@Column(name = "protected_size")
private Long protectedSize;
@Enumerated(value = EnumType.STRING)
@Column(name = "status")
private Backup.Status status;
@Column(name = "backup_offering_id")
private long backupOfferingId;
@Column(name = "account_id")
private long accountId;
@Column(name = "domain_id")
private long domainId;
@Column(name = "zone_id")
private long zoneId;
public BackupVO() {
this.uuid = UUID.randomUUID().toString();
}
@Override
public long getId() {
return id;
}
@Override
public String getUuid() {
return uuid;
}
@Override
public long getVmId() {
return vmId;
}
public void setVmId(long vmId) {
this.vmId = vmId;
}
@Override
public String getExternalId() {
return externalId;
}
public void setExternalId(String externalId) {
this.externalId = externalId;
}
public String getType() {
return backupType;
}
public void setType(String type) {
this.backupType = type;
}
@Override
public String getDate() {
return date;
}
public void setDate(String date) {
this.date = date;
}
@Override
public Long getSize() {
return size;
}
public void setSize(Long size) {
this.size = size;
}
@Override
public Long getProtectedSize() {
return protectedSize;
}
public void setProtectedSize(Long protectedSize) {
this.protectedSize = protectedSize;
}
@Override
public Status getStatus() {
return status;
}
public void setStatus(Status status) {
this.status = status;
}
public long getBackupOfferingId() {
return backupOfferingId;
}
public void setBackupOfferingId(long backupOfferingId) {
this.backupOfferingId = backupOfferingId;
}
@Override
public long getAccountId() {
return accountId;
}
public void setAccountId(long accountId) {
this.accountId = accountId;
}
@Override
public long getDomainId() {
return domainId;
}
public void setDomainId(long domainId) {
this.domainId = domainId;
}
public long getZoneId() {
return zoneId;
}
public void setZoneId(long zoneId) {
this.zoneId = zoneId;
}
@Override
public Class<?> getEntityType() {
return Backup.class;
}
}

View File

@ -0,0 +1,40 @@
// 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.dao;
import java.util.List;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.backup.Backup;
import org.apache.cloudstack.backup.BackupVO;
import com.cloud.utils.db.GenericDao;
public interface BackupDao extends GenericDao<BackupVO, Long> {
Backup findByVmId(Long vmId);
Backup findByVmIdIncludingRemoved(Long vmId);
List<Backup> listByVmId(Long zoneId, Long vmId);
List<Backup> listByAccountId(Long accountId);
List<Backup> listByOfferingId(Long offeringId);
List<Backup> syncBackups(Long zoneId, Long vmId, List<Backup> externalBackups);
BackupVO getBackupVO(Backup backup);
BackupResponse newBackupResponse(Backup backup);
}

View File

@ -0,0 +1,172 @@
// 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.dao;
import java.util.ArrayList;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import org.apache.cloudstack.api.response.BackupResponse;
import org.apache.cloudstack.backup.Backup;
import org.apache.cloudstack.backup.BackupOffering;
import org.apache.cloudstack.backup.BackupVO;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.domain.DomainVO;
import com.cloud.domain.dao.DomainDao;
import com.cloud.user.AccountVO;
import com.cloud.user.dao.AccountDao;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.dao.VMInstanceDao;
import com.google.gson.Gson;
public class BackupDaoImpl extends GenericDaoBase<BackupVO, Long> implements BackupDao {
@Inject
AccountDao accountDao;
@Inject
DomainDao domainDao;
@Inject
DataCenterDao dataCenterDao;
@Inject
VMInstanceDao vmInstanceDao;
@Inject
BackupOfferingDao backupOfferingDao;
private SearchBuilder<BackupVO> backupSearch;
public BackupDaoImpl() {
}
@PostConstruct
protected void init() {
backupSearch = createSearchBuilder();
backupSearch.and("vm_id", backupSearch.entity().getVmId(), SearchCriteria.Op.EQ);
backupSearch.and("external_id", backupSearch.entity().getExternalId(), SearchCriteria.Op.EQ);
backupSearch.done();
}
@Override
public List<Backup> listByAccountId(Long accountId) {
SearchCriteria<BackupVO> sc = backupSearch.create();
sc.setParameters("account_id", accountId);
return new ArrayList<>(listBy(sc));
}
@Override
public Backup findByVmId(Long vmId) {
SearchCriteria<BackupVO> sc = backupSearch.create();
sc.setParameters("vm_id", vmId);
return findOneBy(sc);
}
@Override
public Backup findByVmIdIncludingRemoved(Long vmId) {
SearchCriteria<BackupVO> sc = backupSearch.create();
sc.setParameters("vm_id", vmId);
return findOneIncludingRemovedBy(sc);
}
@Override
public List<Backup> listByVmId(Long zoneId, Long vmId) {
SearchCriteria<BackupVO> sc = backupSearch.create();
sc.setParameters("vm_id", vmId);
if (zoneId != null) {
sc.setParameters("zone_id", zoneId);
}
return new ArrayList<>(listBy(sc));
}
@Override
public List<Backup> listByOfferingId(Long offeringId) {
SearchCriteria<BackupVO> sc = backupSearch.create();
sc.setParameters("offering_id", offeringId);
return new ArrayList<>(listBy(sc));
}
private Backup findByExternalId(Long zoneId, String externalId) {
SearchCriteria<BackupVO> sc = backupSearch.create();
sc.setParameters("external_id", externalId);
sc.setParameters("zone_id", zoneId);
return findOneBy(sc);
}
public BackupVO getBackupVO(Backup backup) {
BackupVO backupVO = new BackupVO();
backupVO.setExternalId(backup.getExternalId());
backupVO.setVmId(backup.getVmId());
return backupVO;
}
public void removeExistingBackups(Long zoneId, Long vmId) {
SearchCriteria<BackupVO> sc = backupSearch.create();
sc.setParameters("vm_id", vmId);
sc.setParameters("zone_id", zoneId);
expunge(sc);
}
@Override
public List<Backup> syncBackups(Long zoneId, Long vmId, List<Backup> externalBackups) {
for (Backup backup : externalBackups) {
BackupVO backupVO = getBackupVO(backup);
persist(backupVO);
}
return listByVmId(zoneId, vmId);
}
@Override
public BackupResponse newBackupResponse(Backup backup) {
VMInstanceVO vm = vmInstanceDao.findByIdIncludingRemoved(backup.getVmId());
AccountVO account = accountDao.findByIdIncludingRemoved(vm.getAccountId());
DomainVO domain = domainDao.findByIdIncludingRemoved(vm.getDomainId());
DataCenterVO zone = dataCenterDao.findByIdIncludingRemoved(vm.getDataCenterId());
BackupOffering offering = backupOfferingDao.findByIdIncludingRemoved(vm.getBackupOfferingId());
BackupResponse response = new BackupResponse();
response.setId(backup.getUuid());
response.setVmId(vm.getUuid());
response.setVmName(vm.getHostName());
response.setExternalId(backup.getExternalId());
response.setType(backup.getType());
response.setDate(backup.getDate());
response.setSize(backup.getSize());
response.setProtectedSize(backup.getProtectedSize());
response.setStatus(backup.getStatus());
response.setVolumes(new Gson().toJson(vm.getBackupVolumeList().toArray(), Backup.VolumeInfo[].class));
response.setBackupOfferingId(offering.getUuid());
response.setBackupOffering(offering.getName());
response.setAccountId(account.getUuid());
response.setAccount(account.getAccountName());
response.setDomainId(domain.getUuid());
response.setDomain(domain.getName());
response.setZoneId(zone.getUuid());
response.setZone(zone.getName());
response.setObjectName("backup");
return response;
}
}

View File

@ -0,0 +1,30 @@
// 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.dao;
import org.apache.cloudstack.api.response.BackupOfferingResponse;
import org.apache.cloudstack.backup.BackupOffering;
import org.apache.cloudstack.backup.BackupOfferingVO;
import com.cloud.utils.db.GenericDao;
public interface BackupOfferingDao extends GenericDao<BackupOfferingVO, Long> {
BackupOfferingResponse newBackupOfferingResponse(BackupOffering policy);
BackupOffering findByExternalId(String externalId, Long zoneId);
BackupOffering findByName(String name, Long zoneId);
}

View File

@ -0,0 +1,88 @@
// 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.dao;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import org.apache.cloudstack.api.response.BackupOfferingResponse;
import org.apache.cloudstack.backup.BackupOffering;
import org.apache.cloudstack.backup.BackupOfferingVO;
import com.cloud.dc.DataCenterVO;
import com.cloud.dc.dao.DataCenterDao;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
public class BackupOfferingDaoImpl extends GenericDaoBase<BackupOfferingVO, Long> implements BackupOfferingDao {
@Inject
DataCenterDao dataCenterDao;
private SearchBuilder<BackupOfferingVO> backupPoliciesSearch;
public BackupOfferingDaoImpl() {
}
@PostConstruct
protected void init() {
backupPoliciesSearch = createSearchBuilder();
backupPoliciesSearch.and("name", backupPoliciesSearch.entity().getName(), SearchCriteria.Op.EQ);
backupPoliciesSearch.and("zone_id", backupPoliciesSearch.entity().getZoneId(), SearchCriteria.Op.EQ);
backupPoliciesSearch.and("external_id", backupPoliciesSearch.entity().getExternalId(), SearchCriteria.Op.EQ);
backupPoliciesSearch.done();
}
@Override
public BackupOfferingResponse newBackupOfferingResponse(BackupOffering offering) {
DataCenterVO zone = dataCenterDao.findById(offering.getZoneId());
BackupOfferingResponse response = new BackupOfferingResponse();
response.setId(offering.getUuid());
response.setName(offering.getName());
response.setDescription(offering.getDescription());
response.setExternalId(offering.getExternalId());
response.setUserDrivenBackups(offering.isUserDrivenBackupAllowed());
if (zone != null) {
response.setZoneId(zone.getUuid());
response.setZoneName(zone.getName());
}
response.setCreated(offering.getCreated());
response.setObjectName("backupoffering");
return response;
}
@Override
public BackupOffering findByExternalId(String externalId, Long zoneId) {
SearchCriteria<BackupOfferingVO> sc = backupPoliciesSearch.create();
sc.setParameters("external_id", externalId);
if (zoneId != null) {
sc.setParameters("zone_id", zoneId);
}
return findOneBy(sc);
}
@Override
public BackupOffering findByName(String name, Long zoneId) {
SearchCriteria<BackupOfferingVO> sc = backupPoliciesSearch.create();
sc.setParameters("name", name);
sc.setParameters("zone_id", zoneId);
return findOneBy(sc);
}
}

View File

@ -0,0 +1,35 @@
// 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.dao;
import java.util.Date;
import java.util.List;
import org.apache.cloudstack.api.response.BackupScheduleResponse;
import org.apache.cloudstack.backup.BackupSchedule;
import org.apache.cloudstack.backup.BackupScheduleVO;
import com.cloud.utils.db.GenericDao;
public interface BackupScheduleDao extends GenericDao<BackupScheduleVO, Long> {
BackupScheduleVO findByVM(Long vmId);
List<BackupScheduleVO> getSchedulesToExecute(Date currentTimestamp);
BackupScheduleResponse newBackupScheduleResponse(BackupSchedule schedule);
}

View File

@ -0,0 +1,86 @@
// 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.dao;
import java.util.Date;
import java.util.List;
import javax.annotation.PostConstruct;
import javax.inject.Inject;
import org.apache.cloudstack.api.response.BackupScheduleResponse;
import org.apache.cloudstack.backup.BackupSchedule;
import org.apache.cloudstack.backup.BackupScheduleVO;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.dao.VMInstanceDao;
public class BackupScheduleDaoImpl extends GenericDaoBase<BackupScheduleVO, Long> implements BackupScheduleDao {
@Inject
VMInstanceDao vmInstanceDao;
private SearchBuilder<BackupScheduleVO> backupScheduleSearch;
private SearchBuilder<BackupScheduleVO> executableSchedulesSearch;
public BackupScheduleDaoImpl() {
}
@PostConstruct
protected void init() {
backupScheduleSearch = createSearchBuilder();
backupScheduleSearch.and("vm_id", backupScheduleSearch.entity().getVmId(), SearchCriteria.Op.EQ);
backupScheduleSearch.and("async_job_id", backupScheduleSearch.entity().getAsyncJobId(), SearchCriteria.Op.EQ);
backupScheduleSearch.done();
executableSchedulesSearch = createSearchBuilder();
executableSchedulesSearch.and("scheduledTimestamp", executableSchedulesSearch.entity().getScheduledTimestamp(), SearchCriteria.Op.LT);
executableSchedulesSearch.and("asyncJobId", executableSchedulesSearch.entity().getAsyncJobId(), SearchCriteria.Op.NULL);
executableSchedulesSearch.done();
}
@Override
public BackupScheduleVO findByVM(Long vmId) {
SearchCriteria<BackupScheduleVO> sc = backupScheduleSearch.create();
sc.setParameters("vm_id", vmId);
return findOneBy(sc);
}
@Override
public List<BackupScheduleVO> getSchedulesToExecute(Date currentTimestamp) {
SearchCriteria<BackupScheduleVO> sc = executableSchedulesSearch.create();
sc.setParameters("scheduledTimestamp", currentTimestamp);
return listBy(sc);
}
@Override
public BackupScheduleResponse newBackupScheduleResponse(BackupSchedule schedule) {
VMInstanceVO vm = vmInstanceDao.findByIdIncludingRemoved(schedule.getVmId());
BackupScheduleResponse response = new BackupScheduleResponse();
response.setVmId(vm.getUuid());
response.setVmName(vm.getHostName());
response.setIntervalType(schedule.getScheduleType());
response.setSchedule(schedule.getSchedule());
response.setTimezone(schedule.getTimezone());
response.setObjectName("backupschedule");
return response;
}
}

View File

@ -16,13 +16,12 @@
// under the License.
package org.apache.cloudstack.engine.cloud.entity.api.db;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.utils.db.Encrypt;
import com.cloud.utils.db.GenericDao;
import com.cloud.utils.db.StateMachine;
import com.cloud.utils.fsm.FiniteStateObject;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.State;
import java.security.SecureRandom;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import javax.persistence.Column;
import javax.persistence.DiscriminatorColumn;
@ -38,11 +37,17 @@ import javax.persistence.TableGenerator;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
import java.security.SecureRandom;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import org.apache.cloudstack.backup.Backup;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.utils.db.Encrypt;
import com.cloud.utils.db.GenericDao;
import com.cloud.utils.db.StateMachine;
import com.cloud.utils.fsm.FiniteStateObject;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.VirtualMachine.State;
import com.google.gson.Gson;
@Entity
@Table(name = "vm_instance")
@ -175,6 +180,15 @@ public class VMEntityVO implements VirtualMachine, FiniteStateObject<State, Virt
@Column(name = "display_vm", updatable = true, nullable = false)
protected boolean display = true;
@Column(name = "backup_offering_id")
protected Long backupOfferingId;
@Column(name = "backup_external_id")
private String backupExternalId;
@Column(name = "backup_volumes")
private String backupVolumes;
@Transient
private VMReservationVO vmReservation;
@ -555,4 +569,19 @@ public class VMEntityVO implements VirtualMachine, FiniteStateObject<State, Virt
public PartitionType partitionType() {
return PartitionType.VM;
}
@Override
public Long getBackupOfferingId() {
return backupOfferingId;
}
@Override
public String getBackupExternalId() {
return backupExternalId;
}
@Override
public List<Backup.VolumeInfo> getBackupVolumeList() {
return Arrays.asList(new Gson().fromJson(this.backupVolumes, Backup.VolumeInfo[].class));
}
}

View File

@ -218,6 +218,7 @@
<bean id="usageVPNUserDaoImpl" class="com.cloud.usage.dao.UsageVPNUserDaoImpl" />
<bean id="usageVolumeDaoImpl" class="com.cloud.usage.dao.UsageVolumeDaoImpl" />
<bean id="usageVmDiskDaoImpl" class="com.cloud.usage.dao.UsageVmDiskDaoImpl" />
<bean id="usageBackupDaoImpl" class="com.cloud.usage.dao.UsageBackupDaoImpl" />
<bean id="userAccountDaoImpl" class="com.cloud.user.dao.UserAccountDaoImpl" />
<bean id="userAccountJoinDaoImpl" class="com.cloud.api.query.dao.UserAccountJoinDaoImpl" />
<bean id="userIpv6AddressDaoImpl" class="com.cloud.network.dao.UserIpv6AddressDaoImpl" />
@ -285,6 +286,9 @@
<bean id="outOfBandManagementDaoImpl" class="org.apache.cloudstack.outofbandmanagement.dao.OutOfBandManagementDaoImpl" />
<bean id="GuestOsDetailsDaoImpl" class="org.apache.cloudstack.resourcedetail.dao.GuestOsDetailsDaoImpl" />
<bean id="annotationDaoImpl" class="org.apache.cloudstack.annotation.dao.AnnotationDaoImpl" />
<bean id="backupOfferingDaoImpl" class="org.apache.cloudstack.backup.dao.BackupOfferingDaoImpl" />
<bean id="backupScheduleDaoImpl" class="org.apache.cloudstack.backup.dao.BackupScheduleDaoImpl" />
<bean id="backupDaoImpl" class="org.apache.cloudstack.backup.dao.BackupDaoImpl" />
<bean id="directDownloadCertificateDaoImpl" class="org.apache.cloudstack.direct.download.DirectDownloadCertificateDaoImpl" />
<bean id="directDownloadCertificateHostMapDaoImpl" class="org.apache.cloudstack.direct.download.DirectDownloadCertificateHostMapDaoImpl" />
<bean id="templateOVFPropertiesDaoImpl" class="com.cloud.storage.dao.TemplateOVFPropertiesDaoImpl" />

View File

@ -28,6 +28,256 @@ UPDATE `cloud`.`vm_template` SET guest_os_id=99 WHERE id=1;
-- #3659 Fix typo: the past tense of shutdown is shutdown, not shutdowned
UPDATE `cloud`.`vm_instance` SET state='Shutdown' WHERE state='Shutdowned';
-- Backup and Recovery
CREATE TABLE IF NOT EXISTS `cloud`.`backup_offering` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`uuid` varchar(40) NOT NULL UNIQUE,
`name` varchar(255) NOT NULL COMMENT 'backup offering name',
`description` varchar(255) NOT NULL COMMENT 'backup offering description',
`external_id` varchar(255) DEFAULT NULL COMMENT 'external ID on provider side',
`user_driven_backup` tinyint(1) unsigned NOT NULL DEFAULT 0 COMMENT 'whether user can do adhoc backups and backup schedules allowed, default false',
`zone_id` bigint(20) unsigned NOT NULL COMMENT 'zone id',
`provider` varchar(255) NOT NULL COMMENT 'backup provider',
`created` datetime DEFAULT NULL,
`removed` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `fk_backup_offering__zone_id` FOREIGN KEY (`zone_id`) REFERENCES `data_center` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
ALTER TABLE `cloud`.`vm_instance` ADD COLUMN `backup_offering_id` bigint unsigned DEFAULT NULL COMMENT 'ID of backup offering';
ALTER TABLE `cloud`.`vm_instance` ADD COLUMN `backup_external_id` varchar(255) DEFAULT NULL COMMENT 'ID of external backup job or container if any';
ALTER TABLE `cloud`.`vm_instance` ADD COLUMN `backup_volumes` text DEFAULT NULL COMMENT 'details of backedup volumes';
CREATE TABLE IF NOT EXISTS `cloud`.`backups` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`uuid` varchar(40) NOT NULL UNIQUE,
`vm_id` bigint(20) unsigned NOT NULL,
`external_id` varchar(255) DEFAULT NULL COMMENT 'external ID',
`type` varchar(255) NOT NULL COMMENT 'backup type',
`date` varchar(255) NOT NULL COMMENT 'backup date',
`size` bigint(20) DEFAULT 0 COMMENT 'size of the backup',
`protected_size` bigint(20) DEFAULT 0,
`status` varchar(32) DEFAULT NULL,
`backup_offering_id` bigint(20) unsigned NOT NULL,
`account_id` bigint(20) unsigned NOT NULL,
`domain_id` bigint(20) unsigned NOT NULL,
`zone_id` bigint(20) unsigned NOT NULL,
`removed` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
CONSTRAINT `fk_backup__vm_id` FOREIGN KEY (`vm_id`) REFERENCES `vm_instance` (`id`) ON DELETE CASCADE,
CONSTRAINT `fk_backup__account_id` FOREIGN KEY (`account_id`) REFERENCES `account` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `cloud`.`backup_schedule` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`vm_id` bigint(20) unsigned NOT NULL UNIQUE,
`schedule_type` int(4) DEFAULT NULL COMMENT 'backup schedulet type e.g. hourly, daily, etc.',
`schedule` varchar(100) DEFAULT NULL COMMENT 'schedule time of execution',
`timezone` varchar(100) DEFAULT NULL COMMENT 'the timezone in which the schedule time is specified',
`scheduled_timestamp` datetime DEFAULT NULL COMMENT 'Time at which the backup was scheduled for execution',
`async_job_id` bigint(20) unsigned DEFAULT NULL COMMENT 'If this schedule is being executed, it is the id of the create aysnc_job. Before that it is null',
PRIMARY KEY (`id`),
CONSTRAINT `fk_backup_schedule__vm_id` FOREIGN KEY (`vm_id`) REFERENCES `vm_instance` (`id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
CREATE TABLE IF NOT EXISTS `cloud_usage`.`usage_backup` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`zone_id` bigint(20) unsigned NOT NULL,
`account_id` bigint(20) unsigned NOT NULL,
`domain_id` bigint(20) unsigned NOT NULL,
`vm_id` bigint(20) unsigned NOT NULL,
`backup_offering_id` bigint(20) unsigned NOT NULL,
`size` bigint(20) DEFAULT 0,
`protected_size` bigint(20) DEFAULT 0,
`created` datetime NOT NULL,
`removed` datetime DEFAULT NULL,
PRIMARY KEY (`id`),
INDEX `i_usage_backup` (`zone_id`,`account_id`,`vm_id`,`created`)
) ENGINE=InnoDB CHARSET=utf8;
DROP VIEW IF EXISTS `cloud`.`user_vm_view`;
CREATE
VIEW `user_vm_view` AS
SELECT
`vm_instance`.`id` AS `id`,
`vm_instance`.`name` AS `name`,
`user_vm`.`display_name` AS `display_name`,
`user_vm`.`user_data` AS `user_data`,
`account`.`id` AS `account_id`,
`account`.`uuid` AS `account_uuid`,
`account`.`account_name` AS `account_name`,
`account`.`type` AS `account_type`,
`domain`.`id` AS `domain_id`,
`domain`.`uuid` AS `domain_uuid`,
`domain`.`name` AS `domain_name`,
`domain`.`path` AS `domain_path`,
`projects`.`id` AS `project_id`,
`projects`.`uuid` AS `project_uuid`,
`projects`.`name` AS `project_name`,
`instance_group`.`id` AS `instance_group_id`,
`instance_group`.`uuid` AS `instance_group_uuid`,
`instance_group`.`name` AS `instance_group_name`,
`vm_instance`.`uuid` AS `uuid`,
`vm_instance`.`user_id` AS `user_id`,
`vm_instance`.`last_host_id` AS `last_host_id`,
`vm_instance`.`vm_type` AS `type`,
`vm_instance`.`limit_cpu_use` AS `limit_cpu_use`,
`vm_instance`.`created` AS `created`,
`vm_instance`.`state` AS `state`,
`vm_instance`.`removed` AS `removed`,
`vm_instance`.`ha_enabled` AS `ha_enabled`,
`vm_instance`.`hypervisor_type` AS `hypervisor_type`,
`vm_instance`.`instance_name` AS `instance_name`,
`vm_instance`.`guest_os_id` AS `guest_os_id`,
`vm_instance`.`display_vm` AS `display_vm`,
`guest_os`.`uuid` AS `guest_os_uuid`,
`vm_instance`.`pod_id` AS `pod_id`,
`host_pod_ref`.`uuid` AS `pod_uuid`,
`vm_instance`.`private_ip_address` AS `private_ip_address`,
`vm_instance`.`private_mac_address` AS `private_mac_address`,
`vm_instance`.`vm_type` AS `vm_type`,
`data_center`.`id` AS `data_center_id`,
`data_center`.`uuid` AS `data_center_uuid`,
`data_center`.`name` AS `data_center_name`,
`data_center`.`is_security_group_enabled` AS `security_group_enabled`,
`data_center`.`networktype` AS `data_center_type`,
`host`.`id` AS `host_id`,
`host`.`uuid` AS `host_uuid`,
`host`.`name` AS `host_name`,
`vm_template`.`id` AS `template_id`,
`vm_template`.`uuid` AS `template_uuid`,
`vm_template`.`name` AS `template_name`,
`vm_template`.`display_text` AS `template_display_text`,
`vm_template`.`enable_password` AS `password_enabled`,
`iso`.`id` AS `iso_id`,
`iso`.`uuid` AS `iso_uuid`,
`iso`.`name` AS `iso_name`,
`iso`.`display_text` AS `iso_display_text`,
`service_offering`.`id` AS `service_offering_id`,
`svc_disk_offering`.`uuid` AS `service_offering_uuid`,
`disk_offering`.`uuid` AS `disk_offering_uuid`,
`disk_offering`.`id` AS `disk_offering_id`,
(CASE
WHEN ISNULL(`service_offering`.`cpu`) THEN `custom_cpu`.`value`
ELSE `service_offering`.`cpu`
END) AS `cpu`,
(CASE
WHEN ISNULL(`service_offering`.`speed`) THEN `custom_speed`.`value`
ELSE `service_offering`.`speed`
END) AS `speed`,
(CASE
WHEN ISNULL(`service_offering`.`ram_size`) THEN `custom_ram_size`.`value`
ELSE `service_offering`.`ram_size`
END) AS `ram_size`,
`backup_offering`.`uuid` AS `backup_offering_uuid`,
`backup_offering`.`id` AS `backup_offering_id`,
`svc_disk_offering`.`name` AS `service_offering_name`,
`disk_offering`.`name` AS `disk_offering_name`,
`backup_offering`.`name` AS `backup_offering_name`,
`storage_pool`.`id` AS `pool_id`,
`storage_pool`.`uuid` AS `pool_uuid`,
`storage_pool`.`pool_type` AS `pool_type`,
`volumes`.`id` AS `volume_id`,
`volumes`.`uuid` AS `volume_uuid`,
`volumes`.`device_id` AS `volume_device_id`,
`volumes`.`volume_type` AS `volume_type`,
`security_group`.`id` AS `security_group_id`,
`security_group`.`uuid` AS `security_group_uuid`,
`security_group`.`name` AS `security_group_name`,
`security_group`.`description` AS `security_group_description`,
`nics`.`id` AS `nic_id`,
`nics`.`uuid` AS `nic_uuid`,
`nics`.`network_id` AS `network_id`,
`nics`.`ip4_address` AS `ip_address`,
`nics`.`ip6_address` AS `ip6_address`,
`nics`.`ip6_gateway` AS `ip6_gateway`,
`nics`.`ip6_cidr` AS `ip6_cidr`,
`nics`.`default_nic` AS `is_default_nic`,
`nics`.`gateway` AS `gateway`,
`nics`.`netmask` AS `netmask`,
`nics`.`mac_address` AS `mac_address`,
`nics`.`broadcast_uri` AS `broadcast_uri`,
`nics`.`isolation_uri` AS `isolation_uri`,
`vpc`.`id` AS `vpc_id`,
`vpc`.`uuid` AS `vpc_uuid`,
`networks`.`uuid` AS `network_uuid`,
`networks`.`name` AS `network_name`,
`networks`.`traffic_type` AS `traffic_type`,
`networks`.`guest_type` AS `guest_type`,
`user_ip_address`.`id` AS `public_ip_id`,
`user_ip_address`.`uuid` AS `public_ip_uuid`,
`user_ip_address`.`public_ip_address` AS `public_ip_address`,
`ssh_keypairs`.`keypair_name` AS `keypair_name`,
`resource_tags`.`id` AS `tag_id`,
`resource_tags`.`uuid` AS `tag_uuid`,
`resource_tags`.`key` AS `tag_key`,
`resource_tags`.`value` AS `tag_value`,
`resource_tags`.`domain_id` AS `tag_domain_id`,
`domain`.`uuid` AS `tag_domain_uuid`,
`domain`.`name` AS `tag_domain_name`,
`resource_tags`.`account_id` AS `tag_account_id`,
`account`.`account_name` AS `tag_account_name`,
`resource_tags`.`resource_id` AS `tag_resource_id`,
`resource_tags`.`resource_uuid` AS `tag_resource_uuid`,
`resource_tags`.`resource_type` AS `tag_resource_type`,
`resource_tags`.`customer` AS `tag_customer`,
`async_job`.`id` AS `job_id`,
`async_job`.`uuid` AS `job_uuid`,
`async_job`.`job_status` AS `job_status`,
`async_job`.`account_id` AS `job_account_id`,
`affinity_group`.`id` AS `affinity_group_id`,
`affinity_group`.`uuid` AS `affinity_group_uuid`,
`affinity_group`.`name` AS `affinity_group_name`,
`affinity_group`.`description` AS `affinity_group_description`,
`vm_instance`.`dynamically_scalable` AS `dynamically_scalable`
FROM
(((((((((((((((((((((((((((((((((`user_vm`
JOIN `vm_instance` ON (((`vm_instance`.`id` = `user_vm`.`id`)
AND ISNULL(`vm_instance`.`removed`))))
JOIN `account` ON ((`vm_instance`.`account_id` = `account`.`id`)))
JOIN `domain` ON ((`vm_instance`.`domain_id` = `domain`.`id`)))
LEFT JOIN `guest_os` ON ((`vm_instance`.`guest_os_id` = `guest_os`.`id`)))
LEFT JOIN `host_pod_ref` ON ((`vm_instance`.`pod_id` = `host_pod_ref`.`id`)))
LEFT JOIN `projects` ON ((`projects`.`project_account_id` = `account`.`id`)))
LEFT JOIN `instance_group_vm_map` ON ((`vm_instance`.`id` = `instance_group_vm_map`.`instance_id`)))
LEFT JOIN `instance_group` ON ((`instance_group_vm_map`.`group_id` = `instance_group`.`id`)))
LEFT JOIN `data_center` ON ((`vm_instance`.`data_center_id` = `data_center`.`id`)))
LEFT JOIN `host` ON ((`vm_instance`.`host_id` = `host`.`id`)))
LEFT JOIN `vm_template` ON ((`vm_instance`.`vm_template_id` = `vm_template`.`id`)))
LEFT JOIN `vm_template` `iso` ON ((`iso`.`id` = `user_vm`.`iso_id`)))
LEFT JOIN `service_offering` ON ((`vm_instance`.`service_offering_id` = `service_offering`.`id`)))
LEFT JOIN `disk_offering` `svc_disk_offering` ON ((`vm_instance`.`service_offering_id` = `svc_disk_offering`.`id`)))
LEFT JOIN `disk_offering` ON ((`vm_instance`.`disk_offering_id` = `disk_offering`.`id`)))
LEFT JOIN `backup_offering` ON ((`vm_instance`.`backup_offering_id` = `backup_offering`.`id`)))
LEFT JOIN `volumes` ON ((`vm_instance`.`id` = `volumes`.`instance_id`)))
LEFT JOIN `storage_pool` ON ((`volumes`.`pool_id` = `storage_pool`.`id`)))
LEFT JOIN `security_group_vm_map` ON ((`vm_instance`.`id` = `security_group_vm_map`.`instance_id`)))
LEFT JOIN `security_group` ON ((`security_group_vm_map`.`security_group_id` = `security_group`.`id`)))
LEFT JOIN `nics` ON (((`vm_instance`.`id` = `nics`.`instance_id`)
AND ISNULL(`nics`.`removed`))))
LEFT JOIN `networks` ON ((`nics`.`network_id` = `networks`.`id`)))
LEFT JOIN `vpc` ON (((`networks`.`vpc_id` = `vpc`.`id`)
AND ISNULL(`vpc`.`removed`))))
LEFT JOIN `user_ip_address` ON ((`user_ip_address`.`vm_id` = `vm_instance`.`id`)))
LEFT JOIN `user_vm_details` `ssh_details` ON (((`ssh_details`.`vm_id` = `vm_instance`.`id`)
AND (`ssh_details`.`name` = 'SSH.PublicKey'))))
LEFT JOIN `ssh_keypairs` ON (((`ssh_keypairs`.`public_key` = `ssh_details`.`value`)
AND (`ssh_keypairs`.`account_id` = `account`.`id`))))
LEFT JOIN `resource_tags` ON (((`resource_tags`.`resource_id` = `vm_instance`.`id`)
AND (`resource_tags`.`resource_type` = 'UserVm'))))
LEFT JOIN `async_job` ON (((`async_job`.`instance_id` = `vm_instance`.`id`)
AND (`async_job`.`instance_type` = 'VirtualMachine')
AND (`async_job`.`job_status` = 0))))
LEFT JOIN `affinity_group_vm_map` ON ((`vm_instance`.`id` = `affinity_group_vm_map`.`instance_id`)))
LEFT JOIN `affinity_group` ON ((`affinity_group_vm_map`.`affinity_group_id` = `affinity_group`.`id`)))
LEFT JOIN `user_vm_details` `custom_cpu` ON (((`custom_cpu`.`vm_id` = `vm_instance`.`id`)
AND (`custom_cpu`.`name` = 'CpuNumber'))))
LEFT JOIN `user_vm_details` `custom_speed` ON (((`custom_speed`.`vm_id` = `vm_instance`.`id`)
AND (`custom_speed`.`name` = 'CpuSpeed'))))
LEFT JOIN `user_vm_details` `custom_ram_size` ON (((`custom_ram_size`.`vm_id` = `vm_instance`.`id`)
AND (`custom_ram_size`.`name` = 'memory'))));
-- Fix OS category for some Ubuntu and RedHat OS-es
UPDATE `cloud`.`guest_os` SET `category_id`='10' WHERE `id`=277 AND display_name="Ubuntu 17.04";
UPDATE `cloud`.`guest_os` SET `category_id`='10' WHERE `id`=278 AND display_name="Ubuntu 17.10";

View File

@ -0,0 +1,56 @@
// 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 com.cloud.storage.dao;
import com.cloud.utils.exception.CloudRuntimeException;
import org.junit.Assert;
import org.junit.Test;
public class DiskOfferingDaoImplTest {
private final DiskOfferingDaoImpl dao = new DiskOfferingDaoImpl();
@Test(expected = CloudRuntimeException.class)
public void testGetClosestDiskSizeInGBNegativeSize() {
long size = -4 * DiskOfferingDaoImpl.GB_UNIT_BYTES;
dao.getClosestDiskSizeInGB(size);
}
@Test
public void testGetClosestDiskSizeInGBSizeGB() {
int gbUnits = 5;
long size = gbUnits * DiskOfferingDaoImpl.GB_UNIT_BYTES;
long sizeInGB = dao.getClosestDiskSizeInGB(size);
Assert.assertEquals(gbUnits, sizeInGB);
}
@Test
public void testGetClosestDiskSizeInGBSizeGBRest() {
int gbUnits = 5;
long size = gbUnits * DiskOfferingDaoImpl.GB_UNIT_BYTES + 12345;
long sizeInGB = dao.getClosestDiskSizeInGB(size);
Assert.assertEquals(gbUnits + 1, sizeInGB);
}
@Test
public void testGetClosestDiskSizeInGBSizeLessOneGB() {
int gbUnits = 1;
long size = gbUnits * DiskOfferingDaoImpl.GB_UNIT_BYTES - 12345;
long sizeInGB = dao.getClosestDiskSizeInGB(size);
Assert.assertEquals(gbUnits, sizeInGB);
}
}

View File

@ -234,6 +234,8 @@ public interface GenericDao<T, ID extends Serializable> {
*/
void expunge();
boolean unremove(ID id);
public <K> K getNextInSequence(Class<K> clazz, String name);
/**

View File

@ -1785,6 +1785,34 @@ public abstract class GenericDaoBase<T, ID extends Serializable> extends Compone
}
}
@Override
public boolean unremove(ID id) {
if (_removed == null) {
return false;
}
final TransactionLegacy txn = TransactionLegacy.currentTxn();
PreparedStatement pstmt = null;
try {
txn.start();
pstmt = txn.prepareAutoCloseStatement(_removeSql.first());
final Attribute[] attrs = _removeSql.second();
pstmt.setObject(1, null);
for (int i = 0; i < attrs.length - 1; i++) {
prepareAttribute(i + 2, pstmt, attrs[i], id);
}
final int result = pstmt.executeUpdate();
txn.commit();
if (_cache != null) {
_cache.remove(id);
}
return result > 0;
} catch (final SQLException e) {
throw new CloudRuntimeException("DB Exception on: " + pstmt, e);
}
}
@DB()
protected void setField(final Object entity, final ResultSet rs, ResultSetMetaData meta, final int index) throws SQLException {
Attribute attr = _allColumns.get(new Pair<String, String>(meta.getTableName(index), meta.getColumnName(index)));

View File

@ -158,6 +158,7 @@ public class QuotaManagerImpl extends ManagerBase implements QuotaManager {
case QuotaTypes.ISO:
case QuotaTypes.VOLUME:
case QuotaTypes.VM_SNAPSHOT:
case QuotaTypes.BACKUP:
qu = updateQuotaDiskUsage(usageRecord, aggregationRatio, usageRecord.getUsageType());
if (qu != null) {
quotaListForAccount.add(qu);

View File

@ -16,12 +16,12 @@
// under the License.
package org.apache.cloudstack.quota.constant;
import org.apache.cloudstack.usage.UsageTypes;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import org.apache.cloudstack.usage.UsageTypes;
public class QuotaTypes extends UsageTypes {
public static final int CPU_CLOCK_RATE = 15;
public static final int CPU_NUMBER = 16;
@ -57,6 +57,7 @@ public class QuotaTypes extends UsageTypes {
quotaTypeList.put(VM_SNAPSHOT, new QuotaTypes(VM_SNAPSHOT, "VM_SNAPSHOT", "GB-Month", "VM Snapshot storage usage"));
quotaTypeList.put(VOLUME_SECONDARY, new QuotaTypes(VOLUME_SECONDARY, "VOLUME_SECONDARY", "GB-Month", "Volume secondary storage usage"));
quotaTypeList.put(VM_SNAPSHOT_ON_PRIMARY, new QuotaTypes(VM_SNAPSHOT_ON_PRIMARY, "VM_SNAPSHOT_ON_PRIMARY", "GB-Month", "VM Snapshot primary storage usage"));
quotaTypeList.put(BACKUP, new QuotaTypes(BACKUP, "BACKUP", "GB-Month", "Backup storage usage"));
quotaTypeList.put(CPU_CLOCK_RATE, new QuotaTypes(CPU_CLOCK_RATE, "CPU_CLOCK_RATE", "Compute-Month", "Quota tariff for using 1 CPU of clock rate 100MHz"));
quotaTypeList.put(CPU_NUMBER, new QuotaTypes(CPU_NUMBER, "CPU_NUMBER", "Compute-Month", "Quota tariff for running VM that has 1vCPU"));
quotaTypeList.put(MEMORY, new QuotaTypes(MEMORY, "MEMORY", "Compute-Month", "Quota tariff for using 1MB of RAM"));

View File

@ -0,0 +1,41 @@
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-plugin-backup-dummy</artifactId>
<name>Apache CloudStack Plugin - Dummy Backup and Recovery Plugin</name>
<parent>
<artifactId>cloudstack-plugins</artifactId>
<groupId>org.apache.cloudstack</groupId>
<version>4.14.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-api</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-utils</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,134 @@
// 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 java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.inject.Inject;
import org.apache.cloudstack.backup.dao.BackupDao;
import org.apache.log4j.Logger;
import com.cloud.utils.Pair;
import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
public class DummyBackupProvider extends AdapterBase implements BackupProvider {
private static final Logger s_logger = Logger.getLogger(DummyBackupProvider.class);
@Inject
private BackupDao backupDao;
@Override
public String getName() {
return "dummy";
}
@Override
public String getDescription() {
return "Dummy Backup Plugin";
}
@Override
public List<BackupOffering> listBackupOfferings(Long zoneId) {
s_logger.debug("Listing backup policies on Dummy B&R Plugin");
BackupOffering policy1 = new BackupOfferingVO(1, "gold-policy", "dummy", "Golden Policy", "Gold description", true);
BackupOffering policy2 = new BackupOfferingVO(1, "silver-policy", "dummy", "Silver Policy", "Silver description", true);
return Arrays.asList(policy1, policy2);
}
@Override
public boolean isValidProviderOffering(Long zoneId, String uuid) {
s_logger.debug("Checking if backup offering exists on the Dummy Backup Provider");
return true;
}
@Override
public boolean assignVMToBackupOffering(VirtualMachine vm, BackupOffering backupOffering) {
s_logger.debug("Creating VM backup for VM " + vm.getInstanceName() + " from backup offering " + backupOffering.getName());
((VMInstanceVO) vm).setBackupExternalId("dummy-external-backup-id");
return true;
}
@Override
public boolean restoreVMFromBackup(VirtualMachine vm, Backup backup) {
s_logger.debug("Restoring vm " + vm.getUuid() + "from backup " + backup.getUuid() + " on the Dummy Backup Provider");
return true;
}
@Override
public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, String volumeUuid, String hostIp, String dataStoreUuid) {
s_logger.debug("Restoring volume " + volumeUuid + "from backup " + backup.getUuid() + " on the Dummy Backup Provider");
throw new CloudRuntimeException("Dummy plugin does not support this feature");
}
@Override
public Map<VirtualMachine, Backup.Metric> getBackupMetrics(Long zoneId, List<VirtualMachine> vms) {
final Map<VirtualMachine, Backup.Metric> metrics = new HashMap<>();
final Backup.Metric metric = new Backup.Metric(1000L, 100L);
for (VirtualMachine vm : vms) {
metrics.put(vm, metric);
}
return metrics;
}
@Override
public boolean removeVMFromBackupOffering(VirtualMachine vm) {
s_logger.debug("Removing VM ID " + vm.getUuid() + " from backup offering by the Dummy Backup Provider");
return true;
}
@Override
public boolean willDeleteBackupsOnOfferingRemoval() {
return true;
}
@Override
public boolean takeBackup(VirtualMachine vm) {
s_logger.debug("Starting backup for VM ID " + vm.getUuid() + " on Dummy provider");
BackupVO backup = new BackupVO();
backup.setVmId(vm.getId());
backup.setExternalId("dummy-external-id");
backup.setType("FULL");
backup.setDate(new Date().toString());
backup.setSize(1024L);
backup.setProtectedSize(1024000L);
backup.setStatus(Backup.Status.BackedUp);
backup.setBackupOfferingId(vm.getBackupOfferingId());
backup.setAccountId(vm.getAccountId());
backup.setDomainId(vm.getDomainId());
backup.setZoneId(vm.getDataCenterId());
return backupDao.persist(backup) != null;
}
@Override
public boolean deleteBackup(Backup backup) {
return true;
}
@Override
public void syncBackups(VirtualMachine vm, Backup.Metric metric) {
}
}

View File

@ -0,0 +1,18 @@
# 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.
name=dummy-backup
parent=backup

View File

@ -0,0 +1,27 @@
<!--
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.
-->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
>
<bean id="dummyBackupRecoveryDriver" class="org.apache.cloudstack.backup.DummyBackupProvider">
<property name="name" value="dummy" />
</bean>
</beans>

View File

@ -0,0 +1,54 @@
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>cloud-plugin-backup-veeam</artifactId>
<name>Apache CloudStack Plugin - Veeam Backup and Recovery Plugin</name>
<parent>
<artifactId>cloudstack-plugins</artifactId>
<groupId>org.apache.cloudstack</groupId>
<version>4.14.0.0-SNAPSHOT</version>
<relativePath>../../pom.xml</relativePath>
</parent>
<dependencies>
<dependency>
<groupId>org.apache.cloudstack</groupId>
<artifactId>cloud-plugin-hypervisor-vmware</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>${cs.jackson.version}</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${cs.commons-lang3.version}</version>
</dependency>
<dependency>
<groupId>com.github.tomakehurst</groupId>
<artifactId>wiremock-standalone</artifactId>
<version>${cs.wiremock.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,310 @@
// 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 java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import javax.inject.Inject;
import org.apache.cloudstack.api.InternalIdentity;
import org.apache.cloudstack.backup.dao.BackupDao;
import org.apache.cloudstack.backup.veeam.VeeamClient;
import org.apache.cloudstack.backup.veeam.api.Job;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;
import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
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.utils.Pair;
import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.db.Transaction;
import com.cloud.utils.db.TransactionCallbackNoReturn;
import com.cloud.utils.db.TransactionStatus;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
public class VeeamBackupProvider extends AdapterBase implements BackupProvider, Configurable {
private static final Logger LOG = Logger.getLogger(VeeamBackupProvider.class);
public static final String BACKUP_IDENTIFIER = "-CSBKP-";
public ConfigKey<String> VeeamUrl = new ConfigKey<>("Advanced", String.class,
"backup.plugin.veeam.url", "https://localhost:9398/api/",
"The Veeam backup and recovery URL.", 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);
private ConfigKey<String> VeeamPassword = new ConfigKey<>("Secure", String.class,
"backup.plugin.veeam.password", "",
"The Veeam backup and recovery password.", true, ConfigKey.Scope.Zone);
private ConfigKey<Boolean> VeeamValidateSSLSecurity = new ConfigKey<>("Advanced", Boolean.class, "backup.plugin.veeam.validate.ssl", "false",
"When set to true, this will validate the SSL certificate when connecting to https/ssl enabled Veeam API service.", true, ConfigKey.Scope.Zone);
private ConfigKey<Integer> VeeamApiRequestTimeout = new ConfigKey<>("Advanced", Integer.class, "backup.plugin.veeam.request.timeout", "300",
"The Veeam B&R API request timeout in seconds.", true, ConfigKey.Scope.Zone);
@Inject
private VmwareDatacenterZoneMapDao vmwareDatacenterZoneMapDao;
@Inject
private VmwareDatacenterDao vmwareDatacenterDao;
@Inject
private BackupDao backupDao;
private VeeamClient getClient(final Long zoneId) {
try {
return new VeeamClient(VeeamUrl.valueIn(zoneId), VeeamUsername.valueIn(zoneId), VeeamPassword.valueIn(zoneId),
VeeamValidateSSLSecurity.valueIn(zoneId), VeeamApiRequestTimeout.valueIn(zoneId));
} catch (URISyntaxException e) {
throw new CloudRuntimeException("Failed to parse Veeam API URL: " + e.getMessage());
} catch (NoSuchAlgorithmException | KeyManagementException e) {
LOG.error("Failed to build Veeam API client due to: ", e);
}
throw new CloudRuntimeException("Failed to build Veeam API client");
}
public List<BackupOffering> listBackupOfferings(final Long zoneId) {
List<BackupOffering> policies = new ArrayList<>();
for (final BackupOffering policy : getClient(zoneId).listJobs()) {
if (!policy.getName().contains(BACKUP_IDENTIFIER)) {
policies.add(policy);
}
}
return policies;
}
@Override
public boolean isValidProviderOffering(final Long zoneId, final String uuid) {
List<BackupOffering> policies = listBackupOfferings(zoneId);
if (CollectionUtils.isEmpty(policies)) {
return false;
}
for (final BackupOffering policy : policies) {
if (policy.getExternalId().equals(uuid)) {
return true;
}
}
return false;
}
private VmwareDatacenter findVmwareDatacenterForVM(final VirtualMachine vm) {
if (vm == null || vm.getHypervisorType() != Hypervisor.HypervisorType.VMware) {
throw new CloudRuntimeException("The Veeam backup provider is only applicable for VMware VMs");
}
final VmwareDatacenterZoneMap zoneMap = vmwareDatacenterZoneMapDao.findByZoneId(vm.getDataCenterId());
if (zoneMap == null) {
throw new CloudRuntimeException("Failed to find a mapped VMware datacenter for zone id:" + vm.getDataCenterId());
}
final VmwareDatacenter vmwareDatacenter = vmwareDatacenterDao.findById(zoneMap.getVmwareDcId());
if (vmwareDatacenter == null) {
throw new CloudRuntimeException("Failed to find a valid VMware datacenter mapped for zone id:" + vm.getDataCenterId());
}
return vmwareDatacenter;
}
private String getGuestBackupName(final String instanceName, final String uuid) {
return String.format("%s%s%s", instanceName, BACKUP_IDENTIFIER, uuid);
}
@Override
public boolean assignVMToBackupOffering(final VirtualMachine vm, final BackupOffering backupOffering) {
final VeeamClient client = getClient(vm.getDataCenterId());
final Job parentJob = client.listJob(backupOffering.getExternalId());
final String clonedJobName = getGuestBackupName(vm.getInstanceName(), vm.getUuid());
if (!client.cloneVeeamJob(parentJob, clonedJobName)) {
LOG.error("Failed to clone pre-defined Veeam job (backup offering) for backup offering ID: " + backupOffering.getExternalId() + " but will check the list of jobs again if it was eventually succeeded.");
}
for (final BackupOffering job : client.listJobs()) {
if (job.getName().equals(clonedJobName)) {
final Job clonedJob = client.listJob(job.getExternalId());
if (clonedJob.getScheduleConfigured() && !clonedJob.getScheduleEnabled()) {
client.toggleJobSchedule(clonedJob.getId());
}
LOG.debug("Veeam job (backup offering) for backup offering ID: " + backupOffering.getExternalId() + " found, now trying to assign the VM to the job.");
final VmwareDatacenter vmwareDC = findVmwareDatacenterForVM(vm);
if (client.addVMToVeeamJob(job.getExternalId(), vm.getInstanceName(), vmwareDC.getVcenterHost())) {
((VMInstanceVO) vm).setBackupExternalId(job.getExternalId());
return true;
}
}
}
return false;
}
@Override
public boolean removeVMFromBackupOffering(final VirtualMachine vm) {
final VeeamClient client = getClient(vm.getDataCenterId());
final VmwareDatacenter vmwareDC = findVmwareDatacenterForVM(vm);
try {
if (!client.removeVMFromVeeamJob(vm.getBackupExternalId(), vm.getInstanceName(), vmwareDC.getVcenterHost())) {
LOG.warn("Failed to remove VM from Veeam Job id: " + vm.getBackupExternalId());
}
} catch (Exception e) {
LOG.debug("VM was removed from the job so could not remove again, trying to delete the veeam job now.", e);
}
final String clonedJobName = getGuestBackupName(vm.getInstanceName(), vm.getUuid());
if (!client.deleteJobAndBackup(clonedJobName)) {
LOG.warn("Failed to remove Veeam job and backup for job: " + clonedJobName);
throw new CloudRuntimeException("Failed to delete Veeam B&R job and backup, an operation may be in progress. Please try again after some time.");
}
return true;
}
@Override
public boolean willDeleteBackupsOnOfferingRemoval() {
return true;
}
@Override
public boolean takeBackup(final VirtualMachine vm) {
final VeeamClient client = getClient(vm.getDataCenterId());
return client.startBackupJob(vm.getBackupExternalId());
}
@Override
public boolean deleteBackup(Backup backup) {
// Veeam does not support removal of a restore point or point-in-time backup
throw new CloudRuntimeException("Veeam B&R plugin does not allow removal of backup restore point, to delete the backup chain remove VM from the backup offering");
}
@Override
public boolean restoreVMFromBackup(VirtualMachine vm, Backup backup) {
final String restorePointId = backup.getExternalId();
return getClient(vm.getDataCenterId()).restoreFullVM(vm.getInstanceName(), restorePointId);
}
@Override
public Pair<Boolean, String> restoreBackedUpVolume(Backup backup, String volumeUuid, String hostIp, String dataStoreUuid) {
final Long zoneId = backup.getZoneId();
final String restorePointId = backup.getExternalId();
return getClient(zoneId).restoreVMToDifferentLocation(restorePointId, hostIp, dataStoreUuid);
}
@Override
public Map<VirtualMachine, Backup.Metric> getBackupMetrics(final Long zoneId, final List<VirtualMachine> vms) {
final Map<VirtualMachine, Backup.Metric> metrics = new HashMap<>();
final Map<String, Backup.Metric> backendMetrics = getClient(zoneId).getBackupMetrics();
for (final VirtualMachine vm : vms) {
if (!backendMetrics.containsKey(vm.getUuid())) {
continue;
}
metrics.put(vm, backendMetrics.get(vm.getUuid()));
}
return metrics;
}
private List<Backup.RestorePoint> listRestorePoints(VirtualMachine vm) {
String backupName = getGuestBackupName(vm.getInstanceName(), vm.getUuid());
return getClient(vm.getDataCenterId()).listRestorePoints(backupName, vm.getInstanceName());
}
@Override
public void syncBackups(VirtualMachine vm, Backup.Metric metric) {
List<Backup.RestorePoint> restorePoints = listRestorePoints(vm);
if (restorePoints == null || restorePoints.isEmpty()) {
return;
}
Transaction.execute(new TransactionCallbackNoReturn() {
@Override
public void doInTransactionWithoutResult(TransactionStatus status) {
final List<Backup> backupsInDb = backupDao.listByVmId(null, vm.getId());
final List<Long> removeList = backupsInDb.stream().map(InternalIdentity::getId).collect(Collectors.toList());
for (final Backup.RestorePoint restorePoint : restorePoints) {
boolean backupExists = false;
for (final Backup backup : backupsInDb) {
if (restorePoint.getId().equals(backup.getExternalId())) {
backupExists = true;
removeList.remove(backup.getId());
if (metric != null) {
((BackupVO) backup).setSize(metric.getBackupSize());
((BackupVO) backup).setProtectedSize(metric.getDataSize());
backupDao.update(backup.getId(), ((BackupVO) backup));
}
break;
}
}
if (backupExists) {
continue;
}
BackupVO backup = new BackupVO();
backup.setVmId(vm.getId());
backup.setExternalId(restorePoint.getId());
backup.setType(restorePoint.getType());
backup.setDate(restorePoint.getCreated());
backup.setStatus(Backup.Status.BackedUp);
if (metric != null) {
backup.setSize(metric.getBackupSize());
backup.setProtectedSize(metric.getDataSize());
}
backup.setBackupOfferingId(vm.getBackupOfferingId());
backup.setAccountId(vm.getAccountId());
backup.setDomainId(vm.getDomainId());
backup.setZoneId(vm.getDataCenterId());
backupDao.persist(backup);
}
for (final Long backupIdToRemove : removeList) {
backupDao.remove(backupIdToRemove);
}
}
});
}
@Override
public String getConfigComponentName() {
return BackupService.class.getSimpleName();
}
@Override
public ConfigKey<?>[] getConfigKeys() {
return new ConfigKey[]{
VeeamUrl,
VeeamUsername,
VeeamPassword,
VeeamValidateSSLSecurity,
VeeamApiRequestTimeout
};
}
@Override
public String getName() {
return "veeam";
}
@Override
public String getDescription() {
return "Veeam Backup Plugin";
}
}

View File

@ -0,0 +1,78 @@
// 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.veeam;
import java.util.Date;
import org.apache.cloudstack.backup.BackupOffering;
public class VeeamBackupOffering implements BackupOffering {
private String name;
private String uid;
public VeeamBackupOffering(String name, String uid) {
this.name = name;
this.uid = uid;
}
@Override
public String getExternalId() {
return uid;
}
@Override
public String getName() {
return name;
}
@Override
public String getDescription() {
return "Veeam Backup Offering (Job)";
}
@Override
public long getZoneId() {
return -1;
}
@Override
public boolean isUserDrivenBackupAllowed() {
return false;
}
@Override
public String getProvider() {
return "veeam";
}
@Override
public Date getCreated() {
return null;
}
@Override
public String getUuid() {
return uid;
}
@Override
public long getId() {
return -1;
}
}

View File

@ -0,0 +1,654 @@
// 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.veeam;
import static org.apache.cloudstack.backup.VeeamBackupProvider.BACKUP_IDENTIFIER;
import java.io.IOException;
import java.net.SocketTimeoutException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.StringJoiner;
import java.util.UUID;
import javax.net.ssl.SSLContext;
import javax.net.ssl.X509TrustManager;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.backup.Backup;
import org.apache.cloudstack.backup.BackupOffering;
import org.apache.cloudstack.backup.veeam.api.BackupJobCloneInfo;
import org.apache.cloudstack.backup.veeam.api.CreateObjectInJobSpec;
import org.apache.cloudstack.backup.veeam.api.EntityReferences;
import org.apache.cloudstack.backup.veeam.api.HierarchyItem;
import org.apache.cloudstack.backup.veeam.api.HierarchyItems;
import org.apache.cloudstack.backup.veeam.api.Job;
import org.apache.cloudstack.backup.veeam.api.JobCloneSpec;
import org.apache.cloudstack.backup.veeam.api.Link;
import org.apache.cloudstack.backup.veeam.api.ObjectInJob;
import org.apache.cloudstack.backup.veeam.api.ObjectsInJob;
import org.apache.cloudstack.backup.veeam.api.Ref;
import org.apache.cloudstack.backup.veeam.api.RestoreSession;
import org.apache.cloudstack.backup.veeam.api.Task;
import org.apache.cloudstack.utils.security.SSLUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.http.HttpHeaders;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpDelete;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ConnectTimeoutException;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.log4j.Logger;
import com.cloud.utils.Pair;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.utils.nio.TrustAllManager;
import com.cloud.utils.ssh.SshHelper;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.xml.XmlMapper;
import com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator;
import com.google.common.base.Strings;
public class VeeamClient {
private static final Logger LOG = Logger.getLogger(VeeamClient.class);
private final URI apiURI;
private final HttpClient httpClient;
private static final String RESTORE_VM_SUFFIX = "CS-RSTR-";
private static final String SESSION_HEADER = "X-RestSvcSessionId";
private String veeamServerIp;
private String veeamServerUsername;
private String veeamServerPassword;
private String veeamSessionId = null;
private final int veeamServerPort = 22;
public VeeamClient(final String url, final String username, final String password, final boolean validateCertificate, final int timeout) throws URISyntaxException, NoSuchAlgorithmException, KeyManagementException {
this.apiURI = new URI(url);
final RequestConfig config = RequestConfig.custom()
.setConnectTimeout(timeout * 1000)
.setConnectionRequestTimeout(timeout * 1000)
.setSocketTimeout(timeout * 1000)
.build();
if (!validateCertificate) {
final SSLContext sslcontext = SSLUtils.getSSLContext();
sslcontext.init(null, new X509TrustManager[]{new TrustAllManager()}, new SecureRandom());
final SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext, NoopHostnameVerifier.INSTANCE);
this.httpClient = HttpClientBuilder.create()
.setDefaultRequestConfig(config)
.setSSLSocketFactory(factory)
.build();
} else {
this.httpClient = HttpClientBuilder.create()
.setDefaultRequestConfig(config)
.build();
}
authenticate(username, password);
setVeeamSshCredentials(this.apiURI.getHost(), username, password);
}
protected void setVeeamSshCredentials(String hostIp, String username, String password) {
this.veeamServerIp = hostIp;
this.veeamServerUsername = username;
this.veeamServerPassword = password;
}
private void authenticate(final String username, final String password) {
// https://helpcenter.veeam.com/docs/backup/rest/http_authentication.html?ver=95u4
final HttpPost request = new HttpPost(apiURI.toString() + "/sessionMngr/?v=v1_4");
request.setHeader(HttpHeaders.AUTHORIZATION, "Basic " + Base64.getEncoder().encodeToString((username + ":" + password).getBytes()));
try {
final HttpResponse response = httpClient.execute(request);
checkAuthFailure(response);
veeamSessionId = response.getFirstHeader(SESSION_HEADER).getValue();
if (Strings.isNullOrEmpty(veeamSessionId)) {
throw new CloudRuntimeException("Veeam Session ID is not available to perform API requests");
}
if (response.getStatusLine().getStatusCode() != HttpStatus.SC_CREATED) {
throw new CloudRuntimeException("Failed to create and authenticate Veeam API client, please check the settings.");
}
} catch (final IOException e) {
throw new CloudRuntimeException("Failed to authenticate Veeam API service due to:" + e.getMessage());
}
}
private void checkAuthFailure(final HttpResponse response) {
if (response != null && response.getStatusLine().getStatusCode() == HttpStatus.SC_UNAUTHORIZED) {
throw new ServerApiException(ApiErrorCode.UNAUTHORIZED, "Veeam B&R API call unauthorized, please ask your administrator to fix integration issues.");
}
}
private void checkResponseOK(final HttpResponse response) {
if (response.getStatusLine().getStatusCode() == HttpStatus.SC_NO_CONTENT) {
LOG.debug("Requested Veeam resource does not exist");
return;
}
if (!(response.getStatusLine().getStatusCode() == HttpStatus.SC_OK ||
response.getStatusLine().getStatusCode() == HttpStatus.SC_ACCEPTED) &&
response.getStatusLine().getStatusCode() != HttpStatus.SC_NO_CONTENT) {
LOG.debug("HTTP request failed, status code is " + response.getStatusLine().getStatusCode() + ", response is: " + response.toString());
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Got invalid API status code returned by the Veeam server");
}
}
private void checkResponseTimeOut(final Exception e) {
if (e instanceof ConnectTimeoutException || e instanceof SocketTimeoutException) {
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, "Veeam API operation timed out, please try again.");
}
}
private HttpResponse get(final String path) throws IOException {
final HttpGet request = new HttpGet(apiURI.toString() + path);
request.setHeader(SESSION_HEADER, veeamSessionId);
final HttpResponse response = httpClient.execute(request);
checkAuthFailure(response);
return response;
}
private HttpResponse post(final String path, final Object obj) throws IOException {
String xml = null;
if (obj != null) {
XmlMapper xmlMapper = new XmlMapper();
xml = xmlMapper.writer()
.with(ToXmlGenerator.Feature.WRITE_XML_DECLARATION)
.writeValueAsString(obj);
// Remove invalid/empty xmlns
xml = xml.replace(" xmlns=\"\"", "");
}
final HttpPost request = new HttpPost(apiURI.toString() + path);
request.setHeader(SESSION_HEADER, veeamSessionId);
request.setHeader("Content-type", "application/xml");
if (StringUtils.isNotBlank(xml)) {
request.setEntity(new StringEntity(xml));
}
final HttpResponse response = httpClient.execute(request);
checkAuthFailure(response);
return response;
}
private HttpResponse delete(final String path) throws IOException {
final HttpDelete request = new HttpDelete(apiURI.toString() + path);
request.setHeader(SESSION_HEADER, veeamSessionId);
final HttpResponse response = httpClient.execute(request);
checkAuthFailure(response);
return response;
}
///////////////////////////////////////////////////////////////////
//////////////// Private Veeam Helper Methods /////////////////////
///////////////////////////////////////////////////////////////////
private String findDCHierarchy(final String vmwareDcName) {
LOG.debug("Trying to find hierarchy ID for vmware datacenter: " + vmwareDcName);
try {
final HttpResponse response = get("/hierarchyRoots");
checkResponseOK(response);
final ObjectMapper objectMapper = new XmlMapper();
final EntityReferences references = objectMapper.readValue(response.getEntity().getContent(), EntityReferences.class);
for (final Ref ref : references.getRefs()) {
if (ref.getName().equals(vmwareDcName) && ref.getType().equals("HierarchyRootReference")) {
return ref.getUid();
}
}
} catch (final IOException e) {
LOG.error("Failed to list Veeam jobs due to:", e);
checkResponseTimeOut(e);
}
throw new CloudRuntimeException("Failed to find hierarchy reference for VMware datacenter " + vmwareDcName + " in Veeam, please ask administrator to check Veeam B&R manager configuration");
}
private String lookupVM(final String hierarchyId, final String vmName) {
LOG.debug("Trying to lookup VM from veeam hierarchy:" + hierarchyId + " for vm name:" + vmName);
try {
final HttpResponse response = get(String.format("/lookup?host=%s&type=Vm&name=%s", hierarchyId, vmName));
checkResponseOK(response);
final ObjectMapper objectMapper = new XmlMapper();
final HierarchyItems items = objectMapper.readValue(response.getEntity().getContent(), HierarchyItems.class);
if (items == null || items.getItems() == null || items.getItems().isEmpty()) {
throw new CloudRuntimeException("Could not find VM " + vmName + " in Veeam, please ask administrator to check Veeam B&R manager");
}
for (final HierarchyItem item : items.getItems()) {
if (item.getObjectName().equals(vmName) && item.getObjectType().equals("Vm")) {
return item.getObjectRef();
}
}
} catch (final IOException e) {
LOG.error("Failed to list Veeam jobs due to:", e);
checkResponseTimeOut(e);
}
throw new CloudRuntimeException("Failed to lookup VM " + vmName + " in Veeam, please ask administrator to check Veeam B&R manager configuration");
}
private Task parseTaskResponse(HttpResponse response) throws IOException {
checkResponseOK(response);
final ObjectMapper objectMapper = new XmlMapper();
return objectMapper.readValue(response.getEntity().getContent(), Task.class);
}
private RestoreSession parseRestoreSessionResponse(HttpResponse response) throws IOException {
checkResponseOK(response);
final ObjectMapper objectMapper = new XmlMapper();
return objectMapper.readValue(response.getEntity().getContent(), RestoreSession.class);
}
private boolean checkTaskStatus(final HttpResponse response) throws IOException {
final Task task = parseTaskResponse(response);
for (int i = 0; i < 120; i++) {
final HttpResponse taskResponse = get("/tasks/" + task.getTaskId());
final Task polledTask = parseTaskResponse(taskResponse);
if (polledTask.getState().equals("Finished")) {
final HttpResponse taskDeleteResponse = delete("/tasks/" + task.getTaskId());
if (taskDeleteResponse.getStatusLine().getStatusCode() != HttpStatus.SC_NO_CONTENT) {
LOG.warn("Operation failed for veeam task id=" + task.getTaskId());
}
if (polledTask.getResult().getSuccess().equals("true")) {
Pair<String, String> pair = getRelatedLinkPair(polledTask.getLink());
if (pair != null) {
String url = pair.first();
String type = pair.second();
String path = url.replace(apiURI.toString(), "");
if (type.equals("RestoreSession")) {
for (int j = 0; j < 120; j++) {
HttpResponse relatedResponse = get(path);
RestoreSession session = parseRestoreSessionResponse(relatedResponse);
if (session.getResult().equals("Success")) {
return true;
}
try {
Thread.sleep(5000);
} catch (InterruptedException ignored) {
}
}
throw new CloudRuntimeException("Related job type: " + type + " was not successful");
}
}
return true;
}
throw new CloudRuntimeException("Failed to assign VM to backup offering due to: " + polledTask.getResult().getMessage());
}
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
LOG.debug("Failed to sleep while polling for Veeam task status due to: ", e);
}
}
return false;
}
private Pair<String, String> getRelatedLinkPair(List<Link> links) {
for (Link link : links) {
if (link.getRel().equals("Related")) {
return new Pair<>(link.getHref(), link.getType());
}
}
return null;
}
////////////////////////////////////////////////////////
//////////////// Public Veeam APIs /////////////////////
////////////////////////////////////////////////////////
public Ref listBackupRepository(final String backupServerId) {
LOG.debug("Trying to list backup repository for backup server id: " + backupServerId);
try {
final HttpResponse response = get(String.format("/backupServers/%s/repositories", backupServerId));
checkResponseOK(response);
final ObjectMapper objectMapper = new XmlMapper();
final EntityReferences references = objectMapper.readValue(response.getEntity().getContent(), EntityReferences.class);
for (final Ref ref : references.getRefs()) {
if (ref.getType().equals("RepositoryReference")) {
return ref;
}
}
} catch (final IOException e) {
LOG.error("Failed to list Veeam jobs due to:", e);
checkResponseTimeOut(e);
}
return null;
}
public void listAllBackups() {
LOG.debug("Trying to list Veeam backups");
try {
final HttpResponse response = get("/backups");
checkResponseOK(response);
final ObjectMapper objectMapper = new XmlMapper();
final EntityReferences entityReferences = objectMapper.readValue(response.getEntity().getContent(), EntityReferences.class);
for (final Ref ref : entityReferences.getRefs()) {
LOG.debug("Veeam Backup found, name: " + ref.getName() + ", uid: " + ref.getUid() + ", type: " + ref.getType());
}
} catch (final IOException e) {
LOG.error("Failed to list Veeam backups due to:", e);
checkResponseTimeOut(e);
}
}
public List<BackupOffering> listJobs() {
LOG.debug("Trying to list backup policies that are Veeam jobs");
try {
final HttpResponse response = get("/jobs");
checkResponseOK(response);
final ObjectMapper objectMapper = new XmlMapper();
final EntityReferences entityReferences = objectMapper.readValue(response.getEntity().getContent(), EntityReferences.class);
final List<BackupOffering> policies = new ArrayList<>();
if (entityReferences == null || entityReferences.getRefs() == null) {
return policies;
}
for (final Ref ref : entityReferences.getRefs()) {
policies.add(new VeeamBackupOffering(ref.getName(), ref.getUid()));
}
return policies;
} catch (final IOException e) {
LOG.error("Failed to list Veeam jobs due to:", e);
checkResponseTimeOut(e);
}
return new ArrayList<>();
}
public Job listJob(final String jobId) {
LOG.debug("Trying to list veeam job id: " + jobId);
try {
final HttpResponse response = get(String.format("/jobs/%s?format=Entity",
jobId.replace("urn:veeam:Job:", "")));
checkResponseOK(response);
final ObjectMapper objectMapper = new XmlMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
return objectMapper.readValue(response.getEntity().getContent(), Job.class);
} catch (final IOException e) {
LOG.error("Failed to list Veeam jobs due to:", e);
checkResponseTimeOut(e);
} catch (final ServerApiException e) {
LOG.error(e);
}
return null;
}
public boolean toggleJobSchedule(final String jobId) {
LOG.debug("Trying to toggle schedule for Veeam job: " + jobId);
try {
final HttpResponse response = post(String.format("/jobs/%s?action=toggleScheduleEnabled", jobId), null);
return checkTaskStatus(response);
} catch (final IOException e) {
LOG.error("Failed to toggle Veeam job schedule due to:", e);
checkResponseTimeOut(e);
}
return false;
}
public boolean startBackupJob(final String jobId) {
LOG.debug("Trying to start ad-hoc backup for Veeam job: " + jobId);
try {
final HttpResponse response = post(String.format("/jobs/%s?action=start", jobId), null);
return checkTaskStatus(response);
} catch (final IOException e) {
LOG.error("Failed to list Veeam jobs due to:", e);
checkResponseTimeOut(e);
}
return false;
}
public boolean cloneVeeamJob(final Job parentJob, final String clonedJobName) {
LOG.debug("Trying to clone veeam job: " + parentJob.getUid() + " with backup uuid: " + clonedJobName);
try {
final Ref repositoryRef = listBackupRepository(parentJob.getBackupServerId());
final BackupJobCloneInfo cloneInfo = new BackupJobCloneInfo();
cloneInfo.setJobName(clonedJobName);
cloneInfo.setFolderName(clonedJobName);
cloneInfo.setRepositoryUid(repositoryRef.getUid());
final JobCloneSpec cloneSpec = new JobCloneSpec(cloneInfo);
final HttpResponse response = post(String.format("/jobs/%s?action=clone", parentJob.getId()), cloneSpec);
return checkTaskStatus(response);
} catch (final Exception e) {
LOG.warn("Exception caught while trying to clone Veeam job:", e);
}
return false;
}
public boolean addVMToVeeamJob(final String jobId, final String vmwareInstanceName, final String vmwareDcName) {
LOG.debug("Trying to add VM to backup offering that is Veeam job: " + jobId);
try {
final String heirarchyId = findDCHierarchy(vmwareDcName);
final String veeamVmRefId = lookupVM(heirarchyId, vmwareInstanceName);
final CreateObjectInJobSpec vmToBackupJob = new CreateObjectInJobSpec();
vmToBackupJob.setObjName(vmwareInstanceName);
vmToBackupJob.setObjRef(veeamVmRefId);
final HttpResponse response = post(String.format("/jobs/%s/includes", jobId), vmToBackupJob);
return checkTaskStatus(response);
} catch (final IOException e) {
LOG.error("Failed to add VM to Veeam job due to:", e);
checkResponseTimeOut(e);
}
throw new CloudRuntimeException("Failed to add VM to backup offering likely due to timeout, please check Veeam tasks");
}
public boolean removeVMFromVeeamJob(final String jobId, final String vmwareInstanceName, final String vmwareDcName) {
LOG.debug("Trying to remove VM from backup offering that is a Veeam job: " + jobId);
try {
final String hierarchyId = findDCHierarchy(vmwareDcName);
final String veeamVmRefId = lookupVM(hierarchyId, vmwareInstanceName);
final HttpResponse response = get(String.format("/jobs/%s/includes", jobId));
checkResponseOK(response);
final ObjectMapper objectMapper = new XmlMapper();
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
final ObjectsInJob jobObjects = objectMapper.readValue(response.getEntity().getContent(), ObjectsInJob.class);
if (jobObjects == null || jobObjects.getObjects() == null) {
LOG.warn("No objects found in the Veeam job " + jobId);
return false;
}
for (final ObjectInJob jobObject : jobObjects.getObjects()) {
if (jobObject.getName().equals(vmwareInstanceName) && jobObject.getHierarchyObjRef().equals(veeamVmRefId)) {
final HttpResponse deleteResponse = delete(String.format("/jobs/%s/includes/%s", jobId, jobObject.getObjectInJobId()));
return checkTaskStatus(deleteResponse);
}
}
LOG.warn(vmwareInstanceName + " VM was not found to be attached to Veaam job (backup offering): " + jobId);
return false;
} catch (final IOException e) {
LOG.error("Failed to list Veeam jobs due to:", e);
checkResponseTimeOut(e);
}
return false;
}
public boolean restoreFullVM(final String vmwareInstanceName, final String restorePointId) {
LOG.debug("Trying to restore full VM: " + vmwareInstanceName + " from backup");
try {
final HttpResponse response = post(String.format("/vmRestorePoints/%s?action=restore", restorePointId), null);
return checkTaskStatus(response);
} catch (final IOException e) {
LOG.error("Failed to restore full VM due to: ", e);
checkResponseTimeOut(e);
}
throw new CloudRuntimeException("Failed to restore full VM from backup");
}
/////////////////////////////////////////////////////////////////
//////////////// Public Veeam PS based APIs /////////////////////
/////////////////////////////////////////////////////////////////
/**
* Generate a single command to be passed through SSH
*/
protected String transformPowerShellCommandList(List<String> cmds) {
StringJoiner joiner = new StringJoiner(";");
joiner.add("PowerShell Add-PSSnapin VeeamPSSnapin");
for (String cmd : cmds) {
joiner.add(cmd);
}
return joiner.toString();
}
/**
* Execute a list of commands in a single call on PowerShell through SSH
*/
protected Pair<Boolean, String> executePowerShellCommands(List<String> cmds) {
try {
Pair<Boolean, String> pairResult = SshHelper.sshExecute(veeamServerIp, veeamServerPort,
veeamServerUsername, null, veeamServerPassword,
transformPowerShellCommandList(cmds),
120000, 120000, 3600000);
return pairResult;
} catch (Exception e) {
throw new CloudRuntimeException("Error while executing PowerShell commands due to: " + e.getMessage());
}
}
public boolean setJobSchedule(final String jobName) {
Pair<Boolean, String> result = executePowerShellCommands(Arrays.asList(
String.format("$job = Get-VBRJob -Name \"%s\"", jobName),
"if ($job) { Set-VBRJobSchedule -Job $job -Daily -At \"11:00\" -DailyKind Weekdays }"
));
return result.first() && !result.second().isEmpty() && !result.second().contains("Failed to delete");
}
public boolean deleteJobAndBackup(final String jobName) {
Pair<Boolean, String> result = executePowerShellCommands(Arrays.asList(
String.format("$job = Get-VBRJob -Name \"%s\"", jobName),
"if ($job) { Remove-VBRJob -Job $job -Confirm:$false }",
String.format("$backup = Get-VBRBackup -Name \"%s\"", jobName),
"if ($backup) { Remove-VBRBackup -Backup $backup -FromDisk -Confirm:$false }",
"$repo = Get-VBRBackupRepository",
"Sync-VBRBackupRepository -Repository $repo"
));
return result.first() && !result.second().contains("Failed to delete");
}
public Map<String, Backup.Metric> getBackupMetrics() {
final String separator = "=====";
final List<String> cmds = Arrays.asList(
"$backups = Get-VBRBackup",
"foreach ($backup in $backups) {" +
"$backup.JobName;" +
"$storageGroups = $backup.GetStorageGroups();" +
"foreach ($group in $storageGroups) {" +
"$usedSize = 0;" +
"$dataSize = 0;" +
"$sizePerStorage = $group.GetStorages().Stats.BackupSize;" +
"$dataPerStorage = $group.GetStorages().Stats.DataSize;" +
"foreach ($size in $sizePerStorage) {" +
"$usedSize += $size;" +
"}" +
"foreach ($size in $dataPerStorage) {" +
"$dataSize += $size;" +
"}" +
"$usedSize;" +
"$dataSize;" +
"}" +
"echo \"" + separator + "\"" +
"}"
);
Pair<Boolean, String> response = executePowerShellCommands(cmds);
final Map<String, Backup.Metric> sizes = new HashMap<>();
for (final String block : response.second().split(separator + "\r\n")) {
final String[] parts = block.split("\r\n");
if (parts.length != 3) {
continue;
}
final String backupName = parts[0];
if (backupName != null && backupName.contains(BACKUP_IDENTIFIER)) {
final String[] names = backupName.split(BACKUP_IDENTIFIER);
sizes.put(names[names.length - 1], new Backup.Metric(Long.valueOf(parts[1]), Long.valueOf(parts[2])));
}
}
return sizes;
}
private Backup.RestorePoint getRestorePointFromBlock(String[] parts) {
String id = null;
String created = null;
String type = null;
for (String part : parts) {
if (part.matches("Id(\\s)+:(.)*")) {
String[] split = part.split(":");
id = split[1].trim();
} else if (part.matches("CreationTime(\\s)+:(.)*")) {
String [] split = part.split(":", 2);
created = split[1].trim();
} else if (part.matches("Type(\\s)+:(.)*")) {
String [] split = part.split(":");
type = split[1].trim();
}
}
return new Backup.RestorePoint(id, created, type);
}
public List<Backup.RestorePoint> listRestorePoints(String backupName, String vmInternalName) {
final List<String> cmds = Arrays.asList(
String.format("$backup = Get-VBRBackup -Name \"%s\"", backupName),
String.format("if ($backup) { (Get-VBRRestorePoint -Backup:$backup -Name \"%s\" ^| Where-Object {$_.IsConsistent -eq $true}) }", vmInternalName)
);
Pair<Boolean, String> response = executePowerShellCommands(cmds);
final List<Backup.RestorePoint> restorePoints = new ArrayList<>();
if (response == null || !response.first()) {
LOG.debug("Veeam restore point listing failed due to: " + (response != null ? response.second() : "no powershell output returned"));
return restorePoints;
}
for (final String block : response.second().split("\r\n\r\n")) {
if (block.isEmpty()) {
continue;
}
final String[] parts = block.split("\r\n");
restorePoints.add(getRestorePointFromBlock(parts));
}
return restorePoints;
}
public Pair<Boolean, String> restoreVMToDifferentLocation(String restorePointId, String hostIp, String dataStoreUuid) {
final String restoreLocation = RESTORE_VM_SUFFIX + UUID.randomUUID().toString();
final String datastoreId = dataStoreUuid.replace("-","");
final List<String> cmds = Arrays.asList(
"$points = Get-VBRRestorePoint",
String.format("foreach($point in $points) { if ($point.Id -eq '%s') { break; } }", restorePointId),
String.format("$server = Get-VBRServer -Name \"%s\"", hostIp),
String.format("$ds = Find-VBRViDatastore -Server:$server -Name \"%s\"", datastoreId),
String.format("$job = Start-VBRRestoreVM -RestorePoint:$point -Server:$server -Datastore:$ds -VMName \"%s\" -RunAsync", restoreLocation),
"while (-not (Get-VBRRestoreSession -Id $job.Id).IsCompleted) { Start-Sleep -Seconds 10 }"
);
Pair<Boolean, String> result = executePowerShellCommands(cmds);
if (result == null || !result.first()) {
throw new CloudRuntimeException("Failed to restore VM to location " + restoreLocation);
}
return new Pair<>(result.first(), restoreLocation);
}
}

View File

@ -0,0 +1,28 @@
// 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.veeam;
import java.util.List;
public interface VeeamObject {
String getUuid();
String getName();
String getHref();
String getType();
List<VeeamObject> getLinks();
}

View File

@ -0,0 +1,58 @@
// 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.veeam.api;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JacksonXmlRootElement(localName = "BackupJobCloneInfo")
public class BackupJobCloneInfo {
@JacksonXmlProperty(localName = "JobName")
private String jobName;
@JacksonXmlProperty(localName = "FolderName")
private String folderName;
@JacksonXmlProperty(localName = "RepositoryUid")
private String repositoryUid;
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
public String getFolderName() {
return folderName;
}
public void setFolderName(String folderName) {
this.folderName = folderName;
}
public String getRepositoryUid() {
return repositoryUid;
}
public void setRepositoryUid(String repositoryUid) {
this.repositoryUid = repositoryUid;
}
}

View File

@ -0,0 +1,46 @@
// 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.veeam.api;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JacksonXmlRootElement(localName = "CreateObjectInJobSpec", namespace = "http://www.veeam.com/ent/v1.0")
public class CreateObjectInJobSpec {
@JacksonXmlProperty(localName = "HierarchyObjRef")
String objRef;
@JacksonXmlProperty(localName = "HierarchyObjName")
String objName;
public String getObjRef() {
return objRef;
}
public void setObjRef(String objRef) {
this.objRef = objRef;
}
public String getObjName() {
return objName;
}
public void setObjName(String objName) {
this.objName = objName;
}
}

View File

@ -0,0 +1,39 @@
// 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.veeam.api;
import java.util.List;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JacksonXmlRootElement(localName = "EntityReferences")
public class EntityReferences {
@JacksonXmlProperty(localName = "Ref")
@JacksonXmlElementWrapper(localName = "Ref", useWrapping = false)
private List<Ref> refs;
public List<Ref> getRefs() {
return refs;
}
public void setRefs(List<Ref> refs) {
this.refs = refs;
}
}

View File

@ -0,0 +1,68 @@
// 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.veeam.api;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JacksonXmlRootElement(localName = "HierarchyItem")
public class HierarchyItem {
@JacksonXmlProperty(localName = "Type", isAttribute = true)
private String type;
@JacksonXmlProperty(localName = "ObjectRef")
private String objectRef;
@JacksonXmlProperty(localName = "ObjectType")
private String objectType;
@JacksonXmlProperty(localName = "ObjectName")
private String objectName;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getObjectRef() {
return objectRef;
}
public void setObjectRef(String objectRef) {
this.objectRef = objectRef;
}
public String getObjectType() {
return objectType;
}
public void setObjectType(String objectType) {
this.objectType = objectType;
}
public String getObjectName() {
return objectName;
}
public void setObjectName(String objectName) {
this.objectName = objectName;
}
}

View File

@ -0,0 +1,39 @@
// 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.veeam.api;
import java.util.List;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JacksonXmlRootElement(localName = "HierarchyItems")
public class HierarchyItems {
@JacksonXmlProperty(localName = "HierarchyItem")
@JacksonXmlElementWrapper(localName = "HierarchyItem", useWrapping = false)
private List<HierarchyItem> items;
public List<HierarchyItem> getItems() {
return items;
}
public void setItems(List<HierarchyItem> items) {
this.items = items;
}
}

View File

@ -0,0 +1,163 @@
// 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.veeam.api;
import java.util.List;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JacksonXmlRootElement(localName = "Job")
public class Job {
@JacksonXmlProperty(localName = "Name", isAttribute = true)
private String name;
@JacksonXmlProperty(localName = "Href", isAttribute = true)
private String href;
@JacksonXmlProperty(localName = "Type", isAttribute = true)
private String type;
@JacksonXmlProperty(localName = "UID", isAttribute = true)
private String uid;
@JacksonXmlProperty(localName = "Link")
@JacksonXmlElementWrapper(localName = "Links")
private List<Link> link;
@JacksonXmlProperty(localName = "Platform")
private String platform;
@JacksonXmlProperty(localName = "Description")
private String description;
@JacksonXmlProperty(localName = "NextRun")
private String nextRun;
@JacksonXmlProperty(localName = "JobType")
private String jobType;
@JacksonXmlProperty(localName = "ScheduleEnabled")
private Boolean scheduleEnabled;
@JacksonXmlProperty(localName = "ScheduleConfigured")
private Boolean scheduleConfigured;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getUid() {
return uid;
}
public String getId() {
return uid.replace("urn:veeam:Job:", "");
}
public void setUid(String uid) {
this.uid = uid;
}
public List<Link> getLink() {
return link;
}
public void setLink(List<Link> link) {
this.link = link;
}
public String getPlatform() {
return platform;
}
public void setPlatform(String platform) {
this.platform = platform;
}
public String getDescription() {
return description;
}
public void setDescription(String description) {
this.description = description;
}
public String getNextRun() {
return nextRun;
}
public void setNextRun(String nextRun) {
this.nextRun = nextRun;
}
public String getJobType() {
return jobType;
}
public void setJobType(String jobType) {
this.jobType = jobType;
}
public String getBackupServerId() {
for (final Link l : link) {
if (l.getType().equals("BackupServerReference")) {
return "" + l.getHref().split("backupServers/")[1];
}
}
return null;
}
public Boolean getScheduleEnabled() {
return scheduleEnabled;
}
public void setScheduleEnabled(String scheduleEnabled) {
this.scheduleEnabled = Boolean.valueOf(scheduleEnabled);
}
public Boolean getScheduleConfigured() {
return scheduleConfigured;
}
public void setScheduleConfigured(String scheduleConfigured) {
this.scheduleConfigured = Boolean.valueOf(scheduleConfigured);
}
}

View File

@ -0,0 +1,41 @@
// 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.veeam.api;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JacksonXmlRootElement(localName = "JobCloneSpec", namespace = "http://www.veeam.com/ent/v1.0")
public class JobCloneSpec {
@JacksonXmlProperty(localName = "BackupJobCloneInfo")
@JacksonXmlElementWrapper(localName = "BackupJobCloneInfo", useWrapping = false)
BackupJobCloneInfo jobCloneInfo;
public JobCloneSpec(final BackupJobCloneInfo jobCloneInfo) {
this.jobCloneInfo = jobCloneInfo;
}
public BackupJobCloneInfo getJobCloneInfo() {
return jobCloneInfo;
}
public void setJobCloneInfo(BackupJobCloneInfo jobCloneInfo) {
this.jobCloneInfo = jobCloneInfo;
}
}

View File

@ -0,0 +1,69 @@
// 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.veeam.api;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JacksonXmlRootElement(localName = "Link")
public class Link {
@JacksonXmlProperty(localName = "Name", isAttribute = true)
private String name;
@JacksonXmlProperty(localName = "Href", isAttribute = true)
private String href;
@JacksonXmlProperty(localName = "Type", isAttribute = true)
private String type;
@JacksonXmlProperty(localName = "Rel", isAttribute = true)
private String rel;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getRel() {
return rel;
}
public void setRel(String rel) {
this.rel = rel;
}
}

View File

@ -0,0 +1,94 @@
// 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.veeam.api;
import java.util.List;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JacksonXmlRootElement(localName = "ObjectInJob")
public class ObjectInJob {
@JacksonXmlProperty(localName = "Href", isAttribute = true)
private String href;
@JacksonXmlProperty(localName = "Type", isAttribute = true)
private String type;
@JacksonXmlProperty(localName = "Link")
@JacksonXmlElementWrapper(localName = "Links")
private List<Link> link;
@JacksonXmlProperty(localName = "ObjectInJobId", isAttribute = true)
private String objectInJobId;
@JacksonXmlProperty(localName = "HierarchyObjRef", isAttribute = true)
private String hierarchyObjRef;
@JacksonXmlProperty(localName = "Name", isAttribute = true)
private String name;
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public List<Link> getLink() {
return link;
}
public void setLink(List<Link> link) {
this.link = link;
}
public String getObjectInJobId() {
return objectInJobId;
}
public void setObjectInJobId(String objectInJobId) {
this.objectInJobId = objectInJobId;
}
public String getHierarchyObjRef() {
return hierarchyObjRef;
}
public void setHierarchyObjRef(String hierarchyObjRef) {
this.hierarchyObjRef = hierarchyObjRef;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

View File

@ -0,0 +1,39 @@
// 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.veeam.api;
import java.util.List;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JacksonXmlRootElement(localName = "ObjectsInJob")
public class ObjectsInJob {
@JacksonXmlProperty(localName = "ObjectInJob")
@JacksonXmlElementWrapper(localName = "ObjectInJob", useWrapping = false)
private List<ObjectInJob> objects;
public List<ObjectInJob> getObjects() {
return objects;
}
public void setObjects(List<ObjectInJob> objects) {
this.objects = objects;
}
}

View File

@ -0,0 +1,83 @@
// 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.veeam.api;
import java.util.List;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JacksonXmlRootElement(localName = "Ref")
public class Ref {
@JacksonXmlProperty(localName = "UID", isAttribute = true)
private String uid;
@JacksonXmlProperty(localName = "Name", isAttribute = true)
private String name;
@JacksonXmlProperty(localName = "Href", isAttribute = true)
private String href;
@JacksonXmlProperty(localName = "Type", isAttribute = true)
private String type;
@JacksonXmlProperty(localName = "Link")
@JacksonXmlElementWrapper(localName = "Links")
private List<Link> link;
public List<Link> getLink() {
return link;
}
public void setLink(List<Link> link) {
this.link = link;
}
public String getUid() {
return uid;
}
public void setUid(String uid) {
this.uid = uid;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
}

View File

@ -0,0 +1,120 @@
// 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.veeam.api;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
import java.util.List;
@JacksonXmlRootElement(localName = "RestoreSession")
public class RestoreSession {
@JacksonXmlProperty(localName = "Type", isAttribute = true)
private String type;
@JacksonXmlProperty(localName = "Href", isAttribute = true)
private String href;
@JacksonXmlProperty(localName = "Name", isAttribute = true)
private String name;
@JacksonXmlProperty(localName = "UID", isAttribute = true)
private String uid;
@JacksonXmlProperty(localName = "VmDisplayName", isAttribute = true)
private String vmDisplayName;
@JacksonXmlProperty(localName = "Link")
@JacksonXmlElementWrapper(localName = "Links")
private List<Link> link;
@JacksonXmlProperty(localName = "JobType")
private String jobType;
@JacksonXmlProperty(localName = "CreationTimeUTC")
private String creationTimeUTC;
@JacksonXmlProperty(localName = "EndTimeUTC")
private String endTimeUTC;
@JacksonXmlProperty(localName = "State")
private String state;
@JacksonXmlProperty(localName = "Result")
private String result;
@JacksonXmlProperty(localName = "Progress")
private String progress;
@JacksonXmlProperty(localName = "RestoredObjRef")
private String restoredObjRef;
public List<Link> getLink() {
return link;
}
public String getJobType() {
return jobType;
}
public String getState() {
return state;
}
public String getResult() {
return result;
}
public String getType() {
return type;
}
public String getHref() {
return href;
}
public String getVmDisplayName() {
return vmDisplayName;
}
public String getCreationTimeUTC() {
return creationTimeUTC;
}
public String getEndTimeUTC() {
return endTimeUTC;
}
public String getProgress() {
return progress;
}
public String getName() {
return name;
}
public String getUid() {
return uid;
}
public String getRestoredObjRef() {
return restoredObjRef;
}
}

View File

@ -0,0 +1,47 @@
// 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.veeam.api;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JacksonXmlRootElement(localName = "Result")
public class Result {
@JacksonXmlProperty(localName = "Success", isAttribute = true)
private String success;
@JacksonXmlProperty(localName = "Message")
private String message;
public String getSuccess() {
return success;
}
public void setSuccess(String success) {
this.success = success;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}

View File

@ -0,0 +1,106 @@
// 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.veeam.api;
import java.util.List;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlRootElement;
@JacksonXmlRootElement(localName = "CreateObjectInJobSpec")
public class Task {
@JacksonXmlProperty(localName = "Type", isAttribute = true)
private String type;
@JacksonXmlProperty(localName = "Href", isAttribute = true)
private String href;
@JacksonXmlProperty(localName = "Link")
@JacksonXmlElementWrapper(localName = "Links")
private List<Link> link;
@JacksonXmlProperty(localName = "TaskId")
private String taskId;
@JacksonXmlProperty(localName = "State")
private String state;
@JacksonXmlProperty(localName = "Operation")
private String operation;
@JacksonXmlProperty(localName = "Result")
@JacksonXmlElementWrapper(localName = "Result", useWrapping = false)
private Result result;
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getHref() {
return href;
}
public void setHref(String href) {
this.href = href;
}
public List<Link> getLink() {
return link;
}
public void setLink(List<Link> link) {
this.link = link;
}
public String getTaskId() {
return taskId;
}
public void setTaskId(String taskId) {
this.taskId = taskId;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public String getOperation() {
return operation;
}
public void setOperation(String operation) {
this.operation = operation;
}
public Result getResult() {
return result;
}
public void setResult(Result result) {
this.result = result;
}
}

Some files were not shown because too many files have changed in this diff Show More