Skip to content

Commit 554e36c

Browse files
João JandreJoaoJandre
authored andcommitted
Feature to extract files from KBOSS backups
1 parent 64178ea commit 554e36c

38 files changed

Lines changed: 2704 additions & 18 deletions

File tree

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
/*
2+
* Licensed to the Apache Software Foundation (ASF) under one
3+
* or more contributor license agreements. See the NOTICE file
4+
* distributed with this work for additional information
5+
* regarding copyright ownership. The ASF licenses this file
6+
* to you under the Apache License, Version 2.0 (the
7+
* "License"); you may not use this file except in compliance
8+
* with the License. You may obtain a copy of the License at
9+
*
10+
* http://www.apache.org/licenses/LICENSE-2.0
11+
*
12+
* Unless required by applicable law or agreed to in writing,
13+
* software distributed under the License is distributed on an
14+
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
* KIND, either express or implied. See the License for the
16+
* specific language governing permissions and limitations
17+
* under the License.
18+
*/
19+
package com.cloud.agent.api.to;
20+
21+
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
22+
import org.apache.commons.lang3.builder.ToStringStyle;
23+
24+
public class FilesystemInfoTO {
25+
private final String name;
26+
private final String filesystem;
27+
private final long size;
28+
private final long volumeId;
29+
30+
public FilesystemInfoTO(String name, String filesystem, long size, long volumeId) {
31+
this.name = name;
32+
this.filesystem = filesystem;
33+
this.size = size;
34+
this.volumeId = volumeId;
35+
}
36+
37+
public String getName() {
38+
return name;
39+
}
40+
41+
public String getFilesystem() {
42+
return filesystem;
43+
}
44+
45+
public long getSize() {
46+
return size;
47+
}
48+
49+
public long getVolumeId() {
50+
return volumeId;
51+
}
52+
53+
@Override
54+
public String toString() {
55+
return ReflectionToStringBuilder.toString(this, ToStringStyle.JSON_STYLE);
56+
}
57+
}

