Skip to content
Merged
Show file tree
Hide file tree
Changes from 42 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
7835a48
New feature: Import volume from storage pool
weizhouapache Mar 20, 2024
3863353
Update 8808: part1
weizhouapache Mar 20, 2024
5a28f97
Update 8808: part2 for local storage
weizhouapache Mar 20, 2024
bb35235
Update 8808: rename VolumeImportUnmanagedManagerImpl to VolumeImportU…
weizhouapache Mar 20, 2024
388e7e2
Update 8808: list volumesforimport by path
weizhouapache Mar 21, 2024
b77c6eb
Update 8808: check if volume is locked
weizhouapache Mar 21, 2024
01059e9
Update 8808: Do not import Encrypted disk (could be supported later)
weizhouapache Mar 21, 2024
c61d13f
Update 8088: revert VMware changes
weizhouapache Mar 21, 2024
deb5e12
Update 8088: do not unmanage encrypted volumes
weizhouapache Mar 21, 2024
167f590
Update 8808: add unit tests
weizhouapache Mar 21, 2024
083d715
Update 8088: code optimization
weizhouapache Mar 21, 2024
a7d1796
Update 8808: add unit tests part2
weizhouapache Mar 22, 2024
55196a4
Update 8808: add unit tests part3
weizhouapache Mar 22, 2024
b14fdf2
Update 8088: remove unused constructor VolumeOnStorageTO
weizhouapache Mar 25, 2024
6d921e3
Update 8088: import volume with name
weizhouapache Mar 25, 2024
6207a97
Update 8088: sort the volumes by name
weizhouapache Mar 25, 2024
70a83d1
Update 8088: add unit tests VolumeImportUnmanageManagerImplTest
weizhouapache Mar 25, 2024
4b9ef71
Update 8088: search by keyword
weizhouapache Mar 25, 2024
b9b7116
Update 8088: fix typo in ImportVolumeCmd
weizhouapache Mar 25, 2024
b13607b
Update 8088: mark unmanaged volume as Destroy
weizhouapache Mar 25, 2024
dc906ba
Update 8088: skip tests in setUpClass
weizhouapache Mar 25, 2024
b085e32
Update 8088: refactor findHostAndLocalPathForVolumeImportForHost
weizhouapache Mar 25, 2024
7a14fbd
Update 8088: refactor LibvirtGetVolumesOnStorageCommandWrapper
weizhouapache Mar 25, 2024
a2db5cf
Update 8808: add test testLogFailureAndThrowException
weizhouapache Mar 25, 2024
bc83209
Update 8088: UI for volume import/unmanage
weizhouapache Mar 25, 2024
fd4b237
Fix PR 8808 against 4.19
weizhouapache Mar 25, 2024
cd0e313
Update 8088: clean search keyword on UI when change zone/pod/cluster/…
weizhouapache Mar 26, 2024
1750a32
Update 8088: import volume for specified account on UI
weizhouapache Mar 27, 2024
0a96796
Update 8088: add validateCustomDiskOfferingSizeRange
weizhouapache Mar 27, 2024
d16a7ed
Update 8088: do not import volume with backing file
weizhouapache Mar 27, 2024
42cd529
Update 8088: do not import volumes with different file format as supp…
weizhouapache Mar 27, 2024
8b06f57
Update 8088: check if volume is a reference of snapshot
weizhouapache Mar 27, 2024
a619041
Update 8088: publish event when import/unmanage is completed
weizhouapache Mar 28, 2024
37e3436
Update 8088: change label
weizhouapache Mar 28, 2024
fb672cc
Update 8088: add MockedStatic<ActionEventUtils>
weizhouapache Mar 28, 2024
1092bbc
Update 8088: refactor VolumeImportUnmanageManagerImplTest
weizhouapache Mar 28, 2024
dff5fd8
Update 8088: select disk offering on UI
weizhouapache Apr 2, 2024
e0b30f0
Update 8808: Disk offering should not support volume encryption
weizhouapache Apr 2, 2024
ff261ca
Update 8808: storage pool should be Up
weizhouapache Apr 2, 2024
ef6d167
Update 8808: check volume path on storage pool on kvm hosts
weizhouapache Apr 2, 2024
ffe9c96
Update 8808: check disk offering tags
weizhouapache Apr 2, 2024
a2574bd
Merge remote-tracking branch 'apache/4.19' into 4.19-import-volume
weizhouapache Apr 4, 2024
3fa226b
Update 8808: define list of supported hypervisors and storage types
weizhouapache Apr 8, 2024
e5f6072
Update 8808: get volume via host and check for both import/unmanage
weizhouapache Apr 22, 2024
8e6d673
Update 8808: allow only unmanage detached/Ready/KVM volume on UI
weizhouapache Apr 22, 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/event/EventTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,8 @@ public class EventTypes {
public static final String EVENT_VOLUME_UPDATE = "VOLUME.UPDATE";
public static final String EVENT_VOLUME_DESTROY = "VOLUME.DESTROY";
public static final String EVENT_VOLUME_RECOVER = "VOLUME.RECOVER";
public static final String EVENT_VOLUME_IMPORT = "VOLUME.IMPORT";
public static final String EVENT_VOLUME_UNMANAGE = "VOLUME.UNMANAGE";
public static final String EVENT_VOLUME_CHANGE_DISK_OFFERING = "VOLUME.CHANGE.DISK.OFFERING";

// Domains
Expand Down
3 changes: 3 additions & 0 deletions api/src/main/java/org/apache/cloudstack/api/ApiConstants.java
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,7 @@ public class ApiConstants {
public static final String CURRENT_START_IP = "currentstartip";
public static final String CURRENT_END_IP = "currentendip";
public static final String ENCRYPT = "encrypt";
public static final String ENCRYPT_FORMAT = "encryptformat";
public static final String ENCRYPT_ROOT = "encryptroot";
public static final String ENCRYPTION_SUPPORTED = "encryptionsupported";
public static final String MIN_IOPS = "miniops";
Expand Down Expand Up @@ -191,6 +192,7 @@ public class ApiConstants {
public static final String FORMAT = "format";
public static final String FOR_VIRTUAL_NETWORK = "forvirtualnetwork";
public static final String FOR_SYSTEM_VMS = "forsystemvms";
public static final String FULL_PATH = "fullpath";
public static final String GATEWAY = "gateway";
public static final String IP6_GATEWAY = "ip6gateway";
public static final String GROUP = "group";
Expand Down Expand Up @@ -550,6 +552,7 @@ public class ApiConstants {
public static final String ALLOCATION_STATE = "allocationstate";
public static final String MANAGED_STATE = "managedstate";
public static final String MANAGEMENT_SERVER_ID = "managementserverid";
public static final String STORAGE = "storage";
public static final String STORAGE_ID = "storageid";
public static final String PING_STORAGE_SERVER_IP = "pingstorageserverip";
public static final String PING_DIR = "pingdir";
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
// 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.volume;

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 org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ResponseObject;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.DiskOfferingResponse;
import org.apache.cloudstack.api.response.DomainResponse;
import org.apache.cloudstack.api.response.ProjectResponse;
import org.apache.cloudstack.api.response.StoragePoolResponse;
import org.apache.cloudstack.api.response.VolumeResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.storage.volume.VolumeImportUnmanageService;

import javax.inject.Inject;

@APICommand(name = "importVolume",
description = "Import an unmanaged volume from a storage pool on a host into CloudStack",
responseObject = VolumeResponse.class,
responseView = ResponseObject.ResponseView.Full,
requestHasSensitiveInfo = false,
responseHasSensitiveInfo = true,
authorized = {RoleType.Admin},
since = "4.19.1")
public class ImportVolumeCmd extends BaseAsyncCmd {

@Inject
public VolumeImportUnmanageService volumeImportService;

/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////


@Parameter(name = ApiConstants.PATH,
type = BaseCmd.CommandType.STRING,
required = true,
description = "the path of the volume")
private String path;

@Parameter(name = ApiConstants.NAME,
type = BaseCmd.CommandType.STRING,
description = "the name of the volume. If not set, it will be set to the path of the volume.")
private String name;

@Parameter(name = ApiConstants.STORAGE_ID,
type = BaseCmd.CommandType.UUID,
required = true,
entityType = StoragePoolResponse.class,
description = "the ID of the storage pool")
private Long storageId;

@Parameter(name = ApiConstants.DISK_OFFERING_ID,
type = BaseCmd.CommandType.UUID,
entityType = DiskOfferingResponse.class,
description = "the ID of the disk offering linked to the volume")
private Long diskOfferingId;

@Parameter(name = ApiConstants.ACCOUNT,
type = BaseCmd.CommandType.STRING,
description = "an optional account for the volume. Must be used with domainId.")
private String accountName;

@Parameter(name = ApiConstants.DOMAIN_ID,
type = BaseCmd.CommandType.UUID,
entityType = DomainResponse.class,
description = "import volume to the domain specified")
private Long domainId;

@Parameter(name = ApiConstants.PROJECT_ID,
type = BaseCmd.CommandType.UUID,
entityType = ProjectResponse.class,
description = "import volume for the project")
private Long projectId;

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

public String getPath() {
return path;
}

public String getName() {
return name;
}

public Long getStorageId() {
return storageId;
}

public Long getDiskOfferingId() {
return diskOfferingId;
}

public String getAccountName() {
return accountName;
}

public Long getDomainId() {
return domainId;
}

public Long getProjectId() {
return projectId;
}

@Override
public String getEventType() {
return EventTypes.EVENT_VOLUME_IMPORT;
}

@Override
public String getEventDescription() {
return String.format("Importing unmanaged Volume with path: %s", path);
}

/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
VolumeResponse response = volumeImportService.importVolume(this);
response.setResponseName(getCommandName());
setResponseObject(response);
}

@Override
public long getEntityOwnerId() {
Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true);
if (accountId == null) {
return CallContext.current().getCallingAccount().getId();
}
return accountId;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// 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.volume;

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 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.BaseListCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ResponseObject;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.api.response.StoragePoolResponse;
import org.apache.cloudstack.api.response.VolumeForImportResponse;
import org.apache.cloudstack.storage.volume.VolumeImportUnmanageService;
import org.apache.cloudstack.storage.volume.VolumeOnStorageTO;

import javax.inject.Inject;

@APICommand(name = "listVolumesForImport",
description = "Lists unmanaged volumes on a storage pool",
responseObject = VolumeForImportResponse.class,
responseView = ResponseObject.ResponseView.Full,
entityType = {VolumeOnStorageTO.class},
requestHasSensitiveInfo = false,
responseHasSensitiveInfo = true,
authorized = {RoleType.Admin},
since = "4.19.1")
public class ListVolumesForImportCmd extends BaseListCmd {

@Inject
public VolumeImportUnmanageService volumeImportService;

/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////

@Parameter(name = ApiConstants.STORAGE_ID,
type = BaseCmd.CommandType.UUID,
required = true,
entityType = StoragePoolResponse.class,
description = "the ID of the storage pool")
private Long storageId;

@Parameter(name = ApiConstants.PATH,
type = BaseCmd.CommandType.STRING,
description = "the path of the volume on the storage pool")
private String path;

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

public Long getStorageId() {
return storageId;
}

public String getPath() {
return path;
}

/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
ListResponse<VolumeForImportResponse> response = volumeImportService.listVolumesForImport(this);
response.setResponseName(getCommandName());
setResponseObject(response);
}
}
Loading