Skip to content

Commit d710c98

Browse files
abh1sarsureshanaparti
authored andcommitted
Change storage pool scope from Cluster to Zone and vise versa (apache#8875)
* New feature: Change storage pool scope * Added checks for Ceph/RBD * Update op_host_capacity table on primary storage scope change * Storage pool scope change integration test * pull 8875 : Addressed review comments * Pull 8875: remove storage checks, AbstractPrimayStorageLifeCycleImpl class * Pull 8875: Fixed integration test failure * Pull 8875: Review comments * Pull 8875: review comments + broke changeStoragePoolScope into smaller functions * Added UT for changeStoragePoolScope * Rename AbstractPrimaryDataStoreLifeCycleImpl to BasePrimaryDataStoreLifeCycleImpl * Pull 8875: Dao review comments * Pull 8875: Rename changeStoragePoolScope.vue to ChangeStoragePoolScope.vue * Pull 8875: Created a new smokes test file + A single warning msg in ui * Pull 8875: Added cleanup in test_primary_storage_scope.py * Pull 8875: Type in en.json * Pull 8875: cleanup array in test_primary_storage_scope.py * Pull:8875 Removing extra whitespace at eof of StorageManagerImplTest * Pull 8875: Added UT for PrimaryDataStoreHelper and BasePrimaryDataStoreLifeCycleImpl * Pull 8875: Added license header * Pull 8875: Fixed sql query for vmstates * Pull 8875: Changed icon plus info on disabled mode in apidoc * Pull 8875: Change scope should not work for local storage * Pull 8875: Change scope completion event * Pull 8875: Added api findAffectedVmsForStorageScopeChange * Pull 8875: Added UT for findAffectedVmsForStorageScopeChange and removed listByPoolIdVMStatesNotInCluster * Pull 8875: Review comments + Vm name in response * Pull 8875: listByVmsNotInClusterUsingPool was returning duplicate VM entries because of multiple volumes in the VM satisfying the criteria * Pull 8875: fixed listAffectedVmsForStorageScopeChange UT * listAffectedVmsForStorageScopeChange should work if the pool is not disabled * Fix listAffectedVmsForStorageScopeChangeTest UT * Pull 8875: add volume.removed not null check in VmsNotInClusterUsingPool query * Pull 8875: minor refactoring in changeStoragePoolScopeToCluster * Update server/src/main/java/com/cloud/storage/StorageManagerImpl.java * fix eof * changeStoragePoolScopeToZone should connect pool to all Up hosts Co-authored-by: Suresh Kumar Anaparti <[email protected]>
1 parent 1443fbe commit d710c98

File tree

42 files changed

+1632
-46
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+1632
-46
lines changed

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,7 @@ public class EventTypes {
455455
public static final String EVENT_ENABLE_PRIMARY_STORAGE = "ENABLE.PS";
456456
public static final String EVENT_DISABLE_PRIMARY_STORAGE = "DISABLE.PS";
457457
public static final String EVENT_SYNC_STORAGE_POOL = "SYNC.STORAGE.POOL";
458+
public static final String EVENT_CHANGE_STORAGE_POOL_SCOPE = "CHANGE.STORAGE.POOL.SCOPE";
458459

459460
// VPN
460461
public static final String EVENT_REMOTE_ACCESS_VPN_CREATE = "VPN.REMOTE.ACCESS.CREATE";
@@ -1012,6 +1013,7 @@ public class EventTypes {
10121013
// Primary storage pool
10131014
entityEventDetails.put(EVENT_ENABLE_PRIMARY_STORAGE, StoragePool.class);
10141015
entityEventDetails.put(EVENT_DISABLE_PRIMARY_STORAGE, StoragePool.class);
1016+
entityEventDetails.put(EVENT_CHANGE_STORAGE_POOL_SCOPE, StoragePool.class);
10151017

10161018
// VPN
10171019
entityEventDetails.put(EVENT_REMOTE_ACCESS_VPN_CREATE, RemoteAccessVpn.class);

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import java.util.Map;
2222

2323
import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaintenanceCmd;
24+
import org.apache.cloudstack.api.command.admin.storage.ChangeStoragePoolScopeCmd;
2425
import org.apache.cloudstack.api.command.admin.storage.CreateSecondaryStagingStoreCmd;
2526
import org.apache.cloudstack.api.command.admin.storage.CreateStoragePoolCmd;
2627
import org.apache.cloudstack.api.command.admin.storage.DeleteImageStoreCmd;
@@ -35,6 +36,7 @@
3536
import com.cloud.exception.DiscoveryException;
3637
import com.cloud.exception.InsufficientCapacityException;
3738
import com.cloud.exception.InvalidParameterValueException;
39+
import com.cloud.exception.PermissionDeniedException;
3840
import com.cloud.exception.ResourceInUseException;
3941
import com.cloud.exception.ResourceUnavailableException;
4042
import org.apache.cloudstack.api.command.admin.storage.heuristics.CreateSecondaryStorageSelectorCmd;
@@ -130,4 +132,6 @@ public interface StorageService {
130132
boolean deleteObjectStore(DeleteObjectStoragePoolCmd cmd);
131133

132134
ObjectStore updateObjectStore(Long id, UpdateObjectStoragePoolCmd cmd);
135+
136+
void changeStoragePoolScope(ChangeStoragePoolScopeCmd cmd) throws IllegalArgumentException, InvalidParameterValueException, PermissionDeniedException;
133137
}
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
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+
18+
package org.apache.cloudstack.api.command.admin.storage;
19+
20+
import org.apache.cloudstack.api.APICommand;
21+
import org.apache.cloudstack.api.ApiCommandResourceType;
22+
import org.apache.cloudstack.api.ApiConstants;
23+
import org.apache.cloudstack.api.BaseAsyncCmd;
24+
import org.apache.cloudstack.api.Parameter;
25+
import org.apache.cloudstack.api.response.ClusterResponse;
26+
import org.apache.cloudstack.api.response.StoragePoolResponse;
27+
import org.apache.cloudstack.api.response.SuccessResponse;
28+
import org.apache.cloudstack.context.CallContext;
29+
30+
import com.cloud.event.EventTypes;
31+
import com.cloud.storage.StoragePool;
32+
33+
@APICommand(name = "changeStoragePoolScope", description = "Changes the scope of a storage pool when the pool is in Disabled state." +
34+
"This feature is officially tested and supported for Hypervisors: KVM and VMware, Protocols: NFS and Ceph, and Storage Provider: DefaultPrimary. " +
35+
"There might be extra steps involved to make this work for other hypervisors and storage options.",
36+
responseObject = SuccessResponse.class, since= "4.19.1", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
37+
public class ChangeStoragePoolScopeCmd extends BaseAsyncCmd {
38+
39+
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = StoragePoolResponse.class, required = true, description = "the Id of the storage pool")
40+
private Long id;
41+
42+
@Parameter(name = ApiConstants.SCOPE, type = CommandType.STRING, required = true, description = "the scope of the storage: cluster or zone")
43+
private String scope;
44+
45+
@Parameter(name = ApiConstants.CLUSTER_ID, type = CommandType.UUID, entityType = ClusterResponse.class, description = "the Id of the cluster to use if scope is being set to Cluster")
46+
private Long clusterId;
47+
48+
@Override
49+
public ApiCommandResourceType getApiResourceType() {
50+
return ApiCommandResourceType.StoragePool;
51+
}
52+
53+
@Override
54+
public Long getApiResourceId() {
55+
return getId();
56+
}
57+
58+
public String getEventType() {
59+
return EventTypes.EVENT_CHANGE_STORAGE_POOL_SCOPE;
60+
}
61+
62+
@Override
63+
public String getEventDescription() {
64+
String description = "Change storage pool scope. Storage pool Id: ";
65+
StoragePool pool = _entityMgr.findById(StoragePool.class, getId());
66+
if (pool != null) {
67+
description += pool.getUuid();
68+
} else {
69+
description += getId();
70+
}
71+
description += " to " + getScope();
72+
return description;
73+
}
74+
75+
@Override
76+
public void execute() {
77+
_storageService.changeStoragePoolScope(this);
78+
SuccessResponse response = new SuccessResponse(getCommandName());
79+
this.setResponseObject(response);
80+
}
81+
82+
@Override
83+
public long getEntityOwnerId() {
84+
return CallContext.current().getCallingAccountId();
85+
}
86+
87+
public Long getId() {
88+
return id;
89+
}
90+
91+
public String getScope() {
92+
return scope;
93+
}
94+
95+
public Long getClusterId() {
96+
return clusterId;
97+
}
98+
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
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 org.apache.cloudstack.api.command.admin.vm;
20+
21+
import org.apache.cloudstack.acl.RoleType;
22+
import org.apache.cloudstack.api.APICommand;
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.ClusterResponse;
27+
import org.apache.cloudstack.api.response.ListResponse;
28+
import org.apache.cloudstack.api.response.StoragePoolResponse;
29+
import org.apache.cloudstack.api.response.VirtualMachineResponse;
30+
31+
import com.cloud.vm.VirtualMachine;
32+
33+
@APICommand(name = "listAffectedVmsForStorageScopeChange",
34+
description = "List user and system VMs that need to be stopped and destroyed respectively for changing the scope of the storage pool from Zone to Cluster.",
35+
responseObject = VirtualMachineResponse.class,
36+
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, since = "4.19.1",
37+
authorized = {RoleType.Admin})
38+
public class ListAffectedVmsForStorageScopeChangeCmd extends BaseListCmd {
39+
40+
@Parameter(name = ApiConstants.CLUSTER_ID,
41+
type = CommandType.UUID,
42+
entityType = ClusterResponse.class,
43+
required = true,
44+
description = "the Id of the cluster the scope of the storage pool is being changed to")
45+
private Long clusterIdForScopeChange;
46+
47+
@Parameter(name = ApiConstants.STORAGE_ID,
48+
type = CommandType.UUID,
49+
entityType = StoragePoolResponse.class,
50+
required = true,
51+
description = "the Id of the storage pool on which change scope operation is being done")
52+
private Long storageId;
53+
54+
/////////////////////////////////////////////////////
55+
/////////////////// Accessors ///////////////////////
56+
/////////////////////////////////////////////////////
57+
58+
public Long getClusterIdForScopeChange() {
59+
return clusterIdForScopeChange;
60+
}
61+
62+
public Long getStorageId() {
63+
return storageId;
64+
}
65+
66+
/////////////////////////////////////////////////////
67+
/////////////// API Implementation///////////////////
68+
/////////////////////////////////////////////////////
69+
70+
@Override
71+
public void execute() {
72+
ListResponse<VirtualMachineResponse> response = _queryService.listAffectedVmsForStorageScopeChange(this);
73+
response.setResponseName(getCommandName());
74+
response.setObjectName(VirtualMachine.class.getSimpleName().toLowerCase());
75+
setResponseObject(response);
76+
}
77+
}
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.response;
18+
19+
import org.apache.cloudstack.api.BaseResponse;
20+
import org.apache.cloudstack.api.EntityReference;
21+
22+
import com.cloud.serializer.Param;
23+
import com.cloud.vm.VirtualMachine;
24+
import com.google.gson.annotations.SerializedName;
25+
26+
@EntityReference(value = VirtualMachine.class)
27+
public class VirtualMachineResponse extends BaseResponse {
28+
@SerializedName("id")
29+
@Param(description = "the ID of the VM")
30+
private String id;
31+
32+
@SerializedName("type")
33+
@Param(description = "the type of VM")
34+
private String type;
35+
36+
@SerializedName("name")
37+
@Param(description = "the name of the VM")
38+
private String name;
39+
40+
@SerializedName("clusterid")
41+
@Param(description = "the cluster ID for the VM")
42+
private String clusterId;
43+
44+
@SerializedName("clustername")
45+
@Param(description = "the cluster name for the VM")
46+
private String clusterName;
47+
48+
@SerializedName("hostid")
49+
@Param(description = "the host ID for the VM")
50+
private String hostId;
51+
52+
@SerializedName("hostname")
53+
@Param(description = "the hostname for the VM")
54+
private String hostName;
55+
56+
@Override
57+
public String getObjectId() {
58+
return this.getId();
59+
}
60+
61+
public String getId() {
62+
return id;
63+
}
64+
65+
public void setId(String id) {
66+
this.id = id;
67+
}
68+
69+
public String getVmType() {
70+
return type;
71+
}
72+
73+
public void setVmType(String type) {
74+
this.type = type;
75+
}
76+
77+
public String getVmName() {
78+
return name;
79+
}
80+
81+
public void setVmName(String name) {
82+
this.name = name;
83+
}
84+
85+
public String getClusterId() {
86+
return clusterId;
87+
}
88+
89+
public void setClusterId(String clusterId) {
90+
this.clusterId = clusterId;
91+
}
92+
93+
public String getClusterName() {
94+
return clusterName;
95+
}
96+
97+
public void setClusterName(String clusterName) {
98+
this.clusterName = clusterName;
99+
}
100+
101+
public String getName() {
102+
return name;
103+
}
104+
105+
public void setName(String name) {
106+
this.name = name;
107+
}
108+
109+
public String getHostId() {
110+
return hostId;
111+
}
112+
113+
public void setHostId(String hostId) {
114+
this.hostId = hostId;
115+
}
116+
117+
public String getHostName() {
118+
return hostName;
119+
}
120+
121+
public void setHostName(String hostName) {
122+
this.hostName = hostName;
123+
}
124+
}

api/src/main/java/org/apache/cloudstack/query/QueryService.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotsCmd;
5353
import org.apache.cloudstack.api.command.user.tag.ListTagsCmd;
5454
import org.apache.cloudstack.api.command.user.template.ListTemplatesCmd;
55+
import org.apache.cloudstack.api.command.admin.vm.ListAffectedVmsForStorageScopeChangeCmd;
5556
import org.apache.cloudstack.api.command.user.vm.ListVMsCmd;
5657
import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd;
5758
import org.apache.cloudstack.api.command.user.volume.ListResourceDetailsCmd;
@@ -89,6 +90,7 @@
8990
import org.apache.cloudstack.api.response.TemplateResponse;
9091
import org.apache.cloudstack.api.response.UserResponse;
9192
import org.apache.cloudstack.api.response.UserVmResponse;
93+
import org.apache.cloudstack.api.response.VirtualMachineResponse;
9294
import org.apache.cloudstack.api.response.VolumeResponse;
9395
import org.apache.cloudstack.api.response.ZoneResponse;
9496
import org.apache.cloudstack.framework.config.ConfigKey;
@@ -140,6 +142,8 @@ public interface QueryService {
140142

141143
ListResponse<UserVmResponse> searchForUserVMs(ListVMsCmd cmd);
142144

145+
ListResponse<VirtualMachineResponse> listAffectedVmsForStorageScopeChange(ListAffectedVmsForStorageScopeChangeCmd cmd);
146+
143147
ListResponse<SecurityGroupResponse> searchForSecurityGroups(ListSecurityGroupsCmd cmd);
144148

145149
ListResponse<DomainRouterResponse> searchForRouters(ListRoutersCmd cmd);

engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreLifeCycle.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020

2121
import java.util.Map;
2222

23+
import com.cloud.hypervisor.Hypervisor;
2324
import com.cloud.storage.StoragePool;
2425

2526
public interface PrimaryDataStoreLifeCycle extends DataStoreLifeCycle {
@@ -29,4 +30,6 @@ public interface PrimaryDataStoreLifeCycle extends DataStoreLifeCycle {
2930
void updateStoragePool(StoragePool storagePool, Map<String, String> details);
3031
void enableStoragePool(DataStore store);
3132
void disableStoragePool(DataStore store);
33+
void changeStoragePoolScopeToZone(DataStore store, ClusterScope clusterScope, Hypervisor.HypervisorType hypervisorType);
34+
void changeStoragePoolScopeToCluster(DataStore store, ClusterScope clusterScope, Hypervisor.HypervisorType hypervisorType);
3235
}

engine/components-api/src/main/java/com/cloud/resource/ResourceManager.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ public interface ResourceManager extends ResourceService, Configurable {
134134

135135
public List<HostVO> listAllHostsInAllZonesByType(Type type);
136136

137+
public List<HostVO> listAllHostsInOneZoneNotInClusterByHypervisor(final HypervisorType type, long dcId, long clusterId);
138+
139+
public List<HostVO> listAllHostsInOneZoneNotInClusterByHypervisors(List<HypervisorType> types, long dcId, long clusterId);
140+
137141
public List<HypervisorType> listAvailHypervisorInZone(Long hostId, Long zoneId);
138142

139143
public HostVO findHostByGuid(String guid);

0 commit comments

Comments
 (0)