Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
75 commits
Select commit Hold shift + click to select a range
f2baa68
backup: Simple NAS backup plugin for KVM
rohityadavcloud Jul 26, 2024
2604f81
cleanup and leave TODOs
rohityadavcloud Jul 26, 2024
b961a4d
cleanup, refactor; add plugin config keys
rohityadavcloud Jul 26, 2024
9a8bbbb
WIP B&R tool
rohityadavcloud Jul 26, 2024
aa90b6d
Merge remote-tracking branch 'origin/main' into kvm-backup-plugin-sha…
rohityadavcloud Jul 31, 2024
d5503e7
add cmd-answer classes
rohityadavcloud Aug 1, 2024
f3bc039
barebone take backup implementation
rohityadavcloud Aug 1, 2024
f13769d
prototype backup e2e
rohityadavcloud Aug 1, 2024
1933f9e
fix backup script
rohityadavcloud Aug 1, 2024
e066c5a
fix command execution handling
rohityadavcloud Aug 1, 2024
50e407c
implement backup delete
rohityadavcloud Aug 1, 2024
9b0be25
fix nasbackup script
rohityadavcloud Aug 1, 2024
11cbea2
fix op typo
rohityadavcloud Aug 1, 2024
18e0589
add todos
rohityadavcloud Aug 1, 2024
97ce34c
introduce backup repository concept for NAS & other backups
rohityadavcloud Aug 2, 2024
0b9db75
complete poc
rohityadavcloud Aug 2, 2024
00b22d4
fix backup script
rohityadavcloud Aug 2, 2024
7db5178
ui tweaks
rohityadavcloud Aug 2, 2024
452bc10
fix listbackups to return their original offering
rohityadavcloud Aug 2, 2024
67821d7
Merge branch 'main' of https://github.com/apache/cloudstack into kvm-…
Pearl1594 Aug 6, 2024
fe5c9d7
add APIs for management of backup repositories and backing up from lo…
Pearl1594 Aug 12, 2024
90b9981
add license
Pearl1594 Aug 12, 2024
0cf5046
support to backup stopped vms
Pearl1594 Aug 13, 2024
427d89b
license
Pearl1594 Aug 13, 2024
e38baa7
support restoring VMs
Pearl1594 Aug 15, 2024
90a45f9
add license
Pearl1594 Aug 15, 2024
119f5ac
support recover volume from backup and attach to VM
Pearl1594 Aug 19, 2024
6483284
fix issues identified during dev testing
Pearl1594 Aug 23, 2024
ed9956f
Merge remote-tracking branch 'origin/main' into kvm-backup-plugin-sha…
rohityadavcloud Aug 28, 2024
9889c44
fix list API bugs
rohityadavcloud Aug 28, 2024
123c911
remove unused import
rohityadavcloud Aug 28, 2024
0d217f5
api: restrict API to only root admin
rohityadavcloud Aug 28, 2024
5cb4f75
ui: add ability to list & delete specific backup repository
rohityadavcloud Aug 28, 2024
fc75705
fixes
rohityadavcloud Aug 28, 2024
1d7b2c0
nasbackup: implement restore backup
rohityadavcloud Aug 28, 2024
da5fe8d
fixes
rohityadavcloud Aug 28, 2024
e765ddb
fix issues
rohityadavcloud Aug 28, 2024
5c3894d
Update tools/marvin/setup.py
rohityadavcloud Aug 28, 2024
e51dedf
Update ui/src/views/AutogenView.vue
rohityadavcloud Aug 28, 2024
c27d1ca
fix pool ID issue in restored volume
rohityadavcloud Aug 29, 2024
8b6bb80
fix potential NPE
rohityadavcloud Aug 29, 2024
25dd780
Update ui/src/components/view/ListView.vue
rohityadavcloud Aug 29, 2024
a1e1980
Update server/src/main/java/org/apache/cloudstack/backup/BackupManage…
rohityadavcloud Aug 29, 2024
0dc00d1
fix unused import
shwstppr Aug 30, 2024
c09a977
Update plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm…
rohityadavcloud Aug 30, 2024
26e48cf
Update core/src/main/java/org/apache/cloudstack/backup/DeleteBackupCo…
rohityadavcloud Aug 30, 2024
958049d
remove/fix weird spacing and newline
rohityadavcloud Aug 30, 2024
5b68e9c
Merge remote-tracking branch 'origin/main' into kvm-backup-plugin-sha…
rohityadavcloud Aug 30, 2024
c50ca68
Missing import
Pearl1594 Aug 30, 2024
93cb33a
Fix created time to after the answer is recieved from the host and ad…
Pearl1594 Sep 2, 2024
1ee025e
fix lint
Pearl1594 Sep 2, 2024
8f04bec
Allow multiple backup schedules to be created
Pearl1594 Sep 2, 2024
a476a94
update setup.py file
Pearl1594 Sep 2, 2024
4764327
fix linter
Pearl1594 Sep 2, 2024
37316f3
Perform virsh attach-disk operation for running VMs when restore volu…
Pearl1594 Sep 2, 2024
f632820
fix linter
Pearl1594 Sep 2, 2024
9011353
address comments
Pearl1594 Sep 2, 2024
d3450b9
cleanup restore op from script as its done via Java - using rsync
Pearl1594 Sep 2, 2024
5bd9eac
fix unit test
Pearl1594 Sep 2, 2024
7e94bfa
1. adds backed_volumes column to the backups table to track volumes b…
Pearl1594 Sep 3, 2024
ae9634d
remove unused import
Pearl1594 Sep 3, 2024
1c28d98
Allow attaching volumes to a VM with backup offering but with No backups
Pearl1594 Sep 4, 2024
e065b4e
Prevent deletion of backup repository if it contains backups
Pearl1594 Sep 4, 2024
414943b
Prevent normal user's from seeing offering that doesnt allow user dri…
Pearl1594 Sep 4, 2024
b7d64e2
fix unit test
Pearl1594 Sep 4, 2024
fbe3c18
address comments provided - rename variable and add some defensive co…
Pearl1594 Sep 4, 2024
265466d
Merge branch 'main' into kvm-backup-plugin-shared-storage
rohityadavcloud Sep 5, 2024
7213eb2
Update schema-41910to42000.sql
rohityadavcloud Sep 5, 2024
8476fd4
Update tools/marvin/setup.py
rohityadavcloud Sep 5, 2024
ee0c5b3
Update engine/schema/src/main/resources/META-INF/db/schema-41910to420…
rohityadavcloud Sep 5, 2024
42e7319
Update engine/schema/src/main/resources/META-INF/db/schema-41910to420…
rohityadavcloud Sep 5, 2024
9bffa4d
add rsync as dependnecy for cloudstack-agent
rohityadavcloud Sep 5, 2024
11c369e
Merge remote-tracking branch 'origin/main' into kvm-backup-plugin-sha…
rohityadavcloud Sep 5, 2024
7423f5f
Merge branch 'main' into kvm-backup-plugin-shared-storage
rohityadavcloud Sep 5, 2024
9efdb57
fix db schema setup issue
rohityadavcloud Sep 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions api/src/main/java/com/cloud/vm/VirtualMachine.java
Original file line number Diff line number Diff line change
Expand Up @@ -333,6 +333,8 @@ public boolean isUsedBySystem() {
*/
Date getCreated();

Date getRemoved();

long getServiceOfferingId();

Long getBackupOfferingId();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1145,6 +1145,7 @@ public class ApiConstants {
public static final String WEBHOOK_NAME = "webhookname";

public static final String NFS_MOUNT_OPTIONS = "nfsmountopts";
public static final String MOUNT_OPTIONS = "mountopts";

public static final String SHAREDFSVM_MIN_CPU_COUNT = "sharedfsvmmincpucount";
public static final String SHAREDFSVM_MIN_RAM_SIZE = "sharedfsvmminramsize";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
import java.util.Map;
import java.util.Set;

import org.apache.cloudstack.api.response.BackupRepositoryResponse;
import org.apache.cloudstack.backup.BackupRepository;
import org.apache.cloudstack.storage.object.Bucket;
import org.apache.cloudstack.affinity.AffinityGroup;
import org.apache.cloudstack.affinity.AffinityGroupResponse;
Expand Down Expand Up @@ -554,5 +556,7 @@ List<TemplateResponse> createTemplateResponses(ResponseView view, VirtualMachine

BucketResponse createBucketResponse(Bucket bucket);

BackupRepositoryResponse createBackupRepositoryResponse(BackupRepository repository);

SharedFSResponse createSharedFSResponse(ResponseView view, SharedFS sharedFS);
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@

import javax.inject.Inject;

import com.amazonaws.util.CollectionUtils;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
Expand All @@ -27,6 +28,7 @@
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.ListResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.backup.BackupManager;
import org.apache.cloudstack.backup.BackupSchedule;
Expand All @@ -39,6 +41,9 @@
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.utils.exception.CloudRuntimeException;

import java.util.ArrayList;
import java.util.List;

@APICommand(name = "listBackupSchedule",
description = "List backup schedule of a VM",
responseObject = BackupScheduleResponse.class, since = "4.14.0",
Expand Down Expand Up @@ -74,9 +79,14 @@ public Long getVmId() {
@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);
List<BackupSchedule> schedules = backupManager.listBackupSchedule(getVmId());
ListResponse<BackupScheduleResponse> response = new ListResponse<>();
List<BackupScheduleResponse> scheduleResponses = new ArrayList<>();
if (CollectionUtils.isNullOrEmpty(schedules)) {
for (BackupSchedule schedule : schedules) {
scheduleResponses.add(_responseGenerator.createBackupScheduleResponse(schedule));
}
response.setResponses(scheduleResponses, schedules.size());
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// 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.repository;

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.BackupRepositoryResponse;
import org.apache.cloudstack.api.response.ZoneResponse;
import org.apache.cloudstack.backup.BackupRepository;
import org.apache.cloudstack.backup.BackupRepositoryService;
import org.apache.cloudstack.context.CallContext;

import javax.inject.Inject;

@APICommand(name = "addBackupRepository",
description = "Adds a backup repository to store NAS backups",
responseObject = BackupRepositoryResponse.class, since = "4.20.0",
authorized = {RoleType.Admin})
public class AddBackupRepositoryCmd extends BaseCmd {

@Inject
private BackupRepositoryService backupRepositoryService;

/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "name of the backup repository")
private String name;

@Parameter(name = ApiConstants.ADDRESS, type = CommandType.STRING, required = true, description = "address of the backup repository")
private String address;

@Parameter(name = ApiConstants.TYPE, type = CommandType.STRING, required = true, description = "type of the backup repository storage. Supported values: nfs, cephfs, cifs")
private String type;

@Parameter(name = ApiConstants.PROVIDER, type = CommandType.STRING, description = "backup repository provider")
private String provider;

@Parameter(name = ApiConstants.MOUNT_OPTIONS, type = CommandType.STRING, description = "shared storage mount options")
private String mountOptions;

@Parameter(name = ApiConstants.ZONE_ID,
type = CommandType.UUID,
entityType = ZoneResponse.class,
required = true,
description = "ID of the zone where the backup repository is to be added")
private Long zoneId;

@Parameter(name = ApiConstants.CAPACITY_BYTES, type = CommandType.LONG, description = "capacity of this backup repository")
private Long capacityBytes;


/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////

public BackupRepositoryService getBackupRepositoryService() {
return backupRepositoryService;
}

public String getName() {
return name;
}

public String getType() {
if ("cephfs".equalsIgnoreCase(type)) {
return "ceph";
}
return type.toLowerCase();
}

public String getAddress() {
return address;
}

public String getProvider() {
return provider;
}

public String getMountOptions() {
return mountOptions == null ? "" : mountOptions;
}

public Long getZoneId() {
return zoneId;
}

public Long getCapacityBytes() {
return capacityBytes;
}

/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////

@Override
public void execute() {
try {
BackupRepository result = backupRepositoryService.addBackupRepository(this);
if (result != null) {
BackupRepositoryResponse response = _responseGenerator.createBackupRepositoryResponse(result);
response.setResponseName(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add backup repository");
}
} catch (Exception ex4) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex4.getMessage());
}

}

@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
// 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.repository;

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.BackupRepositoryResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.backup.BackupRepositoryService;

import javax.inject.Inject;

@APICommand(name = "deleteBackupRepository",
description = "delete a backup repository",
responseObject = SuccessResponse.class, since = "4.20.0",
authorized = {RoleType.Admin})
public class DeleteBackupRepositoryCmd extends BaseCmd {

@Inject
BackupRepositoryService backupRepositoryService;

/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.ID,
type = CommandType.UUID,
entityType = BackupRepositoryResponse.class,
required = true,
description = "ID of the backup repository to be deleted")
private Long id;


/////////////////////////////////////////////////////
//////////////// Accessors //////////////////////////
/////////////////////////////////////////////////////

public Long getId() {
return id;
}

@Override
public void execute() {
boolean result = backupRepositoryService.deleteBackupRepository(this);
if (result) {
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete backup repository");
}
}

@Override
public long getEntityOwnerId() {
return 0;
}
}
Loading