api/src/main/java/com/cloud/event/EventTypes.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,7 @@ public class EventTypes {
669669
public static final String EVENT_VM_BACKUP_EDIT = "BACKUP.OFFERING.EDIT";
670670
public static final String EVENT_VM_CREATE_FROM_BACKUP = "VM.CREATE.FROM.BACKUP";
671671
public static final String EVENT_SCREENSHOT_DOWNLOAD = "BACKUP.VALIDATION.SCREENSHOT.DOWNLOAD";
672+
public static final String EVENT_BACKUP_FILE_DOWNLOAD = "BACKUP.FILE.DOWNLOAD";
672673

673674
// external network device events
674675
public static final String EVENT_EXTERNAL_NVP_CONTROLLER_ADD = "PHYSICAL.NVPCONTROLLER.ADD";

api/src/main/java/com/cloud/storage/Storage.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ public static enum ImageFormat {
3636
TAR(false, false, false, "tar"),
3737
ZIP(false, false, false, "zip"),
3838
DIR(false, false, false, "dir"),
39-
PNG(false, false, false, "png");
39+
PNG(false, false, false, "png"),
40+
GZIP(false, false, false, "gz"),
41+
TARGZ(false, false, false, "tar.gz");
4042

4143
private final boolean supportThinProvisioning;
4244
private final boolean supportSparse;

api/src/main/java/org/apache/cloudstack/api/ApiArgValidator.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,4 +37,10 @@ public enum ApiArgValidator {
3737
* Validates if the parameter is a valid RFC Compliance domain name.
3838
*/
3939
RFCComplianceDomainName,
40+
41+
/**
42+
* Validates that the parameter does not match the following regex '[$|&*`\@!%'"^;<>!()]'
43+
* Some special characters are allowed, such as '/'. If you need to disallow all special characters, a new validator should be created.
44+
* */
45+
LimitedSpecialCharacters,
4046
}

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1489,6 +1489,10 @@ public class ApiConstants {
14891489
public static final String SCHEDULED = "scheduled";
14901490
public static final String SCHEDULED_DATE = "scheduleddate";
14911491
public static final String BACKUP_PROVIDER = "backupprovider";
1492+
public static final String IS_FILESYSTEM = "isfilesystem";
1493+
public static final String IS_SYMLINK = "issymlink";
1494+
public static final String BROWSABLE = "browsable";
1495+
public static final String CANONICAL_PATH = "canonicalpath";
14921496

14931497
/**
14941498
* This enum specifies IO Drivers, each option controls specific policies on I/O.
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.api.command.user.backup;
18+
19+
import com.cloud.event.EventTypes;
20+
import com.cloud.exception.InvalidParameterValueException;
21+
import com.cloud.user.Account;
22+
import org.apache.cloudstack.api.ACL;
23+
import org.apache.cloudstack.api.APICommand;
24+
import org.apache.cloudstack.api.ApiArgValidator;
25+
import org.apache.cloudstack.api.ApiConstants;
26+
import org.apache.cloudstack.api.BaseAsyncCmd;
27+
import org.apache.cloudstack.api.BaseCmd;
28+
import org.apache.cloudstack.api.Parameter;
29+
import org.apache.cloudstack.api.response.BackupResponse;
30+
import org.apache.cloudstack.api.response.ExtractResponse;
31+
import org.apache.cloudstack.api.response.VolumeResponse;
32+
import org.apache.cloudstack.backup.Backup;
33+
import org.apache.cloudstack.backup.BackupManager;
34+
35+
import javax.inject.Inject;
36+
37+
@APICommand(name = "downloadBackupFile",
38+
description = "Download a file from a backup",
39+
responseObject = ExtractResponse.class, since = "4.24.0.0")
40+
public class DownloadBackupFileCmd extends BaseAsyncCmd {
41+
42+
private static final String REGEX = "[$|&*`\\@!%'\"^;<>!()]";
43+
@Inject
44+
private BackupManager backupManager;
45+
46+
/////////////////////////////////////////////////////
47+
//////////////// API parameters /////////////////////
48+
/////////////////////////////////////////////////////
49+
50+
@ACL
51+
@Parameter(name = ApiConstants.BACKUP_ID, type = BaseCmd.CommandType.UUID, entityType = BackupResponse.class, required = true,
52+
description = "ID of the backup to download the file.")
53+
private Long backupId;
54+
55+
@ACL
56+
@Parameter(name = ApiConstants.VOLUME_ID, type = BaseCmd.CommandType.UUID, entityType = VolumeResponse.class, required = true,
57+
description = "ID of the volume. If not informed, we will return every filesystem of every volume.")
58+
private Long volumeId;
59+
60+
@Parameter(name = ApiConstants.FILESYSTEM, type = BaseCmd.CommandType.STRING, required = true,
61+
description = "Filesystem to list the files in.", validations = {ApiArgValidator.LimitedSpecialCharacters})
62+
private String filesystem;
63+
64+
@Parameter(name = ApiConstants.PATH, type = BaseCmd.CommandType.STRING, required = true,
65+
description = "Path to the file to be downloaded in the backed-up volume.", validations = {ApiArgValidator.LimitedSpecialCharacters})
66+
private String path;
67+
68+
/////////////////////////////////////////////////////
69+
/////////////////// Accessors ///////////////////////
70+
/////////////////////////////////////////////////////
71+
72+
public Long getBackupId() {
73+
return backupId;
74+
}
75+
76+
public Long getVolumeId() {
77+
return volumeId;
78+
}
79+
80+
public String getFilesystem() {
81+
return filesystem.trim();
82+
}
83+
84+
public String getPath() {
85+
return path.trim();
86+
}
87+
88+
/////////////////////////////////////////////////////
89+
/////////////// API Implementation //////////////////
90+
/////////////////////////////////////////////////////
91+
92+
@Override
93+
public String getEventType() {
94+
return EventTypes.EVENT_BACKUP_FILE_DOWNLOAD;
95+
}
96+
97+
@Override
98+
public String getEventDescription() {
99+
Backup backup = _entityMgr.findById(Backup.class, getBackupId());
100+
if (backup == null) {
101+
throw new InvalidParameterValueException(String.format("Unable to find backup with ID [%s].", getBackupId()));
102+
}
103+
return "Downloading a file from backup " + backup.getUuid();
104+
}
105+
106+
@Override
107+
public long getEntityOwnerId() {
108+
Backup backup = _entityMgr.findById(Backup.class, getBackupId());
109+
if (backup != null) {
110+
return backup.getAccountId();
111+
}
112+
113+
return Account.ACCOUNT_ID_SYSTEM;
114+
}
115+
116+
@Override
117+
public void execute() {
118+
ExtractResponse response = backupManager.downloadBackupFile(getBackupId(), getVolumeId(), getFilesystem(), getPath());
119+
120+
response.setResponseName(getCommandName());
121+
response.setObjectName(getCommandName());
122+
this.setResponseObject(response);
123+
}
124+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
package org.apache.cloudstack.api.command.user.backup;
18+
19+
import com.cloud.user.Account;
20+
import org.apache.cloudstack.api.ACL;
21+
import org.apache.cloudstack.api.APICommand;
22+
import org.apache.cloudstack.api.ApiArgValidator;
23+
import org.apache.cloudstack.api.ApiConstants;
24+
import org.apache.cloudstack.api.BaseListCmd;
25+
import org.apache.cloudstack.api.Parameter;
26+
import org.apache.cloudstack.api.response.BackupResponse;
27+
import org.apache.cloudstack.api.response.ListResponse;
28+
import org.apache.cloudstack.api.response.VolumeResponse;
29+
import org.apache.cloudstack.backup.Backup;
30+
import org.apache.cloudstack.backup.BackupManager;
31+
import org.apache.cloudstack.storage.browser.DataStoreObjectResponse;
32+
33+
import javax.inject.Inject;
34+
import java.util.List;
35+
36+
@APICommand(name = "listBackupFiles",
37+
description = "List a backup inner files",
38+
responseObject = DataStoreObjectResponse.class, since = "4.24.0.0")
39+
public class ListBackupFilesCmd extends BaseListCmd {
40+
41+
private static final String REGEX = "[$|&*`\\@!%'\"^;<>!()]";
42+
@Inject
43+
private BackupManager backupManager;
44+
45+
/////////////////////////////////////////////////////
46+
//////////////// API parameters /////////////////////
47+
/////////////////////////////////////////////////////
48+
49+
@ACL
50+
@Parameter(name = ApiConstants.BACKUP_ID, type = CommandType.UUID, entityType = BackupResponse.class, required = true,
51+
description = "ID of the backup to list the files.")
52+
private Long backupId;
53+
54+
@ACL
55+
@Parameter(name = ApiConstants.VOLUME_ID, type = CommandType.UUID, entityType = VolumeResponse.class, required = true,
56+
description = "ID of the volume.")
57+
private Long volumeId;
58+
59+
@Parameter(name = ApiConstants.FILESYSTEM, type = CommandType.STRING, required = true,
60+
description = "Filesystem to list the files in.", validations = {ApiArgValidator.LimitedSpecialCharacters})
61+
private String filesystem;
62+
63+
@Parameter(name = ApiConstants.PATH, type = CommandType.STRING, required = true,
64+
description = "Path to list files in the backed-up volume.", validations = {ApiArgValidator.LimitedSpecialCharacters})
65+
private String path;
66+
67+
@Parameter(name = ApiConstants.IS_SYMLINK, type = CommandType.BOOLEAN,
68+
description = "Path to list files in the backed-up volume.")
69+
private Boolean isSymlink;
70+
71+
/////////////////////////////////////////////////////
72+
/////////////////// Accessors ///////////////////////
73+
/////////////////////////////////////////////////////
74+
75+
public Long getBackupId() {
76+
return backupId;
77+
}
78+
79+
public Long getVolumeId() {
80+
return volumeId;
81+
}
82+
83+
public String getFilesystem() {
84+
return filesystem.trim();
85+
}
86+
87+
public String getPath() {
88+
return path.trim();
89+
}
90+
91+
public Boolean getSymlink() {
92+
return isSymlink;
93+
}
94+
95+
/////////////////////////////////////////////////////
96+
/////////////// API Implementation///////////////////
97+
/////////////////////////////////////////////////////
98+
99+
@Override
100+
public long getEntityOwnerId() {
101+
Backup backup = _entityMgr.findById(Backup.class, getBackupId());
102+
if (backup != null) {
103+
return backup.getAccountId();
104+
}
105+
106+
return Account.ACCOUNT_ID_SYSTEM;
107+
}
108+
109+
@Override
110+
public void execute() {
111+
List<DataStoreObjectResponse> responseList = backupManager.listBackupFiles(getBackupId(), getVolumeId(), getFilesystem(), getPath(), getSymlink());
112+
113+
ListResponse<DataStoreObjectResponse> response = new ListResponse<>();
114+
response.setResponses(responseList);
115+
response.setResponseName(getCommandName());
116+
response.setObjectName(getCommandName());
117+
this.setResponseObject(response);
118+
}
119+
}

0 commit comments

Comments
 (0)