Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change storage pool scope from Cluster to Zone and vise versa #8875

Merged
merged 57 commits into from
Jun 29, 2024
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
57 commits
Select commit Hold shift + click to select a range
f7ea076
New feature: Change storage pool scope
abh1sar Apr 1, 2024
d6aa362
Added checks for Ceph/RBD
abh1sar Apr 2, 2024
5a1e7bd
Update op_host_capacity table on primary storage scope change
abh1sar Apr 2, 2024
5bd6995
Storage pool scope change integration test
abh1sar Apr 3, 2024
c5cbd5d
pull 8875 : Addressed review comments
abh1sar Apr 4, 2024
0fab7a3
Pull 8875: remove storage checks, AbstractPrimayStorageLifeCycleImpl …
abh1sar Apr 6, 2024
283db1f
Pull 8875: Fixed integration test failure
abh1sar Apr 8, 2024
fb976d9
Pull 8875: Review comments
abh1sar Apr 9, 2024
042aef7
Pull 8875: review comments + broke changeStoragePoolScope into smalle…
abh1sar Apr 12, 2024
72160ea
Added UT for changeStoragePoolScope
abh1sar Apr 22, 2024
abf7082
Rename AbstractPrimaryDataStoreLifeCycleImpl to BasePrimaryDataStoreL…
abh1sar Apr 22, 2024
5ba040d
Pull 8875: Dao review comments
abh1sar Apr 22, 2024
ca36119
Pull 8875: Rename changeStoragePoolScope.vue to ChangeStoragePoolScop…
abh1sar Apr 22, 2024
962d0f3
Pull 8875: Created a new smokes test file + A single warning msg in ui
abh1sar Apr 22, 2024
f98b754
Merge with latest 4.19
abh1sar Apr 23, 2024
3753be3
Merge remote-tracking branch 'upstream/4.19' into changescope419
abh1sar Apr 24, 2024
30d628d
Merge branch '4.19' into 419-changescope
abh1sar Apr 24, 2024
aa83ec0
Pull 8875: Added cleanup in test_primary_storage_scope.py
abh1sar Apr 24, 2024
dcb9449
Pull 8875: Type in en.json
abh1sar Apr 24, 2024
8ce579a
Merge remote-tracking branch 'upstream/4.19' into changescope419
abh1sar Apr 24, 2024
bc4e700
Merge branch '4.19' into 419-changescope
abh1sar Apr 24, 2024
d714b8c
Merge remote-tracking branch 'upstream/4.19' into 419
abh1sar Apr 24, 2024
8de7aa6
Pull 8875: cleanup array in test_primary_storage_scope.py
abh1sar Apr 24, 2024
4b07a6c
Merge branch '4.19' into 419-changescope
abh1sar Apr 25, 2024
b3245cd
Pull:8875 Removing extra whitespace at eof of StorageManagerImplTest
abh1sar Apr 25, 2024
f3bdae8
Merge branch '419-changescope' of http://github.com/abh1sar/cloudstac…
abh1sar Apr 25, 2024
9657a10
Pull 8875: Added UT for PrimaryDataStoreHelper and BasePrimaryDataSto…
abh1sar Apr 29, 2024
8d36db0
Pull 8875: Added license header
abh1sar Apr 29, 2024
5ef41e1
Merge remote-tracking branch 'upstream/4.19' into changescope419
abh1sar Apr 29, 2024
aad87f2
Pull 8875: Fixed sql query for vmstates
abh1sar Apr 30, 2024
85a6340
Pull 8875: Changed icon plus info on disabled mode in apidoc
abh1sar May 1, 2024
49341db
Merge remote-tracking branch 'upstream/4.19' into changescope419
abh1sar May 6, 2024
419e5a4
Pull 8875: Change scope should not work for local storage
abh1sar May 6, 2024
d611198
Pull 8875: Change scope completion event
abh1sar May 6, 2024
9da8382
Pull 8875: Added api findAffectedVmsForStorageScopeChange
abh1sar May 19, 2024
8646c80
Merge remote-tracking branch 'upstream/4.19' into changescope419
abh1sar May 19, 2024
35c8b00
Pull 8875: Added UT for findAffectedVmsForStorageScopeChange and remo…
abh1sar May 21, 2024
ba397d7
Pull 8875: Review comments + Vm name in response
abh1sar May 22, 2024
81a2c67
Pull 8875: listByVmsNotInClusterUsingPool was returning duplicate VM …
abh1sar May 22, 2024
c502838
Pull 8875: fixed listAffectedVmsForStorageScopeChange UT
abh1sar May 22, 2024
edea352
Merge remote-tracking branch 'upstream/4.19' into changescope419
abh1sar May 23, 2024
3af24b4
Merge remote-tracking branch 'upstream/4.19' into scope
abh1sar Jun 18, 2024
cc08595
listAffectedVmsForStorageScopeChange should work if the pool is not d…
abh1sar Jun 18, 2024
0b75de1
Fix listAffectedVmsForStorageScopeChangeTest UT
abh1sar Jun 18, 2024
eedb361
Merge branch '4.19' into 419-changescope
abh1sar Jun 18, 2024
e62551b
Merge remote-tracking branch 'upstream/4.19' into cs
abh1sar Jun 19, 2024
57c4a2f
Pull 8875: add volume.removed not null check in VmsNotInClusterUsingP…
abh1sar Jun 19, 2024
271d526
Pull 8875: minor refactoring in changeStoragePoolScopeToCluster
abh1sar Jun 19, 2024
0821cc7
Update server/src/main/java/com/cloud/storage/StorageManagerImpl.java
sureshanaparti Jun 25, 2024
0507508
Merge remote-tracking branch 'upstream/4.19' into cs
abh1sar Jun 26, 2024
afd107b
fix eof
abh1sar Jun 26, 2024
2bdd974
Merge branch '4.19' into 419-changescope
abh1sar Jun 26, 2024
e40c14a
Merge branch '4.19' into 419-changescope
abh1sar Jun 27, 2024
e0cec9e
changeStoragePoolScopeToZone should connect pool to all Up hosts
abh1sar Jun 28, 2024
11b43b2
Merge branch '4.19' into 419-changescope
abh1sar Jun 28, 2024
25c4a01
Merge branch '4.19' into 419-changescope
abh1sar Jun 28, 2024
1b698c1
Merge branch '4.19' into 419-changescope
abh1sar Jun 29, 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
1 change: 1 addition & 0 deletions api/src/main/java/com/cloud/event/EventTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -449,6 +449,7 @@ public class EventTypes {
public static final String EVENT_ENABLE_PRIMARY_STORAGE = "ENABLE.PS";
public static final String EVENT_DISABLE_PRIMARY_STORAGE = "DISABLE.PS";
public static final String EVENT_SYNC_STORAGE_POOL = "SYNC.STORAGE.POOL";
public static final String EVENT_CHANGE_STORAGE_POOL_SCOPE = "CHANGE.STORAGE.POOL.SCOPE";

// VPN
public static final String EVENT_REMOTE_ACCESS_VPN_CREATE = "VPN.REMOTE.ACCESS.CREATE";
Expand Down
4 changes: 4 additions & 0 deletions api/src/main/java/com/cloud/storage/StorageService.java
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.util.Map;

import org.apache.cloudstack.api.command.admin.storage.CancelPrimaryStorageMaintenanceCmd;
import org.apache.cloudstack.api.command.admin.storage.ChangeStoragePoolScopeCmd;
import org.apache.cloudstack.api.command.admin.storage.CreateSecondaryStagingStoreCmd;
import org.apache.cloudstack.api.command.admin.storage.CreateStoragePoolCmd;
import org.apache.cloudstack.api.command.admin.storage.DeleteImageStoreCmd;
Expand All @@ -34,6 +35,7 @@
import com.cloud.exception.DiscoveryException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceInUseException;
import com.cloud.exception.ResourceUnavailableException;
import org.apache.cloudstack.api.command.admin.storage.heuristics.CreateSecondaryStorageSelectorCmd;
Expand Down Expand Up @@ -127,4 +129,6 @@ public interface StorageService {
boolean deleteObjectStore(DeleteObjectStoragePoolCmd cmd);

ObjectStore updateObjectStore(Long id, UpdateObjectStoragePoolCmd cmd);

void changeStoragePoolScope(ChangeStoragePoolScopeCmd cmd) throws IllegalArgumentException, InvalidParameterValueException, PermissionDeniedException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
// 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.storage;

import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.response.ClusterResponse;
import org.apache.cloudstack.api.response.StoragePoolResponse;
import org.apache.cloudstack.api.response.SuccessResponse;
import org.apache.cloudstack.context.CallContext;

import com.cloud.event.EventTypes;

@APICommand(name = "changeStoragePoolScope", description = "Changes the scope of a storage pool. " +
"This feature is officially tested and supported for Hypervisors: KVM and VMware, Protocols: NFS and Ceph, and Storage Provider: DefaultPrimary. " +
"There might be extra steps involved to make this work for other hypervisors and storage options.",
responseObject = SuccessResponse.class, since= "4.19.1", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class ChangeStoragePoolScopeCmd extends BaseAsyncCmd {

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

@Parameter(name = ApiConstants.SCOPE, type = CommandType.STRING, required = true, description = "the scope of the storage: cluster or zone")
private String scope;

@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")
private Long clusterId;

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

@Override
public String getEventDescription() {
return "Change the scope to " + scope + " for storage pool " + this.id;
}

@Override
public void execute() {
_storageService.changeStoragePoolScope(this);
SuccessResponse response = new SuccessResponse(getCommandName());
this.setResponseObject(response);
}

@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccountId();
}

public Long getId() {
return id;
}

public String getScope() {
return scope;
}

public Long getClusterId() {
return clusterId;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@

import java.util.Map;

import com.cloud.hypervisor.Hypervisor;
import com.cloud.storage.StoragePool;

public interface PrimaryDataStoreLifeCycle extends DataStoreLifeCycle {
Expand All @@ -29,4 +30,6 @@ public interface PrimaryDataStoreLifeCycle extends DataStoreLifeCycle {
void updateStoragePool(StoragePool storagePool, Map<String, String> details);
void enableStoragePool(DataStore store);
void disableStoragePool(DataStore store);
void changeStoragePoolScopeToZone(DataStore store, ClusterScope clusterScope, Hypervisor.HypervisorType hypervisorType);
void changeStoragePoolScopeToCluster(DataStore store, ClusterScope clusterScope, Hypervisor.HypervisorType hypervisorType);
}
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ public interface ResourceManager extends ResourceService, Configurable {

public List<HostVO> listAllHostsInAllZonesByType(Type type);

public List<HostVO> listAllHostsInOneZoneNotInClusterByHypervisor(final HypervisorType type, long dcId, long clusterId);

public List<HostVO> listAllHostsInOneZoneNotInClusterByHypervisors(List<HypervisorType> types, long dcId, long clusterId);

public List<HypervisorType> listAvailHypervisorInZone(Long hostId, Long zoneId);

public HostVO findHostByGuid(String guid);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -132,17 +132,17 @@ public Long getPodId() {
return podId;
}

public void setPodId(long podId) {
this.podId = new Long(podId);
public void setPodId(Long podId) {
this.podId = podId;
}

@Override
public Long getClusterId() {
return clusterId;
}

public void setClusterId(long clusterId) {
this.clusterId = new Long(clusterId);
public void setClusterId(Long clusterId) {
this.clusterId = clusterId;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,4 +41,6 @@ public interface StoragePoolHostDao extends GenericDao<StoragePoolHostVO, Long>
public void deleteStoragePoolHostDetails(long hostId, long poolId);

List<StoragePoolHostVO> listByHostId(long hostId);

Pair<List<StoragePoolHostVO>, Integer> listByPoolIdNotInCluster(long clusterId, long poolId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,19 @@
import java.util.List;
import java.util.stream.Collectors;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import com.cloud.host.HostVO;
import com.cloud.host.Status;
import com.cloud.host.dao.HostDao;
import com.cloud.storage.StoragePoolHostVO;
import com.cloud.utils.Pair;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.JoinBuilder;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.TransactionLegacy;
Expand All @@ -42,6 +48,11 @@ public class StoragePoolHostDaoImpl extends GenericDaoBase<StoragePoolHostVO, Lo
protected final SearchBuilder<StoragePoolHostVO> HostSearch;
protected final SearchBuilder<StoragePoolHostVO> PoolHostSearch;

protected SearchBuilder<StoragePoolHostVO> poolNotInClusterSearch;

@Inject
HostDao hostDao;

protected static final String HOST_FOR_POOL_SEARCH = "SELECT * FROM storage_pool_host_ref ph, host h where ph.host_id = h.id and ph.pool_id=? and h.status=? ";

protected static final String HOSTS_FOR_POOLS_SEARCH = "SELECT DISTINCT(ph.host_id) FROM storage_pool_host_ref ph, host h WHERE ph.host_id = h.id AND h.status = 'Up' AND resource_state = 'Enabled' AND ph.pool_id IN (?)";
Expand Down Expand Up @@ -70,6 +81,15 @@ public StoragePoolHostDaoImpl() {

}

@PostConstruct
public void init(){
poolNotInClusterSearch = createSearchBuilder();
poolNotInClusterSearch.and("poolId", poolNotInClusterSearch.entity().getPoolId(), SearchCriteria.Op.EQ);
SearchBuilder<HostVO> hostSearch = hostDao.createSearchBuilder();
poolNotInClusterSearch.join("hostSearch", hostSearch, hostSearch.entity().getId(), poolNotInClusterSearch.entity().getHostId(), JoinBuilder.JoinType.INNER);
hostSearch.and("clusterId", hostSearch.entity().getClusterId(), SearchCriteria.Op.NEQ);
}

@Override
public List<StoragePoolHostVO> listByPoolId(long id) {
SearchCriteria<StoragePoolHostVO> sc = PoolSearch.create();
Expand Down Expand Up @@ -196,4 +216,12 @@ public void deleteStoragePoolHostDetails(long hostId, long poolId) {
remove(sc);
txn.commit();
}

@Override
public Pair<List<StoragePoolHostVO>, Integer> listByPoolIdNotInCluster(long clusterId, long poolId) {
SearchCriteria<StoragePoolHostVO> sc = poolNotInClusterSearch.create();
sc.setParameters("poolId", poolId);
sc.setJoinParameters("hostSearch", "clusterId", clusterId);
return searchAndCount(sc, null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import com.cloud.utils.Pair;
import com.cloud.utils.db.GenericDao;
import com.cloud.utils.fsm.StateDao;
import com.cloud.vm.VirtualMachine;

public interface VolumeDao extends GenericDao<VolumeVO, Long>, StateDao<Volume.State, Volume.Event, Volume> {

Expand Down Expand Up @@ -155,4 +156,6 @@ public interface VolumeDao extends GenericDao<VolumeVO, Long>, StateDao<Volume.S
VolumeVO findByPoolIdAndPath(long id, String path);

List<VolumeVO> listByIds(List<Long> ids);

public List<VolumeVO> listByPoolIdVMStatesNotInCluster(long clusterId, List<VirtualMachine.State> states, long poolId);
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,16 @@
import java.util.Date;
import java.util.List;

import javax.annotation.PostConstruct;
import javax.inject.Inject;

import org.apache.commons.collections.CollectionUtils;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import com.cloud.exception.InvalidParameterValueException;
import com.cloud.host.HostVO;
import com.cloud.host.dao.HostDao;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.server.ResourceTag.ResourceObjectType;
import com.cloud.storage.ScopeType;
Expand All @@ -45,13 +48,17 @@
import com.cloud.utils.db.DB;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.GenericSearchBuilder;
import com.cloud.utils.db.JoinBuilder.JoinType;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Func;
import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.db.TransactionLegacy;
import com.cloud.utils.db.UpdateBuilder;
import com.cloud.utils.exception.CloudRuntimeException;
import com.cloud.vm.VMInstanceVO;
import com.cloud.vm.VirtualMachine;
import com.cloud.vm.dao.VMInstanceDao;

@Component
public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements VolumeDao {
Expand All @@ -72,8 +79,14 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, Long> implements Vol
protected GenericSearchBuilder<VolumeVO, SumCount> primaryStorageSearch2;
protected GenericSearchBuilder<VolumeVO, SumCount> secondaryStorageSearch;
private final SearchBuilder<VolumeVO> poolAndPathSearch;
protected SearchBuilder<VolumeVO> volumePoolNotInClusterSearch;

@Inject
ResourceTagDao tagsDao;
@Inject
HostDao hostDao;
@Inject
ResourceTagDao _tagsDao;
VMInstanceDao vmDao;

protected static final String SELECT_VM_SQL = "SELECT DISTINCT instance_id from volumes v where v.host_id = ? and v.mirror_state = ?";
// need to account for zone-wide primary storage where storage_pool has
Expand Down Expand Up @@ -493,7 +506,19 @@ public VolumeDaoImpl() {
poolAndPathSearch.and("poolId", poolAndPathSearch.entity().getPoolId(), Op.EQ);
poolAndPathSearch.and("path", poolAndPathSearch.entity().getPath(), Op.EQ);
poolAndPathSearch.done();
}

@PostConstruct
public void init() {
volumePoolNotInClusterSearch = createSearchBuilder();
volumePoolNotInClusterSearch.and("poolId", volumePoolNotInClusterSearch.entity().getPoolId(), Op.EQ);
SearchBuilder<VMInstanceVO> vmSearch = vmDao.createSearchBuilder();
vmSearch.and("vmStates", vmSearch.entity().getState(), Op.IN);
SearchBuilder<HostVO> hostSearch = hostDao.createSearchBuilder();
hostSearch.and("clusterId", hostSearch.entity().getClusterId(), SearchCriteria.Op.NEQ);
vmSearch.join("hostSearch", hostSearch, hostSearch.entity().getId(), vmSearch.entity().getHostId(), JoinType.INNER);
volumePoolNotInClusterSearch.join("vmSearch", vmSearch, vmSearch.entity().getId(), volumePoolNotInClusterSearch.entity().getInstanceId(), JoinType.INNER);
volumePoolNotInClusterSearch.done();
}

@Override
Expand Down Expand Up @@ -719,7 +744,7 @@ public boolean remove(Long id) {
s_logger.debug(String.format("Removing volume %s from DB", id));
VolumeVO entry = findById(id);
if (entry != null) {
_tagsDao.removeByIdAndType(id, ResourceObjectType.Volume);
tagsDao.removeByIdAndType(id, ResourceObjectType.Volume);
}
boolean result = super.remove(id);

Expand All @@ -742,7 +767,7 @@ public boolean updateUuid(long srcVolId, long destVolId) {
destVol.setInstanceId(instanceId);
update(srcVolId, srcVol);
update(destVolId, destVol);
_tagsDao.updateResourceId(srcVolId, destVolId, ResourceObjectType.Volume);
tagsDao.updateResourceId(srcVolId, destVolId, ResourceObjectType.Volume);
} catch (Exception e) {
throw new CloudRuntimeException("Unable to persist the sequence number for this host");
}
Expand Down Expand Up @@ -841,4 +866,13 @@ public List<VolumeVO> listByIds(List<Long> ids) {
sc.setParameters("idIN", ids.toArray());
return listBy(sc, null);
}

@Override
public List<VolumeVO> listByPoolIdVMStatesNotInCluster(long clusterId, List<VirtualMachine.State> states, long poolId) {
SearchCriteria<VolumeVO> sc = volumePoolNotInClusterSearch.create();
sc.setParameters("poolId", poolId);
sc.setJoinParameters("vmSearch", "vmStates", states);
sc.setJoinParameters("hostSearch", "clusterId", clusterId);
return listBy(sc, null);
}
}
Loading
Loading