This is an automated email from the ASF dual-hosted git repository.

sureshanaparti pushed a commit to branch 4.19
in repository https://gitbox.apache.org/repos/asf/cloudstack.git


The following commit(s) were added to refs/heads/4.19 by this push:
     new 063dc601140 Change storage pool scope from Cluster to Zone and vise 
versa (#8875)
063dc601140 is described below

commit 063dc6011403101c10382d3e950951c96b97755c
Author: Abhisar Sinha <63767682+abh1...@users.noreply.github.com>
AuthorDate: Sat Jun 29 10:03:34 2024 +0530

    Change storage pool scope from Cluster to Zone and vise versa (#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 <sureshkumar.anapa...@gmail.com>
---
 api/src/main/java/com/cloud/event/EventTypes.java  |   2 +
 .../java/com/cloud/storage/StorageService.java     |   4 +
 .../admin/storage/ChangeStoragePoolScopeCmd.java   |  98 +++++++++
 .../ListAffectedVmsForStorageScopeChangeCmd.java   |  77 +++++++
 .../api/response/VirtualMachineResponse.java       | 124 ++++++++++++
 .../org/apache/cloudstack/query/QueryService.java  |   4 +
 .../api/storage/PrimaryDataStoreLifeCycle.java     |   3 +
 .../java/com/cloud/resource/ResourceManager.java   |   4 +
 .../main/java/com/cloud/capacity/CapacityVO.java   |   8 +-
 .../com/cloud/storage/dao/StoragePoolHostDao.java  |   2 +
 .../cloud/storage/dao/StoragePoolHostDaoImpl.java  |  28 +++
 .../java/com/cloud/storage/dao/VolumeDaoImpl.java  |   8 +-
 .../main/java/com/cloud/vm/dao/VMInstanceDao.java  |   2 +
 .../java/com/cloud/vm/dao/VMInstanceDaoImpl.java   |  39 +++-
 .../volume/datastore/PrimaryDataStoreHelper.java   |  57 +++++-
 .../datastore/PrimaryDataStoreHelperTest.java      | 114 +++++++++++
 .../BasePrimaryDataStoreLifeCycleImpl.java         | 106 ++++++++++
 .../BasePrimaryDataStoreLifeCycleImplTest.java     | 127 ++++++++++++
 .../lifecycle/AdaptiveDataStoreLifeCycleImpl.java  |   2 +-
 .../ElastistorPrimaryDataStoreLifeCycle.java       |   2 +-
 .../lifecycle/DateraPrimaryDataStoreLifeCycle.java |  17 +-
 .../CloudStackPrimaryDataStoreLifeCycleImpl.java   |   2 +-
 .../LinstorPrimaryDataStoreLifeCycleImpl.java      |   2 +-
 .../NexentaPrimaryDataStoreLifeCycle.java          |  11 +
 .../SamplePrimaryDataStoreLifeCycleImpl.java       |   8 +
 .../ScaleIOPrimaryDataStoreLifeCycle.java          |   2 +-
 .../SolidFirePrimaryDataStoreLifeCycle.java        |  11 +-
 .../SolidFireSharedPrimaryDataStoreLifeCycle.java  |   2 +-
 .../StorPoolPrimaryDataStoreLifeCycle.java         |   2 +-
 .../java/com/cloud/api/query/QueryManagerImpl.java |  60 ++++++
 .../com/cloud/resource/ResourceManagerImpl.java    |  20 ++
 .../com/cloud/server/ManagementServerImpl.java     |   4 +
 .../java/com/cloud/storage/StorageManagerImpl.java | 118 ++++++++++-
 .../com/cloud/api/query/QueryManagerImplTest.java  |  72 +++++++
 .../cloud/resource/MockResourceManagerImpl.java    |  11 +
 .../com/cloud/storage/StorageManagerImplTest.java  | 111 ++++++++--
 .../smoke/test_primary_storage_scope.py            | 176 ++++++++++++++++
 tools/apidoc/gen_toc.py                            |   1 +
 ui/public/locales/en.json                          |   7 +
 ui/src/config/section/infra/primaryStorages.js     |  20 ++
 ui/src/core/lazy_lib/icons_use.js                  |   2 +
 ui/src/views/infra/ChangeStoragePoolScope.vue      | 223 +++++++++++++++++++++
 42 files changed, 1642 insertions(+), 51 deletions(-)

diff --git a/api/src/main/java/com/cloud/event/EventTypes.java 
b/api/src/main/java/com/cloud/event/EventTypes.java
index 689676290b3..496d9f5b689 100644
--- a/api/src/main/java/com/cloud/event/EventTypes.java
+++ b/api/src/main/java/com/cloud/event/EventTypes.java
@@ -451,6 +451,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";
@@ -1000,6 +1001,7 @@ public class EventTypes {
         // Primary storage pool
         entityEventDetails.put(EVENT_ENABLE_PRIMARY_STORAGE, 
StoragePool.class);
         entityEventDetails.put(EVENT_DISABLE_PRIMARY_STORAGE, 
StoragePool.class);
+        entityEventDetails.put(EVENT_CHANGE_STORAGE_POOL_SCOPE, 
StoragePool.class);
 
         // VPN
         entityEventDetails.put(EVENT_REMOTE_ACCESS_VPN_CREATE, 
RemoteAccessVpn.class);
diff --git a/api/src/main/java/com/cloud/storage/StorageService.java 
b/api/src/main/java/com/cloud/storage/StorageService.java
index 77800d8955c..1ce335b0115 100644
--- a/api/src/main/java/com/cloud/storage/StorageService.java
+++ b/api/src/main/java/com/cloud/storage/StorageService.java
@@ -21,6 +21,7 @@ import java.net.UnknownHostException;
 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;
@@ -35,6 +36,7 @@ import 
org.apache.cloudstack.api.command.admin.storage.UpdateStoragePoolCmd;
 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;
@@ -130,4 +132,6 @@ public interface StorageService {
     boolean deleteObjectStore(DeleteObjectStoragePoolCmd cmd);
 
     ObjectStore updateObjectStore(Long id, UpdateObjectStoragePoolCmd cmd);
+
+    void changeStoragePoolScope(ChangeStoragePoolScopeCmd cmd) throws 
IllegalArgumentException, InvalidParameterValueException, 
PermissionDeniedException;
 }
diff --git 
a/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/ChangeStoragePoolScopeCmd.java
 
b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/ChangeStoragePoolScopeCmd.java
new file mode 100644
index 00000000000..d3b6a074610
--- /dev/null
+++ 
b/api/src/main/java/org/apache/cloudstack/api/command/admin/storage/ChangeStoragePoolScopeCmd.java
@@ -0,0 +1,98 @@
+// 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.ApiCommandResourceType;
+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;
+import com.cloud.storage.StoragePool;
+
+@APICommand(name = "changeStoragePoolScope", description = "Changes the scope 
of a storage pool when the pool is in Disabled state." +
+        "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 ApiCommandResourceType getApiResourceType() {
+        return ApiCommandResourceType.StoragePool;
+    }
+
+    @Override
+    public Long getApiResourceId() {
+        return getId();
+    }
+
+    public String getEventType() {
+        return EventTypes.EVENT_CHANGE_STORAGE_POOL_SCOPE;
+    }
+
+    @Override
+    public String getEventDescription() {
+        String description = "Change storage pool scope. Storage pool Id: ";
+        StoragePool pool = _entityMgr.findById(StoragePool.class, getId());
+        if (pool != null) {
+            description += pool.getUuid();
+        } else {
+            description += getId();
+        }
+        description += " to " + getScope();
+        return description;
+    }
+
+    @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;
+    }
+}
diff --git 
a/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ListAffectedVmsForStorageScopeChangeCmd.java
 
b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ListAffectedVmsForStorageScopeChangeCmd.java
new file mode 100644
index 00000000000..d586a81b685
--- /dev/null
+++ 
b/api/src/main/java/org/apache/cloudstack/api/command/admin/vm/ListAffectedVmsForStorageScopeChangeCmd.java
@@ -0,0 +1,77 @@
+/*
+ * 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.vm;
+
+import org.apache.cloudstack.acl.RoleType;
+import org.apache.cloudstack.api.APICommand;
+import org.apache.cloudstack.api.ApiConstants;
+import org.apache.cloudstack.api.BaseListCmd;
+import org.apache.cloudstack.api.Parameter;
+import org.apache.cloudstack.api.response.ClusterResponse;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.StoragePoolResponse;
+import org.apache.cloudstack.api.response.VirtualMachineResponse;
+
+import com.cloud.vm.VirtualMachine;
+
+@APICommand(name = "listAffectedVmsForStorageScopeChange",
+        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.",
+        responseObject = VirtualMachineResponse.class,
+        requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, 
since = "4.19.1",
+        authorized = {RoleType.Admin})
+public class ListAffectedVmsForStorageScopeChangeCmd extends BaseListCmd {
+
+    @Parameter(name = ApiConstants.CLUSTER_ID,
+            type = CommandType.UUID,
+            entityType = ClusterResponse.class,
+            required = true,
+            description = "the Id of the cluster the scope of the storage pool 
is being changed to")
+    private Long clusterIdForScopeChange;
+
+    @Parameter(name = ApiConstants.STORAGE_ID,
+            type = CommandType.UUID,
+            entityType = StoragePoolResponse.class,
+            required = true,
+            description = "the Id of the storage pool on which change scope 
operation is being done")
+    private Long storageId;
+
+    /////////////////////////////////////////////////////
+    /////////////////// Accessors ///////////////////////
+    /////////////////////////////////////////////////////
+
+    public Long getClusterIdForScopeChange() {
+        return clusterIdForScopeChange;
+    }
+
+    public Long getStorageId() {
+        return storageId;
+    }
+
+    /////////////////////////////////////////////////////
+    /////////////// API Implementation///////////////////
+    /////////////////////////////////////////////////////
+
+    @Override
+    public void execute() {
+        ListResponse<VirtualMachineResponse> response = 
_queryService.listAffectedVmsForStorageScopeChange(this);
+        response.setResponseName(getCommandName());
+        
response.setObjectName(VirtualMachine.class.getSimpleName().toLowerCase());
+        setResponseObject(response);
+    }
+}
diff --git 
a/api/src/main/java/org/apache/cloudstack/api/response/VirtualMachineResponse.java
 
b/api/src/main/java/org/apache/cloudstack/api/response/VirtualMachineResponse.java
new file mode 100644
index 00000000000..7d676292b8a
--- /dev/null
+++ 
b/api/src/main/java/org/apache/cloudstack/api/response/VirtualMachineResponse.java
@@ -0,0 +1,124 @@
+// 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.response;
+
+import org.apache.cloudstack.api.BaseResponse;
+import org.apache.cloudstack.api.EntityReference;
+
+import com.cloud.serializer.Param;
+import com.cloud.vm.VirtualMachine;
+import com.google.gson.annotations.SerializedName;
+
+@EntityReference(value = VirtualMachine.class)
+public class VirtualMachineResponse extends BaseResponse {
+    @SerializedName("id")
+    @Param(description = "the ID of the VM")
+    private String id;
+
+    @SerializedName("type")
+    @Param(description = "the type of VM")
+    private String type;
+
+    @SerializedName("name")
+    @Param(description = "the name of the VM")
+    private String name;
+
+    @SerializedName("clusterid")
+    @Param(description = "the cluster ID for the VM")
+    private String clusterId;
+
+    @SerializedName("clustername")
+    @Param(description = "the cluster name for the VM")
+    private String clusterName;
+
+    @SerializedName("hostid")
+    @Param(description = "the host ID for the VM")
+    private String hostId;
+
+    @SerializedName("hostname")
+    @Param(description = "the hostname for the VM")
+    private String hostName;
+
+    @Override
+    public String getObjectId() {
+        return this.getId();
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getVmType() {
+        return type;
+    }
+
+    public void setVmType(String type) {
+        this.type = type;
+    }
+
+    public String getVmName() {
+        return name;
+    }
+
+    public void setVmName(String name) {
+        this.name = name;
+    }
+
+    public String getClusterId() {
+        return clusterId;
+    }
+
+    public void setClusterId(String clusterId) {
+        this.clusterId = clusterId;
+    }
+
+    public String getClusterName() {
+        return clusterName;
+    }
+
+    public void setClusterName(String clusterName) {
+        this.clusterName = clusterName;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getHostId() {
+        return hostId;
+    }
+
+    public void setHostId(String hostId) {
+        this.hostId = hostId;
+    }
+
+    public String getHostName() {
+        return hostName;
+    }
+
+    public void setHostName(String hostName) {
+        this.hostName = hostName;
+    }
+}
diff --git a/api/src/main/java/org/apache/cloudstack/query/QueryService.java 
b/api/src/main/java/org/apache/cloudstack/query/QueryService.java
index 4c53314aef5..c93e43d9f37 100644
--- a/api/src/main/java/org/apache/cloudstack/query/QueryService.java
+++ b/api/src/main/java/org/apache/cloudstack/query/QueryService.java
@@ -52,6 +52,7 @@ import 
org.apache.cloudstack.api.command.user.snapshot.CopySnapshotCmd;
 import org.apache.cloudstack.api.command.user.snapshot.ListSnapshotsCmd;
 import org.apache.cloudstack.api.command.user.tag.ListTagsCmd;
 import org.apache.cloudstack.api.command.user.template.ListTemplatesCmd;
+import 
org.apache.cloudstack.api.command.admin.vm.ListAffectedVmsForStorageScopeChangeCmd;
 import org.apache.cloudstack.api.command.user.vm.ListVMsCmd;
 import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd;
 import org.apache.cloudstack.api.command.user.volume.ListResourceDetailsCmd;
@@ -89,6 +90,7 @@ import org.apache.cloudstack.api.response.StorageTagResponse;
 import org.apache.cloudstack.api.response.TemplateResponse;
 import org.apache.cloudstack.api.response.UserResponse;
 import org.apache.cloudstack.api.response.UserVmResponse;
+import org.apache.cloudstack.api.response.VirtualMachineResponse;
 import org.apache.cloudstack.api.response.VolumeResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
 import org.apache.cloudstack.framework.config.ConfigKey;
@@ -140,6 +142,8 @@ public interface QueryService {
 
     ListResponse<UserVmResponse> searchForUserVMs(ListVMsCmd cmd);
 
+    ListResponse<VirtualMachineResponse> 
listAffectedVmsForStorageScopeChange(ListAffectedVmsForStorageScopeChangeCmd 
cmd);
+
     ListResponse<SecurityGroupResponse> 
searchForSecurityGroups(ListSecurityGroupsCmd cmd);
 
     ListResponse<DomainRouterResponse> searchForRouters(ListRoutersCmd cmd);
diff --git 
a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreLifeCycle.java
 
b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreLifeCycle.java
index fcbc19c28b7..54f3c63f8d7 100644
--- 
a/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreLifeCycle.java
+++ 
b/engine/api/src/main/java/org/apache/cloudstack/engine/subsystem/api/storage/PrimaryDataStoreLifeCycle.java
@@ -20,6 +20,7 @@ package org.apache.cloudstack.engine.subsystem.api.storage;
 
 import java.util.Map;
 
+import com.cloud.hypervisor.Hypervisor;
 import com.cloud.storage.StoragePool;
 
 public interface PrimaryDataStoreLifeCycle extends DataStoreLifeCycle {
@@ -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);
 }
diff --git 
a/engine/components-api/src/main/java/com/cloud/resource/ResourceManager.java 
b/engine/components-api/src/main/java/com/cloud/resource/ResourceManager.java
index 91197de6a84..b2ae8b89837 100755
--- 
a/engine/components-api/src/main/java/com/cloud/resource/ResourceManager.java
+++ 
b/engine/components-api/src/main/java/com/cloud/resource/ResourceManager.java
@@ -134,6 +134,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);
diff --git a/engine/schema/src/main/java/com/cloud/capacity/CapacityVO.java 
b/engine/schema/src/main/java/com/cloud/capacity/CapacityVO.java
index 50c40134a91..29b58ddccd4 100644
--- a/engine/schema/src/main/java/com/cloud/capacity/CapacityVO.java
+++ b/engine/schema/src/main/java/com/cloud/capacity/CapacityVO.java
@@ -132,8 +132,8 @@ public class CapacityVO implements Capacity {
         return podId;
     }
 
-    public void setPodId(long podId) {
-        this.podId = new Long(podId);
+    public void setPodId(Long podId) {
+        this.podId = podId;
     }
 
     @Override
@@ -141,8 +141,8 @@ public class CapacityVO implements Capacity {
         return clusterId;
     }
 
-    public void setClusterId(long clusterId) {
-        this.clusterId = new Long(clusterId);
+    public void setClusterId(Long clusterId) {
+        this.clusterId = clusterId;
     }
 
     @Override
diff --git 
a/engine/schema/src/main/java/com/cloud/storage/dao/StoragePoolHostDao.java 
b/engine/schema/src/main/java/com/cloud/storage/dao/StoragePoolHostDao.java
index b099a6d6bdb..62ef5b7570d 100644
--- a/engine/schema/src/main/java/com/cloud/storage/dao/StoragePoolHostDao.java
+++ b/engine/schema/src/main/java/com/cloud/storage/dao/StoragePoolHostDao.java
@@ -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);
 }
diff --git 
a/engine/schema/src/main/java/com/cloud/storage/dao/StoragePoolHostDaoImpl.java 
b/engine/schema/src/main/java/com/cloud/storage/dao/StoragePoolHostDaoImpl.java
index c27aeb0f652..03da0405142 100644
--- 
a/engine/schema/src/main/java/com/cloud/storage/dao/StoragePoolHostDaoImpl.java
+++ 
b/engine/schema/src/main/java/com/cloud/storage/dao/StoragePoolHostDaoImpl.java
@@ -23,13 +23,19 @@ import java.util.ArrayList;
 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;
@@ -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 (?)";
@@ -70,6 +81,15 @@ public class StoragePoolHostDaoImpl extends 
GenericDaoBase<StoragePoolHostVO, Lo
 
     }
 
+    @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();
@@ -196,4 +216,12 @@ public class StoragePoolHostDaoImpl extends 
GenericDaoBase<StoragePoolHostVO, Lo
         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);
+    }
 }
diff --git 
a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java 
b/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java
index 3a3c02d83b4..9907af76769 100644
--- a/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/storage/dao/VolumeDaoImpl.java
@@ -72,8 +72,9 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, 
Long> implements Vol
     protected GenericSearchBuilder<VolumeVO, SumCount> primaryStorageSearch2;
     protected GenericSearchBuilder<VolumeVO, SumCount> secondaryStorageSearch;
     private final SearchBuilder<VolumeVO> poolAndPathSearch;
+
     @Inject
-    ResourceTagDao _tagsDao;
+    ResourceTagDao tagsDao;
 
     // need to account for zone-wide primary storage where storage_pool has
     // null-value pod and cluster, where hypervisor information is stored in
@@ -493,7 +494,6 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, 
Long> implements Vol
         poolAndPathSearch.and("poolId", 
poolAndPathSearch.entity().getPoolId(), Op.EQ);
         poolAndPathSearch.and("path", poolAndPathSearch.entity().getPath(), 
Op.EQ);
         poolAndPathSearch.done();
-
     }
 
     @Override
@@ -719,7 +719,7 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, 
Long> implements Vol
         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);
 
@@ -742,7 +742,7 @@ public class VolumeDaoImpl extends GenericDaoBase<VolumeVO, 
Long> implements Vol
             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");
         }
diff --git a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java 
b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java
index 42c00231aac..63f7ad974e6 100755
--- a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDao.java
@@ -165,4 +165,6 @@ public interface VMInstanceDao extends 
GenericDao<VMInstanceVO, Long>, StateDao<
     void updateSystemVmTemplateId(long templateId, Hypervisor.HypervisorType 
hypervisorType);
 
     List<VMInstanceVO> listByHostOrLastHostOrHostPod(List<Long> hostIds, long 
podId);
+
+    Pair<List<VMInstanceVO>, Integer> listByVmsNotInClusterUsingPool(long 
clusterId, long poolId);
 }
diff --git 
a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java 
b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java
index 322895f0ec5..e41c706a9cb 100755
--- a/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java
+++ b/engine/schema/src/main/java/com/cloud/vm/dao/VMInstanceDaoImpl.java
@@ -24,6 +24,7 @@ import java.util.Date;
 import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 import javax.annotation.PostConstruct;
 import javax.inject.Inject;
@@ -35,6 +36,8 @@ import com.cloud.host.HostVO;
 import com.cloud.host.dao.HostDao;
 import com.cloud.hypervisor.Hypervisor;
 import com.cloud.server.ResourceTag.ResourceObjectType;
+import com.cloud.storage.VolumeVO;
+import com.cloud.storage.dao.VolumeDao;
 import com.cloud.tags.dao.ResourceTagDao;
 import com.cloud.utils.DateUtil;
 import com.cloud.utils.Pair;
@@ -97,11 +100,16 @@ public class VMInstanceDaoImpl extends 
GenericDaoBase<VMInstanceVO, Long> implem
     protected SearchBuilder<VMInstanceVO> NotMigratingSearch;
     protected SearchBuilder<VMInstanceVO> BackupSearch;
     protected SearchBuilder<VMInstanceVO> LastHostAndStatesSearch;
+    protected SearchBuilder<VMInstanceVO> VmsNotInClusterUsingPool;
 
     @Inject
-    ResourceTagDao _tagsDao;
+    ResourceTagDao tagsDao;
     @Inject
-    NicDao _nicDao;
+    NicDao nicDao;
+    @Inject
+    VolumeDao volumeDao;
+    @Inject
+    HostDao hostDao;
 
     protected Attribute _updateTimeAttr;
 
@@ -278,7 +286,7 @@ public class VMInstanceDaoImpl extends 
GenericDaoBase<VMInstanceVO, Long> implem
         _updateTimeAttr = _allAttributes.get("updateTime");
         assert _updateTimeAttr != null : "Couldn't get this updateTime 
attribute";
 
-        SearchBuilder<NicVO> nicSearch = _nicDao.createSearchBuilder();
+        SearchBuilder<NicVO> nicSearch = nicDao.createSearchBuilder();
         nicSearch.and("networkId", nicSearch.entity().getNetworkId(), 
SearchCriteria.Op.EQ);
         nicSearch.and("removedNic", nicSearch.entity().getRemoved(), 
SearchCriteria.Op.NULL);
 
@@ -307,6 +315,16 @@ public class VMInstanceDaoImpl extends 
GenericDaoBase<VMInstanceVO, Long> implem
         LastHostAndStatesSearch.and("states", 
LastHostAndStatesSearch.entity().getState(), Op.IN);
         LastHostAndStatesSearch.done();
 
+        VmsNotInClusterUsingPool = createSearchBuilder();
+        SearchBuilder<VolumeVO> volumeSearch = volumeDao.createSearchBuilder();
+        volumeSearch.and("poolId", volumeSearch.entity().getPoolId(), Op.EQ);
+        volumeSearch.and("removed", volumeSearch.entity().getRemoved(), 
Op.NULL);
+        VmsNotInClusterUsingPool.join("volumeSearch", volumeSearch, 
volumeSearch.entity().getInstanceId(), 
VmsNotInClusterUsingPool.entity().getId(), JoinType.INNER);
+        SearchBuilder<HostVO> hostSearch2 = hostDao.createSearchBuilder();
+        hostSearch2.and("clusterId", hostSearch2.entity().getClusterId(), 
SearchCriteria.Op.NEQ);
+        VmsNotInClusterUsingPool.join("hostSearch2", hostSearch2, 
hostSearch2.entity().getId(), VmsNotInClusterUsingPool.entity().getHostId(), 
JoinType.INNER);
+        VmsNotInClusterUsingPool.and("vmStates", 
VmsNotInClusterUsingPool.entity().getState(), Op.IN);
+        VmsNotInClusterUsingPool.done();
     }
 
     @Override
@@ -836,7 +854,7 @@ public class VMInstanceDaoImpl extends 
GenericDaoBase<VMInstanceVO, Long> implem
     public List<VMInstanceVO> listNonRemovedVmsByTypeAndNetwork(long 
networkId, VirtualMachine.Type... types) {
         if (NetworkTypeSearch == null) {
 
-            SearchBuilder<NicVO> nicSearch = _nicDao.createSearchBuilder();
+            SearchBuilder<NicVO> nicSearch = nicDao.createSearchBuilder();
             nicSearch.and("networkId", nicSearch.entity().getNetworkId(), 
SearchCriteria.Op.EQ);
 
             NetworkTypeSearch = createSearchBuilder();
@@ -873,7 +891,7 @@ public class VMInstanceDaoImpl extends 
GenericDaoBase<VMInstanceVO, Long> implem
         txn.start();
         VMInstanceVO vm = findById(id);
         if (vm != null && vm.getType() == Type.User) {
-            _tagsDao.removeByIdAndType(id, ResourceObjectType.UserVm);
+            tagsDao.removeByIdAndType(id, ResourceObjectType.UserVm);
         }
         boolean result = super.remove(id);
         txn.commit();
@@ -1018,4 +1036,15 @@ public class VMInstanceDaoImpl extends 
GenericDaoBase<VMInstanceVO, Long> implem
         sc.setParameters("podId", String.valueOf(podId));
         return listBy(sc);
     }
+
+    @Override
+    public Pair<List<VMInstanceVO>, Integer> 
listByVmsNotInClusterUsingPool(long clusterId, long poolId) {
+        SearchCriteria<VMInstanceVO> sc = VmsNotInClusterUsingPool.create();
+        sc.setParameters("vmStates", State.Starting, State.Running, 
State.Stopping, State.Migrating, State.Restoring);
+        sc.setJoinParameters("volumeSearch", "poolId", poolId);
+        sc.setJoinParameters("hostSearch2", "clusterId", clusterId);
+        List<VMInstanceVO> vms = search(sc, null);
+        List<VMInstanceVO> uniqueVms = 
vms.stream().distinct().collect(Collectors.toList());
+        return new Pair<>(uniqueVms, uniqueVms.size());
+    }
 }
diff --git 
a/engine/storage/src/main/java/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java
 
b/engine/storage/src/main/java/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java
index fbb4a6e1618..216d6042f36 100644
--- 
a/engine/storage/src/main/java/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java
+++ 
b/engine/storage/src/main/java/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelper.java
@@ -28,31 +28,34 @@ import javax.inject.Inject;
 
 import org.apache.cloudstack.annotation.AnnotationService;
 import org.apache.cloudstack.annotation.dao.AnnotationDao;
-import org.apache.log4j.Logger;
-import org.springframework.stereotype.Component;
-
+import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStoreManager;
 import org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
 import 
org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
+import org.apache.log4j.Logger;
+import org.springframework.stereotype.Component;
 
 import com.cloud.agent.api.StoragePoolInfo;
 import com.cloud.capacity.Capacity;
 import com.cloud.capacity.CapacityVO;
 import com.cloud.capacity.dao.CapacityDao;
-import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.storage.DataStoreRole;
 import com.cloud.storage.ScopeType;
+import com.cloud.storage.Storage.StoragePoolType;
 import com.cloud.storage.StorageManager;
 import com.cloud.storage.StoragePoolHostVO;
 import com.cloud.storage.StoragePoolStatus;
-import com.cloud.storage.Storage.StoragePoolType;
 import com.cloud.storage.dao.StoragePoolHostDao;
 import com.cloud.utils.crypt.DBEncryptionUtil;
+import com.cloud.utils.db.Transaction;
+import com.cloud.utils.db.TransactionCallbackNoReturn;
 import com.cloud.utils.db.TransactionLegacy;
+import com.cloud.utils.db.TransactionStatus;
 import com.cloud.utils.exception.CloudRuntimeException;
 
 @Component
@@ -265,4 +268,48 @@ public class PrimaryDataStoreHelper {
         return true;
     }
 
+    public void switchToZone(DataStore store, HypervisorType hypervisorType) {
+        StoragePoolVO pool = dataStoreDao.findById(store.getId());
+        CapacityVO capacity = _capacityDao.findByHostIdType(store.getId(), 
Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED);
+        Transaction.execute(new TransactionCallbackNoReturn() {
+            public void doInTransactionWithoutResult(TransactionStatus status) 
{
+                pool.setScope(ScopeType.ZONE);
+                pool.setPodId(null);
+                pool.setClusterId(null);
+                pool.setHypervisor(hypervisorType);
+                dataStoreDao.update(pool.getId(), pool);
+
+                capacity.setPodId(null);
+                capacity.setClusterId(null);
+                _capacityDao.update(capacity.getId(), capacity);
+            }
+        });
+        s_logger.debug("Scope of storage pool id=" + pool.getId() + " is 
changed to zone");
+    }
+
+    public void switchToCluster(DataStore store, ClusterScope clusterScope) {
+        List<StoragePoolHostVO> hostPoolRecords = 
storagePoolHostDao.listByPoolIdNotInCluster(clusterScope.getScopeId(), 
store.getId()).first();
+        StoragePoolVO pool = dataStoreDao.findById(store.getId());
+        CapacityVO capacity = _capacityDao.findByHostIdType(store.getId(), 
Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED);
+
+        Transaction.execute(new TransactionCallbackNoReturn() {
+            @Override
+            public void doInTransactionWithoutResult(TransactionStatus status) 
{
+                if (hostPoolRecords != null) {
+                    for (StoragePoolHostVO host : hostPoolRecords) {
+                        
storagePoolHostDao.deleteStoragePoolHostDetails(host.getHostId(), 
host.getPoolId());
+                    }
+                }
+                pool.setScope(ScopeType.CLUSTER);
+                pool.setPodId(clusterScope.getPodId());
+                pool.setClusterId(clusterScope.getScopeId());
+                dataStoreDao.update(pool.getId(), pool);
+
+                capacity.setPodId(clusterScope.getPodId());
+                capacity.setClusterId(clusterScope.getScopeId());
+                _capacityDao.update(capacity.getId(), capacity);
+            }
+        });
+        s_logger.debug("Scope of storage pool id=" + pool.getId() + " is 
changed to cluster id=" + clusterScope.getScopeId());
+    }
 }
diff --git 
a/engine/storage/src/test/java/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelperTest.java
 
b/engine/storage/src/test/java/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelperTest.java
new file mode 100644
index 00000000000..3927b43f393
--- /dev/null
+++ 
b/engine/storage/src/test/java/org/apache/cloudstack/storage/volume/datastore/PrimaryDataStoreHelperTest.java
@@ -0,0 +1,114 @@
+// 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.storage.volume.datastore;
+
+import java.util.List;
+
+import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
+import org.junit.Assert;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+
+import com.cloud.capacity.Capacity;
+import com.cloud.capacity.CapacityVO;
+import com.cloud.capacity.dao.CapacityDao;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.storage.ScopeType;
+import com.cloud.storage.Storage;
+import com.cloud.storage.StoragePoolHostVO;
+import com.cloud.storage.dao.StoragePoolHostDao;
+import com.cloud.utils.Pair;
+
+@RunWith(MockitoJUnitRunner.class)
+public class PrimaryDataStoreHelperTest {
+
+    @Mock
+    private PrimaryDataStoreDao dataStoreDao;
+
+    @Mock
+    private CapacityDao capacityDao;
+
+    @Mock
+    private StoragePoolHostDao storagePoolHostDao;
+
+    @Spy
+    @InjectMocks
+    PrimaryDataStoreHelper dataStoreHelper;
+
+    private static final Long ZONE_ID = 1L;
+    private static final Long CLUSTER_ID = 2L;
+    private static final Long POD_ID = 3L;
+    private static final Long POOL_ID = 4L;
+    private static final Short capacityType = 0;
+    private static final Float usedPercentage = 0.0f;
+
+    @Test
+    public void testSwitchToZone() {
+        StoragePoolVO pool = new StoragePoolVO(POOL_ID, null, null, 
Storage.StoragePoolType.NetworkFilesystem, ZONE_ID, POD_ID, 0L, 0L, null, 0, 
null);
+        pool.setClusterId(CLUSTER_ID);
+        pool.setScope(ScopeType.CLUSTER);
+        CapacityVO capacity = new CapacityVO(ZONE_ID, POD_ID, CLUSTER_ID, 
capacityType, usedPercentage);
+
+        Mockito.when(dataStoreDao.findById(pool.getId())).thenReturn(pool);
+        Mockito.when(capacityDao.findByHostIdType(pool.getId(), 
Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED)).thenReturn(capacity);
+        DataStore storeMock = Mockito.mock(DataStore.class);
+        Mockito.when(storeMock.getId()).thenReturn(POOL_ID);
+
+        dataStoreHelper.switchToZone(storeMock, HypervisorType.KVM);
+
+        Assert.assertEquals(pool.getScope(), ScopeType.ZONE);
+        Assert.assertEquals(pool.getPodId(), null);
+        Assert.assertEquals(pool.getClusterId(), null);
+        Assert.assertEquals(pool.getHypervisor(), HypervisorType.KVM);
+        Assert.assertEquals(capacity.getPodId(), null);
+        Assert.assertEquals(capacity.getClusterId(), null);
+    }
+
+    @Test
+    public void testSwitchToCluster() {
+        StoragePoolVO pool = new StoragePoolVO(POOL_ID, null, null, 
Storage.StoragePoolType.NetworkFilesystem, ZONE_ID, null, 0L, 0L, null, 0, 
null);
+        pool.setScope(ScopeType.ZONE);
+        CapacityVO capacity = new CapacityVO(ZONE_ID, null, null, 
capacityType, usedPercentage);
+        ClusterScope clusterScope = new ClusterScope(CLUSTER_ID, POD_ID, 
ZONE_ID);
+
+        Pair<List<StoragePoolHostVO>, Integer> hostPoolRecords = new 
Pair<>(null, 0);
+        Mockito.when(storagePoolHostDao.listByPoolIdNotInCluster(CLUSTER_ID, 
POOL_ID)).thenReturn(hostPoolRecords);
+        Mockito.when(dataStoreDao.findById(pool.getId())).thenReturn(pool);
+        Mockito.when(capacityDao.findByHostIdType(pool.getId(), 
Capacity.CAPACITY_TYPE_STORAGE_ALLOCATED)).thenReturn(capacity);
+        DataStore storeMock = Mockito.mock(DataStore.class);
+        Mockito.when(storeMock.getId()).thenReturn(POOL_ID);
+
+        dataStoreHelper.switchToCluster(storeMock, clusterScope);
+
+        Mockito.verify(storagePoolHostDao, 
Mockito.never()).deleteStoragePoolHostDetails(Mockito.anyLong(), 
Mockito.anyLong());
+
+        Assert.assertEquals(pool.getScope(), ScopeType.CLUSTER);
+        Assert.assertEquals(pool.getPodId(), POD_ID);
+        Assert.assertEquals(pool.getClusterId(), CLUSTER_ID);
+        Assert.assertEquals(capacity.getPodId(), POD_ID);
+        Assert.assertEquals(capacity.getClusterId(), CLUSTER_ID);
+    }
+}
diff --git 
a/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/BasePrimaryDataStoreLifeCycleImpl.java
 
b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/BasePrimaryDataStoreLifeCycleImpl.java
new file mode 100644
index 00000000000..adc74a77d43
--- /dev/null
+++ 
b/engine/storage/volume/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/BasePrimaryDataStoreLifeCycleImpl.java
@@ -0,0 +1,106 @@
+// 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.storage.datastore.lifecycle;
+
+import java.util.Arrays;
+import java.util.List;
+
+import javax.inject.Inject;
+
+import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
+import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
+import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
+import org.apache.log4j.Logger;
+
+import com.cloud.agent.AgentManager;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.DeleteStoragePoolCommand;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.resource.ResourceManager;
+import com.cloud.storage.StorageManager;
+import com.cloud.storage.StoragePool;
+import com.cloud.storage.StoragePoolHostVO;
+import com.cloud.storage.dao.StoragePoolHostDao;
+import com.cloud.utils.Pair;
+
+public class BasePrimaryDataStoreLifeCycleImpl {
+    private static final Logger s_logger = 
Logger.getLogger(BasePrimaryDataStoreLifeCycleImpl.class);
+    @Inject
+    AgentManager agentMgr;
+    @Inject
+    protected ResourceManager resourceMgr;
+    @Inject
+    StorageManager storageMgr;
+    @Inject
+    PrimaryDataStoreHelper dataStoreHelper;
+    @Inject
+    protected HostDao hostDao;
+    @Inject
+    protected StoragePoolHostDao storagePoolHostDao;
+
+    private List<HostVO> getPoolHostsList(ClusterScope clusterScope, 
HypervisorType hypervisorType) {
+        List<HostVO> hosts;
+        if (hypervisorType != null) {
+             hosts = resourceMgr
+                    
.listAllHostsInOneZoneNotInClusterByHypervisor(hypervisorType, 
clusterScope.getZoneId(), clusterScope.getScopeId());
+        } else {
+            List<HypervisorType> hypervisorTypes = 
Arrays.asList(HypervisorType.KVM, HypervisorType.VMware);
+            hosts = resourceMgr
+                    
.listAllHostsInOneZoneNotInClusterByHypervisors(hypervisorTypes, 
clusterScope.getZoneId(), clusterScope.getScopeId());
+        }
+        return hosts;
+    }
+
+    public void changeStoragePoolScopeToZone(DataStore store, ClusterScope 
clusterScope, HypervisorType hypervisorType) {
+        List<HostVO> hosts = getPoolHostsList(clusterScope, hypervisorType);
+        s_logger.debug("Changing scope of the storage pool to Zone");
+        if (hosts != null) {
+            for (HostVO host : hosts) {
+                try {
+                    storageMgr.connectHostToSharedPool(host.getId(), 
store.getId());
+                } catch (Exception e) {
+                    s_logger.warn("Unable to establish a connection between " 
+ host + " and " + store, e);
+                }
+            }
+        }
+        dataStoreHelper.switchToZone(store, hypervisorType);
+    }
+
+    public void changeStoragePoolScopeToCluster(DataStore store, ClusterScope 
clusterScope, HypervisorType hypervisorType) {
+        Pair<List<StoragePoolHostVO>, Integer> hostPoolRecords = 
storagePoolHostDao.listByPoolIdNotInCluster(clusterScope.getScopeId(), 
store.getId());
+        s_logger.debug("Changing scope of the storage pool to Cluster");
+        if (hostPoolRecords.second() > 0) {
+            StoragePool pool = (StoragePool) store;
+            for (StoragePoolHostVO host : hostPoolRecords.first()) {
+                DeleteStoragePoolCommand deleteCmd = new 
DeleteStoragePoolCommand(pool);
+                final Answer answer = agentMgr.easySend(host.getHostId(), 
deleteCmd);
+
+                if (answer != null) {
+                    if (!answer.getResult()) {
+                        s_logger.debug("Failed to delete storage pool: " + 
answer.getResult());
+                    } else if (HypervisorType.KVM != hypervisorType) {
+                        break;
+                    }
+                }
+            }
+        }
+        dataStoreHelper.switchToCluster(store, clusterScope);
+    }
+}
diff --git 
a/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/datastore/lifecycle/BasePrimaryDataStoreLifeCycleImplTest.java
 
b/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/datastore/lifecycle/BasePrimaryDataStoreLifeCycleImplTest.java
new file mode 100644
index 00000000000..355eb075129
--- /dev/null
+++ 
b/engine/storage/volume/src/test/java/org/apache/cloudstack/storage/datastore/lifecycle/BasePrimaryDataStoreLifeCycleImplTest.java
@@ -0,0 +1,127 @@
+// 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.storage.datastore.lifecycle;
+
+import static org.mockito.ArgumentMatchers.eq;
+
+import java.util.Arrays;
+import java.util.List;
+
+import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
+import org.apache.cloudstack.storage.datastore.PrimaryDataStoreImpl;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
+import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.InjectMocks;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.Spy;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
+
+import com.cloud.agent.AgentManager;
+import com.cloud.agent.api.Answer;
+import com.cloud.agent.api.DeleteStoragePoolCommand;
+import com.cloud.host.HostVO;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
+import com.cloud.resource.ResourceManager;
+import com.cloud.storage.Storage;
+import com.cloud.storage.StorageManager;
+import com.cloud.storage.StoragePoolHostVO;
+import com.cloud.storage.dao.StoragePoolHostDao;
+import com.cloud.utils.Pair;
+
+@RunWith(MockitoJUnitRunner.class)
+public class BasePrimaryDataStoreLifeCycleImplTest {
+
+    @Mock
+    private StoragePoolHostDao storagePoolHostDao;
+
+    @Mock
+    private PrimaryDataStoreHelper dataStoreHelper;
+
+    @Mock
+    private AgentManager agentManager;
+
+    @Mock
+    private ResourceManager resourceManager;
+
+    @Mock
+    private StorageManager storageManager;
+
+    @Spy
+    @InjectMocks
+    private BasePrimaryDataStoreLifeCycleImpl dataStoreLifeCycle;
+
+    private static final Long POOL_ID = 1L;
+    private static final Long CLUSTER_ID = 2L;
+    private static final Long POD_ID = 3L;
+    private static final Long ZONE_ID = 4L;
+    private static final Long HOST_ID = 5L;
+
+    private static ClusterScope clusterScope;
+    private static PrimaryDataStoreImpl store;
+
+
+    @BeforeClass
+    public static void init() {
+        clusterScope = new ClusterScope(CLUSTER_ID, POD_ID, ZONE_ID);
+        StoragePoolVO pool = new StoragePoolVO(POOL_ID, null, null, 
Storage.StoragePoolType.NetworkFilesystem, 0L, 0L, 0L, 0L, null, 0, null);
+        store = new PrimaryDataStoreImpl();
+        store.configure(pool, null, null);
+    }
+
+    @Test
+    public void testChangeStoragePoolScopeToZone() throws Exception {
+        
Mockito.when(resourceManager.listAllHostsInOneZoneNotInClusterByHypervisor(HypervisorType.KVM,
 ZONE_ID, CLUSTER_ID)).thenReturn(null);
+
+        dataStoreLifeCycle.changeStoragePoolScopeToZone(store, clusterScope, 
HypervisorType.KVM);
+
+        Mockito.verify(dataStoreHelper, Mockito.times(1)).switchToZone(store, 
HypervisorType.KVM);
+
+        HostVO host = new HostVO(null);
+        ReflectionTestUtils.setField(host, "id", HOST_ID);
+        List<HypervisorType> hypervisorTypes = 
Arrays.asList(HypervisorType.KVM, HypervisorType.VMware);
+        
Mockito.when(resourceManager.listAllHostsInOneZoneNotInClusterByHypervisors(hypervisorTypes,
 ZONE_ID, CLUSTER_ID)).thenReturn(Arrays.asList(host));
+        Mockito.when(storageManager.connectHostToSharedPool(HOST_ID, 
POOL_ID)).thenReturn(true);
+
+        dataStoreLifeCycle.changeStoragePoolScopeToZone(store, clusterScope, 
null);
+
+        Mockito.verify(dataStoreHelper, Mockito.times(1)).switchToZone(store, 
null);
+    }
+
+    @Test
+    public void testChangeStoragePoolScopeToCluster() {
+        Pair<List<StoragePoolHostVO>, Integer> hostPoolRecords = new 
Pair<>(null, 0);
+        Mockito.when(storagePoolHostDao.listByPoolIdNotInCluster(CLUSTER_ID, 
POOL_ID)).thenReturn(hostPoolRecords);
+        Mockito.doNothing().when(dataStoreHelper).switchToCluster(store, 
clusterScope);
+
+        dataStoreLifeCycle.changeStoragePoolScopeToCluster(store, 
clusterScope, HypervisorType.KVM);
+
+        hostPoolRecords.set(Arrays.asList(new StoragePoolHostVO(POOL_ID, 
HOST_ID, null)), 1);
+        Answer answer = new Answer(null, false, null);
+        Mockito.when(storagePoolHostDao.listByPoolIdNotInCluster(CLUSTER_ID, 
POOL_ID)).thenReturn(hostPoolRecords);
+        Mockito.when(agentManager.easySend(eq(HOST_ID), 
Mockito.any(DeleteStoragePoolCommand.class))).thenReturn(answer);
+
+        dataStoreLifeCycle.changeStoragePoolScopeToCluster(store, 
clusterScope, HypervisorType.KVM);
+
+        Mockito.verify(dataStoreHelper, 
Mockito.times(2)).switchToCluster(store, clusterScope);
+    }
+}
diff --git 
a/plugins/storage/volume/adaptive/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/AdaptiveDataStoreLifeCycleImpl.java
 
b/plugins/storage/volume/adaptive/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/AdaptiveDataStoreLifeCycleImpl.java
index ab1d49d8b4f..d1877bf09f0 100644
--- 
a/plugins/storage/volume/adaptive/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/AdaptiveDataStoreLifeCycleImpl.java
+++ 
b/plugins/storage/volume/adaptive/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/AdaptiveDataStoreLifeCycleImpl.java
@@ -62,7 +62,7 @@ import com.cloud.host.Host;
 /**
  * Manages the lifecycle of a Managed Data Store in CloudStack
  */
-public class AdaptiveDataStoreLifeCycleImpl implements 
PrimaryDataStoreLifeCycle {
+public class AdaptiveDataStoreLifeCycleImpl extends 
BasePrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLifeCycle {
     @Inject
     private PrimaryDataStoreDao _storagePoolDao;
     private static final Logger s_logger = 
Logger.getLogger(AdaptiveDataStoreLifeCycleImpl.class);
diff --git 
a/plugins/storage/volume/cloudbyte/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/ElastistorPrimaryDataStoreLifeCycle.java
 
b/plugins/storage/volume/cloudbyte/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/ElastistorPrimaryDataStoreLifeCycle.java
index 0798f9f2cd2..9ad63faebf7 100644
--- 
a/plugins/storage/volume/cloudbyte/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/ElastistorPrimaryDataStoreLifeCycle.java
+++ 
b/plugins/storage/volume/cloudbyte/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/ElastistorPrimaryDataStoreLifeCycle.java
@@ -65,7 +65,7 @@ import com.cloud.storage.StoragePoolHostVO;
 import com.cloud.storage.dao.StoragePoolHostDao;
 import com.cloud.utils.exception.CloudRuntimeException;
 
-public class ElastistorPrimaryDataStoreLifeCycle implements 
PrimaryDataStoreLifeCycle {
+public class ElastistorPrimaryDataStoreLifeCycle extends 
BasePrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLifeCycle {
     private static final Logger s_logger = 
Logger.getLogger(ElastistorPrimaryDataStoreLifeCycle.class);
 
     @Inject
diff --git 
a/plugins/storage/volume/datera/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/DateraPrimaryDataStoreLifeCycle.java
 
b/plugins/storage/volume/datera/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/DateraPrimaryDataStoreLifeCycle.java
index 6fd42009125..dae7d63d595 100644
--- 
a/plugins/storage/volume/datera/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/DateraPrimaryDataStoreLifeCycle.java
+++ 
b/plugins/storage/volume/datera/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/DateraPrimaryDataStoreLifeCycle.java
@@ -20,11 +20,11 @@ package org.apache.cloudstack.storage.datastore.lifecycle;
 
 import com.cloud.agent.api.StoragePoolInfo;
 import com.cloud.capacity.CapacityManager;
+import com.cloud.dc.ClusterDetailsDao;
 import com.cloud.dc.ClusterVO;
 import com.cloud.dc.DataCenterVO;
-import com.cloud.dc.dao.DataCenterDao;
-import com.cloud.dc.ClusterDetailsDao;
 import com.cloud.dc.dao.ClusterDao;
+import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.host.Host;
 import com.cloud.host.HostVO;
 import com.cloud.host.dao.HostDao;
@@ -43,10 +43,10 @@ import com.cloud.utils.exception.CloudRuntimeException;
 import org.apache.cloudstack.engine.subsystem.api.storage.ClusterScope;
 import org.apache.cloudstack.engine.subsystem.api.storage.DataStore;
 import org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
+import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo;
 import 
org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle;
 import 
org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
 import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
-import org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreInfo;
 import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
 import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.apache.cloudstack.storage.datastore.util.DateraUtil;
@@ -58,7 +58,7 @@ import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
 
-public class DateraPrimaryDataStoreLifeCycle implements 
PrimaryDataStoreLifeCycle {
+public class DateraPrimaryDataStoreLifeCycle extends 
BasePrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLifeCycle {
     private static final Logger s_logger = 
Logger.getLogger(DateraPrimaryDataStoreLifeCycle.class);
 
     @Inject
@@ -395,6 +395,15 @@ public class DateraPrimaryDataStoreLifeCycle implements 
PrimaryDataStoreLifeCycl
         dataStoreHelper.disable(dataStore);
     }
 
+    @Override
+    public void changeStoragePoolScopeToZone(DataStore store, ClusterScope 
clusterScope, HypervisorType hypervisorType) {
+        /*
+         * We need to attach all VMware, Xenserver and KVM hosts in the zone.
+         * So pass hypervisorType as null.
+         */
+        super.changeStoragePoolScopeToZone(store, clusterScope, null);
+    }
+
     private HypervisorType getHypervisorTypeForCluster(long clusterId) {
         ClusterVO cluster = _clusterDao.findById(clusterId);
 
diff --git 
a/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java
 
b/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java
index 73d9ca4b4f9..4d6fc09dc57 100644
--- 
a/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java
+++ 
b/plugins/storage/volume/default/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/CloudStackPrimaryDataStoreLifeCycleImpl.java
@@ -72,7 +72,7 @@ import java.util.List;
 import java.util.Map;
 import java.util.UUID;
 
-public class CloudStackPrimaryDataStoreLifeCycleImpl implements 
PrimaryDataStoreLifeCycle {
+public class CloudStackPrimaryDataStoreLifeCycleImpl extends 
BasePrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLifeCycle {
     private static final Logger s_logger = 
Logger.getLogger(CloudStackPrimaryDataStoreLifeCycleImpl.class);
     @Inject
     protected ResourceManager _resourceMgr;
diff --git 
a/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/LinstorPrimaryDataStoreLifeCycleImpl.java
 
b/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/LinstorPrimaryDataStoreLifeCycleImpl.java
index efc69438e75..0ef97ae4796 100644
--- 
a/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/LinstorPrimaryDataStoreLifeCycleImpl.java
+++ 
b/plugins/storage/volume/linstor/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/LinstorPrimaryDataStoreLifeCycleImpl.java
@@ -53,7 +53,7 @@ import 
org.apache.cloudstack.storage.datastore.util.LinstorUtil;
 import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
 import org.apache.log4j.Logger;
 
-public class LinstorPrimaryDataStoreLifeCycleImpl implements 
PrimaryDataStoreLifeCycle {
+public class LinstorPrimaryDataStoreLifeCycleImpl extends 
BasePrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLifeCycle {
     private static final Logger s_logger = 
Logger.getLogger(LinstorPrimaryDataStoreLifeCycleImpl.class);
 
     @Inject
diff --git 
a/plugins/storage/volume/nexenta/src/main/java/org/apache/cloudstack/storage/datastore/lifecylce/NexentaPrimaryDataStoreLifeCycle.java
 
b/plugins/storage/volume/nexenta/src/main/java/org/apache/cloudstack/storage/datastore/lifecylce/NexentaPrimaryDataStoreLifeCycle.java
index 507189edc14..922803ce9db 100644
--- 
a/plugins/storage/volume/nexenta/src/main/java/org/apache/cloudstack/storage/datastore/lifecylce/NexentaPrimaryDataStoreLifeCycle.java
+++ 
b/plugins/storage/volume/nexenta/src/main/java/org/apache/cloudstack/storage/datastore/lifecylce/NexentaPrimaryDataStoreLifeCycle.java
@@ -30,6 +30,7 @@ import 
org.apache.cloudstack.engine.subsystem.api.storage.HostScope;
 import 
org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreLifeCycle;
 import 
org.apache.cloudstack.engine.subsystem.api.storage.PrimaryDataStoreParameters;
 import org.apache.cloudstack.engine.subsystem.api.storage.ZoneScope;
+import 
org.apache.cloudstack.storage.datastore.lifecycle.BasePrimaryDataStoreLifeCycleImpl;
 import org.apache.cloudstack.storage.datastore.util.NexentaUtil;
 import org.apache.cloudstack.storage.volume.datastore.PrimaryDataStoreHelper;
 import org.apache.log4j.Logger;
@@ -45,6 +46,7 @@ import com.cloud.storage.StoragePool;
 import com.cloud.storage.StoragePoolAutomation;
 
 public class NexentaPrimaryDataStoreLifeCycle
+        extends BasePrimaryDataStoreLifeCycleImpl
         implements PrimaryDataStoreLifeCycle {
     private static final Logger logger =
             Logger.getLogger(NexentaPrimaryDataStoreLifeCycle.class);
@@ -177,6 +179,15 @@ public class NexentaPrimaryDataStoreLifeCycle
         dataStoreHelper.disable(dataStore);
     }
 
+    @Override
+    public void changeStoragePoolScopeToZone(DataStore store, ClusterScope 
clusterScope, Hypervisor.HypervisorType hypervisorType) {
+        /*
+         * We need to attach all VMware, Xenserver and KVM hosts in the zone.
+         * So pass hypervisorType as null.
+         */
+        super.changeStoragePoolScopeToZone(store, clusterScope, null);
+    }
+
     @Override
     public boolean deleteDataStore(DataStore store) {
         return dataStoreHelper.deletePrimaryDataStore(store);
diff --git 
a/plugins/storage/volume/sample/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/SamplePrimaryDataStoreLifeCycleImpl.java
 
b/plugins/storage/volume/sample/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/SamplePrimaryDataStoreLifeCycleImpl.java
index 3a0ce83f951..24d277251ea 100644
--- 
a/plugins/storage/volume/sample/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/SamplePrimaryDataStoreLifeCycleImpl.java
+++ 
b/plugins/storage/volume/sample/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/SamplePrimaryDataStoreLifeCycleImpl.java
@@ -146,4 +146,12 @@ public class SamplePrimaryDataStoreLifeCycleImpl 
implements PrimaryDataStoreLife
     @Override
     public void disableStoragePool(DataStore store) {
     }
+
+    @Override
+    public void changeStoragePoolScopeToZone(DataStore store, ClusterScope 
clusterScope, HypervisorType hypervisorType) {
+    }
+
+    @Override
+    public void changeStoragePoolScopeToCluster(DataStore store, ClusterScope 
clusterScope, HypervisorType hypervisorType) {
+    }
 }
diff --git 
a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycle.java
 
b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycle.java
index 2d7aca11f84..c1a7411d29f 100644
--- 
a/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycle.java
+++ 
b/plugins/storage/volume/scaleio/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/ScaleIOPrimaryDataStoreLifeCycle.java
@@ -74,7 +74,7 @@ import com.cloud.utils.UriUtils;
 import com.cloud.utils.crypt.DBEncryptionUtil;
 import com.cloud.utils.exception.CloudRuntimeException;
 
-public class ScaleIOPrimaryDataStoreLifeCycle implements 
PrimaryDataStoreLifeCycle {
+public class ScaleIOPrimaryDataStoreLifeCycle extends 
BasePrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLifeCycle {
     private static final Logger LOGGER = 
Logger.getLogger(ScaleIOPrimaryDataStoreLifeCycle.class);
 
     @Inject
diff --git 
a/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
 
b/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
index 7a2767c32e6..0e6474de0bb 100644
--- 
a/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
+++ 
b/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/SolidFirePrimaryDataStoreLifeCycle.java
@@ -63,7 +63,7 @@ import com.cloud.utils.exception.CloudRuntimeException;
 
 import com.google.common.base.Preconditions;
 
-public class SolidFirePrimaryDataStoreLifeCycle implements 
PrimaryDataStoreLifeCycle {
+public class SolidFirePrimaryDataStoreLifeCycle extends 
BasePrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLifeCycle {
     private static final Logger s_logger = 
Logger.getLogger(SolidFirePrimaryDataStoreLifeCycle.class);
 
     @Inject private CapacityManager _capacityMgr;
@@ -387,4 +387,13 @@ public class SolidFirePrimaryDataStoreLifeCycle implements 
PrimaryDataStoreLifeC
     public void disableStoragePool(DataStore dataStore) {
         _dataStoreHelper.disable(dataStore);
     }
+
+    @Override
+    public void changeStoragePoolScopeToZone(DataStore store, ClusterScope 
clusterScope, HypervisorType hypervisorType) {
+        /*
+         * We need to attach all VMware, Xenserver and KVM hosts in the zone.
+         * So pass hypervisorType as null.
+         */
+        super.changeStoragePoolScopeToZone(store, clusterScope, null);
+    }
 }
diff --git 
a/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java
 
b/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java
index 557cc3f60f6..dc106d398e1 100644
--- 
a/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java
+++ 
b/plugins/storage/volume/solidfire/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/SolidFireSharedPrimaryDataStoreLifeCycle.java
@@ -72,7 +72,7 @@ import com.cloud.user.dao.AccountDao;
 import com.cloud.utils.db.GlobalLock;
 import com.cloud.utils.exception.CloudRuntimeException;
 
-public class SolidFireSharedPrimaryDataStoreLifeCycle implements 
PrimaryDataStoreLifeCycle {
+public class SolidFireSharedPrimaryDataStoreLifeCycle extends 
BasePrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLifeCycle {
     private static final Logger LOGGER = 
Logger.getLogger(SolidFireSharedPrimaryDataStoreLifeCycle.class);
 
     @Inject private AccountDao accountDao;
diff --git 
a/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/StorPoolPrimaryDataStoreLifeCycle.java
 
b/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/StorPoolPrimaryDataStoreLifeCycle.java
index 4dbc7e4a22c..47f6089d734 100644
--- 
a/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/StorPoolPrimaryDataStoreLifeCycle.java
+++ 
b/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/lifecycle/StorPoolPrimaryDataStoreLifeCycle.java
@@ -60,7 +60,7 @@ import com.cloud.storage.dao.VMTemplateDetailsDao;
 import com.cloud.storage.dao.VMTemplatePoolDao;
 import com.cloud.utils.exception.CloudRuntimeException;
 
-public class StorPoolPrimaryDataStoreLifeCycle implements 
PrimaryDataStoreLifeCycle {
+public class StorPoolPrimaryDataStoreLifeCycle extends 
BasePrimaryDataStoreLifeCycleImpl implements PrimaryDataStoreLifeCycle {
     private static final Logger log = 
Logger.getLogger(StorPoolPrimaryDataStoreLifeCycle.class);
 
     @Inject
diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java 
b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
index 698c3d7fa33..5286dad29e4 100644
--- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
+++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java
@@ -100,6 +100,7 @@ import 
org.apache.cloudstack.api.command.admin.storage.ListStorageTagsCmd;
 import 
org.apache.cloudstack.api.command.admin.storage.heuristics.ListSecondaryStorageSelectorsCmd;
 import 
org.apache.cloudstack.api.command.admin.template.ListTemplatesCmdByAdmin;
 import org.apache.cloudstack.api.command.admin.user.ListUsersCmd;
+import 
org.apache.cloudstack.api.command.admin.vm.ListAffectedVmsForStorageScopeChangeCmd;
 import org.apache.cloudstack.api.command.admin.zone.ListZonesCmdByAdmin;
 import org.apache.cloudstack.api.command.user.account.ListAccountsCmd;
 import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd;
@@ -155,6 +156,7 @@ import 
org.apache.cloudstack.api.response.StorageTagResponse;
 import org.apache.cloudstack.api.response.TemplateResponse;
 import org.apache.cloudstack.api.response.UserResponse;
 import org.apache.cloudstack.api.response.UserVmResponse;
+import org.apache.cloudstack.api.response.VirtualMachineResponse;
 import org.apache.cloudstack.api.response.VolumeResponse;
 import org.apache.cloudstack.api.response.ZoneResponse;
 import org.apache.cloudstack.backup.BackupOfferingVO;
@@ -243,8 +245,10 @@ import com.cloud.api.query.vo.UserVmJoinVO;
 import com.cloud.api.query.vo.VolumeJoinVO;
 import com.cloud.cluster.ManagementServerHostVO;
 import com.cloud.cluster.dao.ManagementServerHostDao;
+import com.cloud.dc.ClusterVO;
 import com.cloud.dc.DataCenter;
 import com.cloud.dc.DedicatedResourceVO;
+import com.cloud.dc.dao.ClusterDao;
 import com.cloud.dc.dao.DedicatedResourceDao;
 import com.cloud.domain.Domain;
 import com.cloud.domain.DomainVO;
@@ -593,6 +597,10 @@ public class QueryManagerImpl extends 
MutualExclusiveIdsManagerBase implements Q
     @Inject
     private StoragePoolHostDao storagePoolHostDao;
 
+    @Inject
+    private ClusterDao clusterDao;
+
+
     private SearchCriteria<ServiceOfferingJoinVO> 
getMinimumCpuServiceOfferingJoinSearchCriteria(int cpu) {
         SearchCriteria<ServiceOfferingJoinVO> sc = 
_srvOfferingJoinDao.createSearchCriteria();
         SearchCriteria<ServiceOfferingJoinVO> sc1 = 
_srvOfferingJoinDao.createSearchCriteria();
@@ -1147,6 +1155,58 @@ public class QueryManagerImpl extends 
MutualExclusiveIdsManagerBase implements Q
         return response;
     }
 
+    @Override
+    public ListResponse<VirtualMachineResponse> 
listAffectedVmsForStorageScopeChange(ListAffectedVmsForStorageScopeChangeCmd 
cmd) {
+        Long poolId = cmd.getStorageId();
+        StoragePoolVO pool = storagePoolDao.findById(poolId);
+        if (pool == null) {
+            throw new IllegalArgumentException("Unable to find storage pool 
with ID: " + poolId);
+        }
+
+        ListResponse<VirtualMachineResponse> response = new ListResponse<>();
+        List<VirtualMachineResponse> responsesList = new ArrayList<>();
+        if (pool.getScope() != ScopeType.ZONE) {
+            response.setResponses(responsesList, 0);
+            return response;
+        }
+
+        Pair<List<VMInstanceVO>, Integer> vms = 
_vmInstanceDao.listByVmsNotInClusterUsingPool(cmd.getClusterIdForScopeChange(), 
poolId);
+        for (VMInstanceVO vm : vms.first()) {
+            VirtualMachineResponse resp = new VirtualMachineResponse();
+            
resp.setObjectName(VirtualMachine.class.getSimpleName().toLowerCase());
+            resp.setId(vm.getUuid());
+            resp.setVmType(vm.getType().toString());
+
+            UserVmJoinVO userVM = null;
+            if (!vm.getType().isUsedBySystem()) {
+                userVM = _userVmJoinDao.findById(vm.getId());
+            }
+            if (userVM != null) {
+                if (userVM.getDisplayName() != null) {
+                    resp.setVmName(userVM.getDisplayName());
+                } else {
+                    resp.setVmName(userVM.getName());
+                }
+            } else {
+                resp.setVmName(vm.getInstanceName());
+            }
+
+            HostVO host = hostDao.findById(vm.getHostId());
+            if (host != null) {
+                resp.setHostId(host.getUuid());
+                resp.setHostName(host.getName());
+                ClusterVO cluster = clusterDao.findById(host.getClusterId());
+                if (cluster != null) {
+                    resp.setClusterId(cluster.getUuid());
+                    resp.setClusterName(cluster.getName());
+                }
+            }
+            responsesList.add(resp);
+        }
+        response.setResponses(responsesList, vms.second());
+        return response;
+    }
+
     private Object getObjectPossibleMethodValue(Object obj, String methodName) 
{
         Object result = null;
 
diff --git a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java 
b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java
index b9163a188ea..5d3ec62c56d 100755
--- a/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java
+++ b/server/src/main/java/com/cloud/resource/ResourceManagerImpl.java
@@ -3426,6 +3426,26 @@ public class ResourceManagerImpl extends ManagerBase 
implements ResourceManager,
         return _hostGpuGroupsDao.customSearch(sc, searchFilter);
     }
 
+    @Override
+    public List<HostVO> listAllHostsInOneZoneNotInClusterByHypervisor(final 
HypervisorType type, final long dcId, final long clusterId) {
+        final QueryBuilder<HostVO> sc = QueryBuilder.create(HostVO.class);
+        sc.and(sc.entity().getHypervisorType(), Op.EQ, type);
+        sc.and(sc.entity().getDataCenterId(), Op.EQ, dcId);
+        sc.and(sc.entity().getClusterId(), Op.NEQ, clusterId);
+        sc.and(sc.entity().getStatus(), Op.EQ, Status.Up);
+        return sc.list();
+    }
+
+    @Override
+    public List<HostVO> 
listAllHostsInOneZoneNotInClusterByHypervisors(List<HypervisorType> types, 
final long dcId, final long clusterId) {
+        final QueryBuilder<HostVO> sc = QueryBuilder.create(HostVO.class);
+        sc.and(sc.entity().getHypervisorType(), Op.IN, types);
+        sc.and(sc.entity().getDataCenterId(), Op.EQ, dcId);
+        sc.and(sc.entity().getClusterId(), Op.NEQ, clusterId);
+        sc.and(sc.entity().getStatus(), Op.EQ, Status.Up);
+        return sc.list();
+    }
+
     @Override
     public boolean isGPUDeviceAvailable(final long hostId, final String 
groupName, final String vgpuType) {
         if(!listAvailableGPUDevice(hostId, groupName, vgpuType).isEmpty()) {
diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java 
b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
index 14afcc71245..9d69a52cfb8 100644
--- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java
@@ -211,6 +211,7 @@ import 
org.apache.cloudstack.api.command.admin.storage.AddImageStoreCmd;
 import org.apache.cloudstack.api.command.admin.storage.AddImageStoreS3CMD;
 import org.apache.cloudstack.api.command.admin.storage.AddObjectStoragePoolCmd;
 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;
@@ -522,6 +523,7 @@ import 
org.apache.cloudstack.api.command.user.vm.AddIpToVmNicCmd;
 import org.apache.cloudstack.api.command.user.vm.AddNicToVMCmd;
 import org.apache.cloudstack.api.command.user.vm.DeployVMCmd;
 import org.apache.cloudstack.api.command.user.vm.DestroyVMCmd;
+import 
org.apache.cloudstack.api.command.admin.vm.ListAffectedVmsForStorageScopeChangeCmd;
 import org.apache.cloudstack.api.command.user.vm.GetVMPasswordCmd;
 import org.apache.cloudstack.api.command.user.vm.ListNicsCmd;
 import org.apache.cloudstack.api.command.user.vm.ListVMsCmd;
@@ -3481,6 +3483,7 @@ public class ManagementServerImpl extends ManagerBase 
implements ManagementServe
         cmdList.add(UpgradeRouterCmd.class);
         cmdList.add(AddSwiftCmd.class);
         cmdList.add(CancelPrimaryStorageMaintenanceCmd.class);
+        cmdList.add(ChangeStoragePoolScopeCmd.class);
         cmdList.add(CreateStoragePoolCmd.class);
         cmdList.add(DeletePoolCmd.class);
         cmdList.add(ListSwiftsCmd.class);
@@ -3917,6 +3920,7 @@ public class ManagementServerImpl extends ManagerBase 
implements ManagementServe
         cmdList.add(CreateSecondaryStorageSelectorCmd.class);
         cmdList.add(UpdateSecondaryStorageSelectorCmd.class);
         cmdList.add(RemoveSecondaryStorageSelectorCmd.class);
+        cmdList.add(ListAffectedVmsForStorageScopeChangeCmd.class);
 
 
         // Out-of-band management APIs for admins
diff --git a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java 
b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
index de3ec02dc7a..74b19b61fd4 100644
--- a/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
+++ b/server/src/main/java/com/cloud/storage/StorageManagerImpl.java
@@ -54,6 +54,7 @@ import org.apache.cloudstack.annotation.AnnotationService;
 import org.apache.cloudstack.annotation.dao.AnnotationDao;
 import org.apache.cloudstack.api.ApiConstants;
 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;
@@ -257,6 +258,7 @@ import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.vm.DiskProfile;
 import com.cloud.vm.UserVmManager;
 import com.cloud.vm.VMInstanceVO;
+import com.cloud.vm.VirtualMachine;
 import com.cloud.vm.VirtualMachine.State;
 import com.cloud.vm.dao.VMInstanceDao;
 import com.google.common.collect.Sets;
@@ -412,6 +414,9 @@ public class StorageManagerImpl extends ManagerBase 
implements StorageManager, C
 
     private final Map<String, HypervisorHostListener> hostListeners = new 
HashMap<String, HypervisorHostListener>();
 
+    private final Set<HypervisorType> zoneWidePoolSupportedHypervisorTypes = 
Sets.newHashSet(HypervisorType.KVM, HypervisorType.VMware,
+            HypervisorType.Hyperv, HypervisorType.LXC, HypervisorType.Any, 
HypervisorType.Simulator);
+
     private static final String NFS_MOUNT_OPTIONS_INCORRECT = "An incorrect 
mount option was specified";
 
     public boolean share(VMInstanceVO vm, List<VolumeVO> vols, HostVO host, 
boolean cancelPreviousShare) throws StorageUnavailableException {
@@ -967,9 +972,7 @@ public class StorageManagerImpl extends ManagerBase 
implements StorageManager, C
                 throw new InvalidParameterValueException("Missing parameter 
hypervisor. Hypervisor type is required to create zone wide primary storage.");
             }
 
-            Set<HypervisorType> supportedHypervisorTypes = 
Sets.newHashSet(HypervisorType.KVM, HypervisorType.VMware,
-                    HypervisorType.Hyperv, HypervisorType.LXC, 
HypervisorType.Any, HypervisorType.Simulator);
-            if (!supportedHypervisorTypes.contains(hypervisorType)) {
+            if 
(!zoneWidePoolSupportedHypervisorTypes.contains(hypervisorType)) {
                 throw new InvalidParameterValueException("Zone wide storage 
pool is not supported for hypervisor type " + hypervisor);
             }
         } else {
@@ -1249,6 +1252,115 @@ public class StorageManagerImpl extends ManagerBase 
implements StorageManager, C
         return (PrimaryDataStoreInfo)_dataStoreMgr.getDataStore(pool.getId(), 
DataStoreRole.Primary);
     }
 
+    private void changeStoragePoolScopeToZone(StoragePoolVO primaryStorage) {
+        /*
+         * For cluster wide primary storage the hypervisor type might not be 
set.
+         * So, get it from the clusterVO.
+         */
+        Long clusterId = primaryStorage.getClusterId();
+        ClusterVO clusterVO = _clusterDao.findById(clusterId);
+        HypervisorType hypervisorType = clusterVO.getHypervisorType();
+        if (!zoneWidePoolSupportedHypervisorTypes.contains(hypervisorType)) {
+            throw new InvalidParameterValueException("Primary storage scope 
change to Zone is not supported for hypervisor type " + hypervisorType);
+        }
+
+        DataStoreProvider storeProvider = 
_dataStoreProviderMgr.getDataStoreProvider(primaryStorage.getStorageProviderName());
+        PrimaryDataStoreLifeCycle lifeCycle = (PrimaryDataStoreLifeCycle) 
storeProvider.getDataStoreLifeCycle();
+
+        DataStore primaryStore = 
_dataStoreMgr.getPrimaryDataStore(primaryStorage.getId());
+        ClusterScope clusterScope = new 
ClusterScope(primaryStorage.getClusterId(), null, 
primaryStorage.getDataCenterId());
+
+        lifeCycle.changeStoragePoolScopeToZone(primaryStore, clusterScope, 
hypervisorType);
+    }
+
+    private void changeStoragePoolScopeToCluster(StoragePoolVO primaryStorage, 
Long clusterId) {
+        if (clusterId == null) {
+            throw new InvalidParameterValueException("Cluster ID not 
provided");
+        }
+        ClusterVO clusterVO = _clusterDao.findById(clusterId);
+        if (clusterVO == null) {
+            throw new InvalidParameterValueException("Unable to find cluster 
by id " + clusterId);
+        }
+        if 
(clusterVO.getAllocationState().equals(Grouping.AllocationState.Disabled)) {
+            throw new PermissionDeniedException("Cannot perform this 
operation, Cluster is currently disabled: " + clusterId);
+        }
+
+        List<VirtualMachine.State> states = Arrays.asList(State.Starting, 
State.Running, State.Stopping, State.Migrating, State.Restoring);
+
+        Long id = primaryStorage.getId();
+        Pair<List<VMInstanceVO>, Integer> vmsNotInClusterUsingPool = 
_vmInstanceDao.listByVmsNotInClusterUsingPool(clusterId, id);
+        if (vmsNotInClusterUsingPool.second() != 0) {
+            throw new CloudRuntimeException(String.format("Cannot change scope 
of the storage pool [%s] to cluster [%s] " +
+                    "as there are %s VMs with volumes in this pool that are 
running on other clusters. " +
+                    "All such User VMs must be stopped and System VMs must be 
destroyed before proceeding. " +
+                    "Please use the API listAffectedVmsForStorageScopeChange 
to get the list.",
+                    primaryStorage.getName(), clusterVO.getName(), 
vmsNotInClusterUsingPool.second()));
+        }
+
+        DataStoreProvider storeProvider = 
_dataStoreProviderMgr.getDataStoreProvider(primaryStorage.getStorageProviderName());
+        PrimaryDataStoreLifeCycle lifeCycle = (PrimaryDataStoreLifeCycle) 
storeProvider.getDataStoreLifeCycle();
+
+        DataStore primaryStore = _dataStoreMgr.getPrimaryDataStore(id);
+        ClusterScope clusterScope = new ClusterScope(clusterId, 
clusterVO.getPodId(), primaryStorage.getDataCenterId());
+
+        lifeCycle.changeStoragePoolScopeToCluster(primaryStore, clusterScope, 
primaryStorage.getHypervisor());
+    }
+
+    @Override
+    @ActionEvent(eventType = EventTypes.EVENT_CHANGE_STORAGE_POOL_SCOPE, 
eventDescription = "changing storage pool scope")
+    public void changeStoragePoolScope(ChangeStoragePoolScopeCmd cmd) throws 
IllegalArgumentException, InvalidParameterValueException, 
PermissionDeniedException {
+        Long id = cmd.getId();
+
+        Long accountId = cmd.getEntityOwnerId();
+        if (!_accountMgr.isRootAdmin(accountId)) {
+            throw new PermissionDeniedException("Only root admin can perform 
this operation");
+        }
+
+        ScopeType newScope = EnumUtils.getEnumIgnoreCase(ScopeType.class, 
cmd.getScope());
+        if (newScope != ScopeType.ZONE && newScope != ScopeType.CLUSTER) {
+            throw new InvalidParameterValueException("Invalid scope " + 
cmd.getScope() + "for Primary storage");
+        }
+
+        StoragePoolVO primaryStorage = _storagePoolDao.findById(id);
+        if (primaryStorage == null) {
+            throw new IllegalArgumentException("Unable to find storage pool 
with ID: " + id);
+        }
+
+        String eventDetails = String.format(" Storage pool Id: %s to 
%s",primaryStorage.getUuid(), newScope);
+        CallContext.current().setEventDetails(eventDetails);
+
+        ScopeType currentScope = primaryStorage.getScope();
+        if (currentScope.equals(newScope)) {
+            throw new InvalidParameterValueException("New scope must be 
different than the current scope");
+        }
+
+        if (currentScope != ScopeType.ZONE && currentScope != 
ScopeType.CLUSTER) {
+            throw new InvalidParameterValueException("This operation is 
supported only for Primary storages having scope "
+                    + ScopeType.CLUSTER + " or " + ScopeType.ZONE);
+        }
+
+        if (!primaryStorage.getStatus().equals(StoragePoolStatus.Disabled)) {
+            throw new InvalidParameterValueException("Scope of the Primary 
storage with id "
+                    + primaryStorage.getUuid() +
+                    " cannot be changed, as it is not in the Disabled state");
+        }
+
+        Long zoneId = primaryStorage.getDataCenterId();
+        DataCenterVO zone = _dcDao.findById(zoneId);
+        if (zone == null) {
+            throw new InvalidParameterValueException("Unable to find zone by 
id " + zoneId);
+        }
+        if 
(zone.getAllocationState().equals(Grouping.AllocationState.Disabled)) {
+            throw new PermissionDeniedException("Cannot perform this 
operation, Zone is currently disabled: " + zoneId);
+        }
+
+        if (newScope.equals(ScopeType.ZONE)) {
+            changeStoragePoolScopeToZone(primaryStorage);
+        } else {
+            changeStoragePoolScopeToCluster(primaryStorage, 
cmd.getClusterId());
+        }
+    }
+
     @Override
     public void removeStoragePoolFromCluster(long hostId, String iScsiName, 
StoragePool storagePool) {
         final Map<String, String> details = new HashMap<>();
diff --git a/server/src/test/java/com/cloud/api/query/QueryManagerImplTest.java 
b/server/src/test/java/com/cloud/api/query/QueryManagerImplTest.java
index be8978e799b..2a62adef06b 100644
--- a/server/src/test/java/com/cloud/api/query/QueryManagerImplTest.java
+++ b/server/src/test/java/com/cloud/api/query/QueryManagerImplTest.java
@@ -18,18 +18,25 @@
 package com.cloud.api.query;
 
 import com.cloud.api.query.dao.TemplateJoinDao;
+import com.cloud.api.query.dao.UserVmJoinDao;
 import com.cloud.api.query.vo.EventJoinVO;
 import com.cloud.api.query.vo.TemplateJoinVO;
+import com.cloud.api.query.vo.UserVmJoinVO;
+import com.cloud.dc.ClusterVO;
+import com.cloud.dc.dao.ClusterDao;
 import com.cloud.event.EventVO;
 import com.cloud.event.dao.EventDao;
 import com.cloud.event.dao.EventJoinDao;
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.PermissionDeniedException;
+import com.cloud.host.HostVO;
+import com.cloud.host.dao.HostDao;
 import com.cloud.network.Network;
 import com.cloud.network.VNF;
 import com.cloud.network.dao.NetworkVO;
 import com.cloud.server.ResourceTag;
 import com.cloud.storage.BucketVO;
+import com.cloud.storage.ScopeType;
 import com.cloud.storage.dao.BucketDao;
 import com.cloud.user.Account;
 import com.cloud.user.AccountManager;
@@ -41,10 +48,14 @@ import com.cloud.utils.db.EntityManager;
 import com.cloud.utils.db.Filter;
 import com.cloud.utils.db.SearchBuilder;
 import com.cloud.utils.db.SearchCriteria;
+import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.VirtualMachine;
+import com.cloud.vm.dao.VMInstanceDao;
+
 import org.apache.cloudstack.acl.SecurityChecker;
 import org.apache.cloudstack.api.ApiCommandResourceType;
 import 
org.apache.cloudstack.api.command.admin.storage.ListObjectStoragePoolsCmd;
+import 
org.apache.cloudstack.api.command.admin.vm.ListAffectedVmsForStorageScopeChangeCmd;
 import org.apache.cloudstack.api.command.user.bucket.ListBucketsCmd;
 import org.apache.cloudstack.api.command.user.event.ListEventsCmd;
 import org.apache.cloudstack.api.command.user.resource.ListDetailOptionsCmd;
@@ -52,9 +63,12 @@ import 
org.apache.cloudstack.api.response.DetailOptionsResponse;
 import org.apache.cloudstack.api.response.EventResponse;
 import org.apache.cloudstack.api.response.ListResponse;
 import org.apache.cloudstack.api.response.ObjectStoreResponse;
+import org.apache.cloudstack.api.response.VirtualMachineResponse;
 import org.apache.cloudstack.context.CallContext;
 import org.apache.cloudstack.storage.datastore.db.ObjectStoreDao;
 import org.apache.cloudstack.storage.datastore.db.ObjectStoreVO;
+import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolVO;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -65,6 +79,7 @@ import org.mockito.MockedStatic;
 import org.mockito.Mockito;
 import org.mockito.Spy;
 import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -112,9 +127,24 @@ public class QueryManagerImplTest {
     @Mock
     ObjectStoreDao objectStoreDao;
 
+    @Mock
+    VMInstanceDao vmInstanceDao;
+
+    @Mock
+    PrimaryDataStoreDao storagePoolDao;
+
+    @Mock
+    HostDao hostDao;
+
+    @Mock
+    ClusterDao clusterDao;
+
     @Mock
     BucketDao bucketDao;
 
+    @Mock
+    UserVmJoinDao userVmJoinDao;
+
     private AccountVO account;
     private UserVO user;
 
@@ -352,4 +382,46 @@ public class QueryManagerImplTest {
         when(bucketDao.searchAndCount(any(), any())).thenReturn(new 
Pair<>(buckets, 2));
         queryManagerImplSpy.searchForBuckets(listBucketsCmd);
     }
+
+    @Test
+    public void testListAffectedVmsForScopeChange() {
+        Long clusterId = 1L;
+        Long poolId = 2L;
+        Long hostId = 3L;
+        Long vmId = 4L;
+        String vmName = "VM1";
+
+        ListAffectedVmsForStorageScopeChangeCmd cmd = new 
ListAffectedVmsForStorageScopeChangeCmd();
+        ReflectionTestUtils.setField(cmd, "clusterIdForScopeChange", 
clusterId);
+        ReflectionTestUtils.setField(cmd, "storageId", poolId);
+
+        StoragePoolVO pool = Mockito.mock(StoragePoolVO.class);
+        Mockito.when(pool.getScope()).thenReturn(ScopeType.CLUSTER);
+        Mockito.when(storagePoolDao.findById(poolId)).thenReturn(pool);
+        ListResponse<VirtualMachineResponse> response = 
queryManager.listAffectedVmsForStorageScopeChange(cmd);
+        Assert.assertEquals(response.getResponses().size(), 0);
+
+        VMInstanceVO instance = Mockito.mock(VMInstanceVO.class);
+        UserVmJoinVO userVM = Mockito.mock(UserVmJoinVO.class);
+        String instanceUuid = String.valueOf(UUID.randomUUID());
+        Pair<List<VMInstanceVO>, Integer> vms = new Pair<>(List.of(instance), 
1);
+        HostVO host = Mockito.mock(HostVO.class);
+        ClusterVO cluster = Mockito.mock(ClusterVO.class);
+
+        Mockito.when(pool.getScope()).thenReturn(ScopeType.ZONE);
+        Mockito.when(instance.getUuid()).thenReturn(instanceUuid);
+        
Mockito.when(instance.getType()).thenReturn(VirtualMachine.Type.Instance);
+        Mockito.when(instance.getHostId()).thenReturn(hostId);
+        Mockito.when(instance.getId()).thenReturn(vmId);
+        Mockito.when(userVM.getDisplayName()).thenReturn(vmName);
+        Mockito.when(vmInstanceDao.listByVmsNotInClusterUsingPool(clusterId, 
poolId)).thenReturn(vms);
+        Mockito.when(userVmJoinDao.findById(vmId)).thenReturn(userVM);
+        Mockito.when(hostDao.findById(hostId)).thenReturn(host);
+        Mockito.when(host.getClusterId()).thenReturn(clusterId);
+        Mockito.when(clusterDao.findById(clusterId)).thenReturn(cluster);
+
+        response = queryManager.listAffectedVmsForStorageScopeChange(cmd);
+        Assert.assertEquals(response.getResponses().get(0).getId(), 
instanceUuid);
+        Assert.assertEquals(response.getResponses().get(0).getName(), vmName);
+    }
 }
diff --git 
a/server/src/test/java/com/cloud/resource/MockResourceManagerImpl.java 
b/server/src/test/java/com/cloud/resource/MockResourceManagerImpl.java
index f9c07ef8dd8..6aae7a091d3 100755
--- a/server/src/test/java/com/cloud/resource/MockResourceManagerImpl.java
+++ b/server/src/test/java/com/cloud/resource/MockResourceManagerImpl.java
@@ -431,6 +431,17 @@ public class MockResourceManagerImpl extends ManagerBase 
implements ResourceMana
         return null;
     }
 
+    @Override
+    public List<HostVO> 
listAllHostsInOneZoneNotInClusterByHypervisor(HypervisorType type, long dcId, 
long clusterId) {
+        return null;
+    }
+
+    @Override
+    public List<HostVO> 
listAllHostsInOneZoneNotInClusterByHypervisors(List<HypervisorType> types, long 
dcId, long clusterId) {
+        // TODO Auto-generated method stub
+        return null;
+    }
+
     /* (non-Javadoc)
      * @see 
com.cloud.resource.ResourceManager#listAvailHypervisorInZone(java.lang.Long, 
java.lang.Long)
      */
diff --git a/server/src/test/java/com/cloud/storage/StorageManagerImplTest.java 
b/server/src/test/java/com/cloud/storage/StorageManagerImplTest.java
index 2596f9facba..901676542c9 100644
--- a/server/src/test/java/com/cloud/storage/StorageManagerImplTest.java
+++ b/server/src/test/java/com/cloud/storage/StorageManagerImplTest.java
@@ -16,17 +16,22 @@
 // under the License.
 package com.cloud.storage;
 
+import 
org.apache.cloudstack.api.command.admin.storage.ChangeStoragePoolScopeCmd;
 import com.cloud.agent.api.StoragePoolInfo;
+import com.cloud.dc.ClusterVO;
+import com.cloud.dc.DataCenter;
 import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.dao.ClusterDao;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.exception.ConnectionException;
 import com.cloud.exception.InvalidParameterValueException;
 import com.cloud.exception.PermissionDeniedException;
 import com.cloud.host.Host;
-import com.cloud.hypervisor.Hypervisor;
+import com.cloud.hypervisor.Hypervisor.HypervisorType;
 import com.cloud.storage.dao.VolumeDao;
-import com.cloud.user.AccountManager;
+import com.cloud.user.AccountManagerImpl;
 import com.cloud.utils.Pair;
+import com.cloud.utils.exception.CloudRuntimeException;
 import com.cloud.vm.VMInstanceVO;
 import com.cloud.vm.dao.VMInstanceDao;
 
@@ -46,6 +51,7 @@ import org.mockito.Mock;
 import org.mockito.Mockito;
 import org.mockito.Spy;
 import org.mockito.junit.MockitoJUnitRunner;
+import org.springframework.test.util.ReflectionTestUtils;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -67,10 +73,16 @@ public class StorageManagerImplTest {
     @Mock
     DataCenterDao dataCenterDao;
     @Mock
-    AccountManager accountManager;
+    AccountManagerImpl accountMgr;
     @Mock
     StoragePoolDetailsDao storagePoolDetailsDao;
 
+    @Mock
+    ClusterDao clusterDao;
+
+    @Mock
+    PrimaryDataStoreDao storagePoolDao;
+
     @Spy
     @InjectMocks
     private StorageManagerImpl storageManagerImpl;
@@ -260,11 +272,74 @@ public class StorageManagerImplTest {
                 
.update(StorageManager.DataStoreDownloadFollowRedirects.key(),StorageManager.DataStoreDownloadFollowRedirects.defaultValue());
     }
 
+    private ChangeStoragePoolScopeCmd mockChangeStoragePooolScopeCmd(String 
newScope) {
+        ChangeStoragePoolScopeCmd cmd = new ChangeStoragePoolScopeCmd();
+        ReflectionTestUtils.setField(cmd, "id", 1L);
+        ReflectionTestUtils.setField(cmd, "clusterId", 1L);
+        ReflectionTestUtils.setField(cmd, "scope", newScope);
+        return cmd;
+    }
+
+    private StoragePoolVO mockStoragePoolVOForChangeStoragePoolScope(ScopeType 
currentScope, StoragePoolStatus status) {
+        StoragePoolVO primaryStorage = new StoragePoolVO();
+        primaryStorage.setId(1L);
+        primaryStorage.setDataCenterId(1L);
+        primaryStorage.setClusterId(1L);
+        primaryStorage.setStatus(StoragePoolStatus.Disabled);
+        primaryStorage.setScope(currentScope);
+        primaryStorage.setStatus(status);
+        return primaryStorage;
+    }
+
+    private void prepareTestChangeStoragePoolScope(ScopeType currentScope, 
StoragePoolStatus status) {
+        final DataCenterVO zone = new DataCenterVO(1L, null, null, null, null, 
null, null, null, null, null, DataCenter.NetworkType.Advanced, null, null);
+        StoragePoolVO primaryStorage = 
mockStoragePoolVOForChangeStoragePoolScope(currentScope, status);
+
+        Mockito.when(accountMgr.isRootAdmin(Mockito.any())).thenReturn(true);
+        Mockito.when(dataCenterDao.findById(1L)).thenReturn(zone);
+        Mockito.when(storagePoolDao.findById(1L)).thenReturn(primaryStorage);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testChangeStoragePoolScopeNotDisabledException() {
+        prepareTestChangeStoragePoolScope(ScopeType.CLUSTER, 
StoragePoolStatus.Initialized);
+
+        ChangeStoragePoolScopeCmd cmd = mockChangeStoragePooolScopeCmd("ZONE");
+        storageManagerImpl.changeStoragePoolScope(cmd);
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void testChangeStoragePoolScopeToZoneHypervisorNotSupported() {
+        prepareTestChangeStoragePoolScope(ScopeType.CLUSTER, 
StoragePoolStatus.Disabled);
+
+        final ClusterVO cluster = new ClusterVO();
+        cluster.setHypervisorType(String.valueOf(HypervisorType.XenServer));
+        Mockito.when(clusterDao.findById(1L)).thenReturn(cluster);
+
+        ChangeStoragePoolScopeCmd cmd = mockChangeStoragePooolScopeCmd("ZONE");
+        storageManagerImpl.changeStoragePoolScope(cmd);
+    }
+
+    @Test(expected = CloudRuntimeException.class)
+    public void testChangeStoragePoolScopeToClusterVolumesPresentException() {
+        prepareTestChangeStoragePoolScope(ScopeType.ZONE, 
StoragePoolStatus.Disabled);
+
+        final ClusterVO cluster = new ClusterVO();
+        Mockito.when(clusterDao.findById(1L)).thenReturn(cluster);
+
+        VMInstanceVO instance = Mockito.mock(VMInstanceVO.class);
+        Pair<List<VMInstanceVO>, Integer> vms = new Pair<>(List.of(instance), 
1);
+        Mockito.when(vmInstanceDao.listByVmsNotInClusterUsingPool(1L, 
1L)).thenReturn(vms);
+
+        ChangeStoragePoolScopeCmd cmd = 
mockChangeStoragePooolScopeCmd("CLUSTER");
+        storageManagerImpl.changeStoragePoolScope(cmd);
+    }
+
     @Test
     public void testCheckNFSMountOptionsForCreateNoNFSMountOptions() {
         Map<String, String> details = new HashMap<>();
         try {
-            storageManagerImpl.checkNFSMountOptionsForCreate(details, 
Hypervisor.HypervisorType.XenServer, "");
+            storageManagerImpl.checkNFSMountOptionsForCreate(details, 
HypervisorType.XenServer, "");
         } catch (Exception e) {
             Assert.fail();
         }
@@ -275,8 +350,8 @@ public class StorageManagerImplTest {
         Map<String, String> details = new HashMap<>();
         details.put(ApiConstants.NFS_MOUNT_OPTIONS, "vers=4.1");
         InvalidParameterValueException exception = 
Assert.assertThrows(InvalidParameterValueException.class,
-                () -> 
storageManagerImpl.checkNFSMountOptionsForCreate(details, 
Hypervisor.HypervisorType.XenServer, ""));
-        Assert.assertEquals(exception.getMessage(), "NFS options can not be 
set for the hypervisor type " + Hypervisor.HypervisorType.XenServer);
+                () -> 
storageManagerImpl.checkNFSMountOptionsForCreate(details, 
HypervisorType.XenServer, ""));
+        Assert.assertEquals(exception.getMessage(), "NFS options can not be 
set for the hypervisor type " + HypervisorType.XenServer);
     }
 
     @Test
@@ -284,7 +359,7 @@ public class StorageManagerImplTest {
         Map<String, String> details = new HashMap<>();
         details.put(ApiConstants.NFS_MOUNT_OPTIONS, "vers=4.1");
         InvalidParameterValueException exception = 
Assert.assertThrows(InvalidParameterValueException.class,
-                () -> 
storageManagerImpl.checkNFSMountOptionsForCreate(details, 
Hypervisor.HypervisorType.KVM, ""));
+                () -> 
storageManagerImpl.checkNFSMountOptionsForCreate(details, HypervisorType.KVM, 
""));
         Assert.assertEquals(exception.getMessage(), "NFS options can only be 
set on pool type " + Storage.StoragePoolType.NetworkFilesystem);
     }
 
@@ -306,7 +381,7 @@ public class StorageManagerImplTest {
         StoragePoolVO pool = new StoragePoolVO();
         Long accountId = 1L;
         details.put(ApiConstants.NFS_MOUNT_OPTIONS, "vers=4.1");
-        Mockito.when(accountManager.isRootAdmin(accountId)).thenReturn(false);
+        Mockito.when(accountMgr.isRootAdmin(accountId)).thenReturn(false);
         PermissionDeniedException exception = 
Assert.assertThrows(PermissionDeniedException.class,
                 () -> 
storageManagerImpl.checkNFSMountOptionsForUpdate(details, pool, accountId));
         Assert.assertEquals(exception.getMessage(), "Only root admin can 
modify nfs options");
@@ -318,11 +393,11 @@ public class StorageManagerImplTest {
         StoragePoolVO pool = new StoragePoolVO();
         Long accountId = 1L;
         details.put(ApiConstants.NFS_MOUNT_OPTIONS, "vers=4.1");
-        Mockito.when(accountManager.isRootAdmin(accountId)).thenReturn(true);
-        pool.setHypervisor(Hypervisor.HypervisorType.XenServer);
+        Mockito.when(accountMgr.isRootAdmin(accountId)).thenReturn(true);
+        pool.setHypervisor(HypervisorType.XenServer);
         InvalidParameterValueException exception = 
Assert.assertThrows(InvalidParameterValueException.class,
                 () -> 
storageManagerImpl.checkNFSMountOptionsForUpdate(details, pool, accountId));
-        Assert.assertEquals(exception.getMessage(), "NFS options can only be 
set for the hypervisor type " + Hypervisor.HypervisorType.KVM);
+        Assert.assertEquals(exception.getMessage(), "NFS options can only be 
set for the hypervisor type " + HypervisorType.KVM);
     }
 
     @Test
@@ -331,8 +406,8 @@ public class StorageManagerImplTest {
         StoragePoolVO pool = new StoragePoolVO();
         Long accountId = 1L;
         details.put(ApiConstants.NFS_MOUNT_OPTIONS, "vers=4.1");
-        Mockito.when(accountManager.isRootAdmin(accountId)).thenReturn(true);
-        pool.setHypervisor(Hypervisor.HypervisorType.KVM);
+        Mockito.when(accountMgr.isRootAdmin(accountId)).thenReturn(true);
+        pool.setHypervisor(HypervisorType.KVM);
         pool.setPoolType(Storage.StoragePoolType.FiberChannel);
         InvalidParameterValueException exception = 
Assert.assertThrows(InvalidParameterValueException.class,
                 () -> 
storageManagerImpl.checkNFSMountOptionsForUpdate(details, pool, accountId));
@@ -345,8 +420,8 @@ public class StorageManagerImplTest {
         StoragePoolVO pool = new StoragePoolVO();
         Long accountId = 1L;
         details.put(ApiConstants.NFS_MOUNT_OPTIONS, "vers=4.1");
-        Mockito.when(accountManager.isRootAdmin(accountId)).thenReturn(true);
-        pool.setHypervisor(Hypervisor.HypervisorType.KVM);
+        Mockito.when(accountMgr.isRootAdmin(accountId)).thenReturn(true);
+        pool.setHypervisor(HypervisorType.KVM);
         pool.setPoolType(Storage.StoragePoolType.NetworkFilesystem);
         pool.setStatus(StoragePoolStatus.Up);
         InvalidParameterValueException exception = 
Assert.assertThrows(InvalidParameterValueException.class,
@@ -359,7 +434,7 @@ public class StorageManagerImplTest {
         String nfsMountOpts = "vers=4.1, nconnect=4,vers=4.2";
         Map<String, String> details = new HashMap<>();
         details.put(ApiConstants.NFS_MOUNT_OPTIONS, nfsMountOpts);
-        storageManagerImpl.checkNFSMountOptionsForCreate(details, 
Hypervisor.HypervisorType.KVM, "nfs");
+        storageManagerImpl.checkNFSMountOptionsForCreate(details, 
HypervisorType.KVM, "nfs");
     }
 
     @Test(expected = InvalidParameterValueException.class)
@@ -368,11 +443,11 @@ public class StorageManagerImplTest {
         Map<String, String> details = new HashMap<>();
         details.put(ApiConstants.NFS_MOUNT_OPTIONS, nfsMountOpts);
         StoragePoolVO pool = new StoragePoolVO();
-        pool.setHypervisor(Hypervisor.HypervisorType.KVM);
+        pool.setHypervisor(HypervisorType.KVM);
         pool.setPoolType(Storage.StoragePoolType.NetworkFilesystem);
         pool.setStatus(StoragePoolStatus.Maintenance);
         Long accountId = 1L;
-        Mockito.when(accountManager.isRootAdmin(accountId)).thenReturn(true);
+        Mockito.when(accountMgr.isRootAdmin(accountId)).thenReturn(true);
         storageManagerImpl.checkNFSMountOptionsForUpdate(details, pool, 
accountId);
     }
 
diff --git a/test/integration/smoke/test_primary_storage_scope.py 
b/test/integration/smoke/test_primary_storage_scope.py
new file mode 100644
index 00000000000..e85a06b99f0
--- /dev/null
+++ b/test/integration/smoke/test_primary_storage_scope.py
@@ -0,0 +1,176 @@
+# 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.
+""" BVT tests for Primary Storage
+"""
+
+# Import System modules
+# Import Local Modules
+from marvin.cloudstackTestCase import *
+from marvin.lib.base import (Host, StoragePool, Cluster, updateStoragePool, 
changeStoragePoolScope)
+from marvin.lib.common import (get_zone, get_pod, list_clusters)
+from marvin.lib.utils import cleanup_resources
+from nose.plugins.attrib import attr
+
+class TestPrimaryStorageScope(cloudstackTestCase):
+
+    def setUp(self):
+
+        self.apiclient = self.testClient.getApiClient()
+        self.dbclient = self.testClient.getDbConnection()
+        self.services = self.testClient.getParsedTestDataConfig()
+        self._cleanup = []
+        self.zone = get_zone(self.apiclient, self.testClient.getZoneForTests())
+        self.pod = get_pod(self.apiclient, self.zone.id)
+        self.debug("here")
+        self.debug(self.services)
+        self.cluster1 = list_clusters(self.apiclient)[0]
+        self.debug("here1")
+        self.debug(self.cluster1)
+        self.cluster = {
+            'clustername': 'C0_testScope',
+            'clustertype': 'CloudManaged'
+        }
+        self.cluster2 = Cluster.create(self.apiclient,
+                                       self.cluster,
+                                       zoneid=self.zone.id,
+                                       podid=self.pod.id,
+                                       hypervisor=self.cluster1.hypervisortype
+                                       )
+        self._cleanup.append(self.cluster2)
+        self.storage = StoragePool.create(self.apiclient,
+                                          self.services["nfs"],
+                                          scope = 'ZONE',
+                                          zoneid=self.zone.id,
+                                          
hypervisor=self.cluster1.hypervisortype
+                                          )
+        self._cleanup.append(self.storage)
+        self.debug("Created storage pool %s in zone scope", self.storage.id)
+        return
+
+    def tearDown(self):
+        try:
+            cleanup_resources(self.apiclient, self._cleanup)
+        except Exception as e:
+            raise Exception("Warning: Exception during cleanup : %s" % e)
+        return
+
+    @attr(tags=["advanced", "advancedns", "smoke", "basic", "sg"], 
required_hardware="true")
+    def test_01_primary_storage_scope_change(self):
+        """Test primary storage pool scope change
+        """
+
+        # Disable storage pool
+        cmd = updateStoragePool.updateStoragePoolCmd()
+        cmd.id = self.storage.id
+        cmd.enabled = False
+        self.apiclient.updateStoragePool(cmd)
+
+        self.debug("Disabled storage pool : %s" % self.storage.id)
+
+        # Change storage pool scope to Cluster2
+        cmd = changeStoragePoolScope.changeStoragePoolScopeCmd()
+        cmd.id = self.storage.id
+        cmd.scope = "CLUSTER"
+        cmd.clusterid = self.cluster2.id
+        self.apiclient.changeStoragePoolScope(cmd)
+
+        self.debug("Changed scope of storage pool %s to cluster" % 
self.storage.id)
+
+        pool_id = self.dbclient.execute("select id from storage_pool where 
uuid=\"" + self.storage.id + "\"")[0][0]
+        host1 = Host.list(self.apiclient, clusterid=self.cluster1.id, 
listall=True)[0]
+        host1_id = self.dbclient.execute("select id from host where uuid=\"" + 
host1.id + "\"")[0][0]
+
+        pool_row = self.dbclient.execute("select cluster_id, pod_id, scope 
from storage_pool where id=" + str(pool_id))[0]
+        capacity_row = self.dbclient.execute("select cluster_id, pod_id from 
op_host_capacity where capacity_type=3 and host_id=" + str(pool_id))[0]
+        pool_host_rows = self.dbclient.execute("select id from 
storage_pool_host_ref where host_id=" + str(host1_id) + " and pool_id=" + 
str(pool_id))
+
+        self.assertIsNotNone(
+            pool_row[0],
+            "Cluster id should not be NULL for cluster scope"
+        )
+        self.assertIsNotNone(
+            pool_row[1],
+            "Pod id should not be NULL for cluster scope"
+        )
+        self.assertEqual(
+            pool_row[2],
+            "CLUSTER",
+            "Storage pool scope not changed to Cluster"
+        )
+        self.assertIsNotNone(
+            capacity_row[0],
+            "Cluster id should not be NULL in the op_host_capacity table"
+        )
+        self.assertIsNotNone(
+            capacity_row[1],
+            "Pod id set should not be NULL in the op_host_capacity table"
+        )
+        self.assertEqual(
+            len(pool_host_rows),
+            0,
+            "Storage pool not removed from the storage_pool_host_ref table for 
host on another cluster"
+        )
+
+        # Change storage pool scope to Zone
+        cmd = changeStoragePoolScope.changeStoragePoolScopeCmd()
+        cmd.id = self.storage.id
+        cmd.scope = "ZONE"
+        self.apiclient.changeStoragePoolScope(cmd)
+
+        self.debug("Changed scope of storage pool %s to zone" % 
self.storage.id)
+
+        pool_row = self.dbclient.execute("select cluster_id, pod_id, scope 
from storage_pool where id=" + str(pool_id))[0]
+        capacity_row = self.dbclient.execute("select cluster_id, pod_id from 
op_host_capacity where capacity_type=3 and host_id=" + str(pool_id))[0]
+        pool_host_rows = self.dbclient.execute("select id from 
storage_pool_host_ref where host_id=" + str(host1_id) + " and pool_id=" + 
str(pool_id))
+
+        self.assertIsNone(
+            pool_row[0],
+            "Cluster id not set to NULL for zone scope"
+        )
+        self.assertIsNone(
+            pool_row[1],
+            "Pod id not set to NULL for zone scope"
+        )
+        self.assertEqual(
+            pool_row[2],
+            "ZONE",
+            "Storage pool scope not changed to ZONE"
+        )
+        self.assertIsNone(
+            capacity_row[0],
+            "Cluster id not set to NULL in the op_host_capacity table"
+        )
+        self.assertIsNone(
+            capacity_row[1],
+            "Pod id not set to NULL in the op_host_capacity table"
+        )
+        self.assertEqual(
+            len(pool_host_rows),
+            1,
+            "Storage pool not added to the storage_pool_host_ref table for 
host on another cluster"
+        )
+
+        # Enable storage pool
+        cmd = updateStoragePool.updateStoragePoolCmd()
+        cmd.id = self.storage.id
+        cmd.enabled = True
+        response = self.apiclient.updateStoragePool(cmd)
+        self.assertEqual(
+            response.state,
+            "Up",
+            "Storage pool couldn't be enabled"
+        )
diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py
index b971d244941..fc4d9dab514 100644
--- a/tools/apidoc/gen_toc.py
+++ b/tools/apidoc/gen_toc.py
@@ -142,6 +142,7 @@ known_categories = {
     'StorageMaintenance': 'Storage Pool',
     'StoragePool': 'Storage Pool',
     'StorageProvider': 'Storage Pool',
+    'StorageScope' : 'Storage Pool',
     'updateStorageCapabilities' : 'Storage Pool',
     'SecurityGroup': 'Security Group',
     'SSH': 'SSH',
diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json
index 66d45056c96..c5d87d208b4 100644
--- a/ui/public/locales/en.json
+++ b/ui/public/locales/en.json
@@ -60,6 +60,7 @@
 "label.action.bulk.release.public.ip.address": "Bulk release public IP 
addresses",
 "label.action.cancel.maintenance.mode": "Cancel maintenance mode",
 "label.action.change.password": "Change password",
+"label.action.change.primary.storage.scope": "Change primary storage scope",
 "label.action.configure.stickiness": "Stickiness",
 "label.action.copy.iso": "Copy ISO",
 "label.action.copy.snapshot": "Copy Snapshot",
@@ -2483,6 +2484,8 @@
 "message.action.manage.cluster": "Please confirm that you want to manage the 
cluster.",
 "message.action.patch.router": "Please confirm that you want to live patch the 
router. <br> This operation is equivalent updating the router packages and 
restarting the Network without cleanup.",
 "message.action.patch.systemvm": "Please confirm that you want to patch the 
System VM.",
+"message.action.primary.storage.scope.cluster": "Please confirm that you want 
to change the scope from zone to the specified cluster.<br>This operation will 
update the database and disconnect the storage pool from all hosts that were 
previously connected to the primary storage and are not part of the specified 
cluster.",
+"message.action.primary.storage.scope.zone": "Please confirm that you want to 
change the scope from cluster to zone.<br>This operation will update the 
database and connect the storage pool to all hosts of the zone running the same 
hypervisor as set on the storage pool.",
 "message.action.primarystorage.enable.maintenance.mode": "Warning: placing the 
primary storage into maintenance mode will cause all Instances using volumes 
from it to be stopped.  Do you want to continue?",
 "message.action.reboot.instance": "Please confirm that you want to reboot this 
Instance.",
 "message.action.reboot.router": "All services provided by this virtual router 
will be interrupted. Please confirm that you want to reboot this router.",
@@ -2600,6 +2603,8 @@
 "message.change.offering.for.volume.failed": "Change offering for the volume 
failed",
 "message.change.offering.for.volume.processing": "Changing offering for the 
volume...",
 "message.change.password": "Please change your password.",
+"message.change.scope.failed": "Scope change failed",
+"message.change.scope.processing": "Scope change in progress",
 "message.cluster.dedicated": "Cluster Dedicated",
 "message.cluster.dedication.released": "Cluster dedication released.",
 "message.config.health.monitor.failed": "Configure Health Monitor failed",
@@ -3188,6 +3193,7 @@
 "message.success.change.affinity.group": "Successfully changed affinity 
groups",
 "message.success.change.offering": "Successfully changed offering",
 "message.success.change.password": "Successfully changed password for User",
+"message.success.change.scope": "Successfully changed scope for storage pool",
 "message.success.config.backup.schedule": "Successfully configured Instance 
backup schedule",
 "message.success.config.health.monitor": "Successfully Configure Health 
Monitor",
 "message.success.config.sticky.policy": "Successfully configured sticky 
policy",
@@ -3374,6 +3380,7 @@
 "message.volumes.unmanaged": "Volumes not controlled by CloudStack.",
 "message.vr.alert.upon.network.offering.creation.l2": "As virtual routers are 
not created for L2 Networks, the compute offering will not be used.",
 "message.vr.alert.upon.network.offering.creation.others": "As none of the 
obligatory services for creating a virtual router (VPN, DHCP, DNS, Firewall, 
LB, UserData, SourceNat, StaticNat, PortForwarding) are enabled, the virtual 
router will not be created and the compute offering will not be used.",
+"message.warn.change.primary.storage.scope": "This feature is tested and 
supported for the following configurations:<br>KVM - NFS/Ceph - 
DefaultPrimary<br>VMware - NFS - DefaultPrimary<br>*There might be extra steps 
involved to make it work for other configurations.",
 "message.warn.filetype": "jpg, jpeg, png, bmp and svg are the only supported 
image formats.",
 "message.warn.importing.instance.without.nic": "WARNING: This Instance is 
being imported without NICs and many Network resources will not be available. 
Consider creating a NIC via vCenter before importing or as soon as the Instance 
is imported.",
 "message.warn.zone.mtu.update": "Please note that this limit won't affect 
pre-existing Network’s MTU settings",
diff --git a/ui/src/config/section/infra/primaryStorages.js 
b/ui/src/config/section/infra/primaryStorages.js
index 24333367f1c..c4932b2daad 100644
--- a/ui/src/config/section/infra/primaryStorages.js
+++ b/ui/src/config/section/infra/primaryStorages.js
@@ -135,6 +135,26 @@ export default {
       dataView: true,
       show: (record) => { return ['Maintenance', 'PrepareForMaintenance', 
'ErrorInMaintenance'].includes(record.state) }
     },
+    {
+      api: 'changeStoragePoolScope',
+      icon: 'swap-outlined',
+      label: 'label.action.change.primary.storage.scope',
+      dataView: true,
+      popup: true,
+      show: (record) => {
+        return (record.state === 'Disabled' &&
+          (record.scope === 'CLUSTER' ||
+           record.scope === 'ZONE') &&
+          (record.hypervisor === 'KVM' ||
+           record.hypervisor === 'VMware' ||
+           record.hypervisor === 'HyperV' ||
+           record.hypervisor === 'LXC' ||
+           record.hypervisor === 'Any' ||
+           record.hypervisor === 'Simulator')
+        )
+      },
+      component: shallowRef(defineAsyncComponent(() => 
import('@/views/infra/ChangeStoragePoolScope.vue')))
+    },
     {
       api: 'deleteStoragePool',
       icon: 'delete-outlined',
diff --git a/ui/src/core/lazy_lib/icons_use.js 
b/ui/src/core/lazy_lib/icons_use.js
index 2e0eea4f84b..ce57625d6e7 100644
--- a/ui/src/core/lazy_lib/icons_use.js
+++ b/ui/src/core/lazy_lib/icons_use.js
@@ -21,6 +21,7 @@ import {
   ApiOutlined,
   AppstoreOutlined,
   ArrowDownOutlined,
+  ArrowRightOutlined,
   ArrowUpOutlined,
   ArrowsAltOutlined,
   AuditOutlined,
@@ -182,6 +183,7 @@ export default {
     app.component('ApiOutlined', ApiOutlined)
     app.component('AppstoreOutlined', AppstoreOutlined)
     app.component('ArrowDownOutlined', ArrowDownOutlined)
+    app.component('ArrowRightOutlined', ArrowRightOutlined)
     app.component('ArrowUpOutlined', ArrowUpOutlined)
     app.component('ArrowsAltOutlined', ArrowsAltOutlined)
     app.component('AuditOutlined', AuditOutlined)
diff --git a/ui/src/views/infra/ChangeStoragePoolScope.vue 
b/ui/src/views/infra/ChangeStoragePoolScope.vue
new file mode 100644
index 00000000000..1e1c14201b9
--- /dev/null
+++ b/ui/src/views/infra/ChangeStoragePoolScope.vue
@@ -0,0 +1,223 @@
+// 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.
+
+<template>
+  <a-spin :spinning="loading">
+    <div class="form-layout" v-ctrl-enter="handleSubmitForm">
+      <div class="form">
+        <a-form
+          :ref="formRef"
+          :model="form"
+          :rules="rules"
+          layout="vertical"
+          @submit="handleSubmitForm">
+          <a-alert type="warning">
+            <template #message>
+              <span
+                v-html="(resource.scope=='ZONE' ? 
$t('message.action.primary.storage.scope.cluster') : 
$t('message.action.primary.storage.scope.zone')) +
+                        '<br><br>' + 
$t('message.warn.change.primary.storage.scope')"></span>
+            </template>
+          </a-alert>
+          <p></p>
+          <a-form-item name="clusterid" ref="clusterid" 
v-if="resource.scope=='ZONE'">
+            <template #label>
+              <tooltip-label :title="$t('label.clustername')" 
:tooltip="placeholder.clusterid"/>
+            </template>
+            <a-select
+              v-model:value="form.clusterid"
+              :placeholder="placeholder.clusterid"
+              showSearch
+              optionFilterProp="label"
+              :filterOption="(input, option) => {
+                return option.label.toLowerCase().indexOf(input.toLowerCase()) 
>= 0
+              }"
+              @change="handleChangeCluster">
+              <a-select-option
+                v-for="cluster in clustersList"
+                :value="cluster.id"
+                :key="cluster.id"
+                :label="cluster.name">
+                {{ cluster.name }}
+              </a-select-option>
+            </a-select>
+          </a-form-item>
+
+          <div :span="24" class="action-button">
+            <a-button @click="closeAction">{{ $t('label.cancel') }}</a-button>
+            <a-button @click="handleSubmitForm" ref="submit" type="primary">{{ 
$t('label.ok') }}</a-button>
+          </div>
+        </a-form>
+      </div>
+    </div>
+  </a-spin>
+</template>
+
+<script>
+import { ref, reactive, toRaw } from 'vue'
+import { api } from '@/api'
+import { mixinForm } from '@/utils/mixin'
+import DedicateDomain from '../../components/view/DedicateDomain'
+import ResourceIcon from '@/components/view/ResourceIcon'
+import TooltipLabel from '@/components/widgets/TooltipLabel'
+
+export default {
+  name: 'ChangeStoragePoolScope',
+  mixins: [mixinForm],
+  components: {
+    DedicateDomain,
+    ResourceIcon,
+    TooltipLabel
+  },
+  props: {
+    resource: {
+      type: Object,
+      required: true
+    }
+  },
+  data () {
+    return {
+      loading: false,
+      clustersList: [],
+      selectedCluster: null,
+      placeholder: {
+        clusterid: null
+      }
+    }
+  },
+  created () {
+    this.initForm()
+    this.fetchData()
+  },
+  methods: {
+    initForm () {
+      this.formRef = ref()
+      this.form = reactive({ })
+      this.rules = reactive({
+        clusterid: [{ required: true, message: this.$t('message.error.select') 
}]
+      })
+    },
+    fetchData () {
+      this.fetchClusters(this.resource.zoneid)
+    },
+    fetchClusters (zoneId) {
+      this.form.clusterid = null
+      this.clustersList = []
+      if (!zoneId) return
+      this.zoneId = zoneId
+      this.loading = true
+      api('listClusters', { zoneid: zoneId }).then(response => {
+        this.clustersList = response.listclustersresponse.cluster || []
+        this.form.clusterid = this.clustersList[0].id || null
+        if (this.form.clusterid) {
+          this.handleChangeCluster(this.form.clusterid)
+        }
+      }).catch(error => {
+        this.$notifyError(error)
+        this.clustersList = []
+        this.form.clusterid = null
+      }).finally(() => {
+        this.loading = false
+      })
+    },
+    handleChangeCluster (value) {
+      this.form.clusterid = value
+      this.selectedCluster = this.clustersList.find(i => i.id === 
this.form.clusterid)
+    },
+    handleSubmitForm () {
+      if (this.loading) return
+      this.formRef.value.validate().then(() => {
+        const formRaw = toRaw(this.form)
+        const values = this.handleRemoveFields(formRaw)
+
+        this.args = {}
+        if (this.resource.scope === 'ZONE') {
+          this.args = {
+            id: this.resource.id,
+            scope: 'CLUSTER',
+            clusterid: values.clusterid
+          }
+        } else {
+          this.args = {
+            id: this.resource.id,
+            scope: 'ZONE'
+          }
+        }
+
+        this.changeStoragePoolScope(this.args)
+      }).catch(error => {
+        this.formRef.value.scrollToField(error.errorFields[0].name)
+      })
+    },
+    closeAction () {
+      this.$emit('close-action')
+    },
+    changeStoragePoolScope (args) {
+      api('changeStoragePoolScope', args).then(json => {
+        this.$pollJob({
+          jobId: json.changestoragepoolscoperesponse.jobid,
+          title: this.$t('message.success.change.scope'),
+          description: args.name,
+          successMessage: this.$t('message.success.change.scope'),
+          successMethod: (result) => {
+            this.closeAction()
+          },
+          errorMessage: this.$t('message.change.scope.failed'),
+          loadingMessage: this.$t('message.change.scope.processing'),
+          catchMessage: this.$t('error.fetching.async.job.result')
+        })
+        this.closeAction()
+      }).catch(error => {
+        this.$notifyError(error)
+      }).finally(() => {
+        this.loading = false
+      })
+    }
+
+  }
+}
+</script>
+
+<style lang="scss">
+  .form {
+    &__label {
+      margin-bottom: 5px;
+
+      .required {
+        margin-left: 10px;
+      }
+    }
+    &__item {
+      margin-bottom: 20px;
+    }
+    .ant-select {
+      width: 85vw;
+      @media (min-width: 760px) {
+        width: 400px;
+      }
+    }
+  }
+
+  .required {
+    color: #ff0000;
+    &-label {
+      display: none;
+      &--error {
+        display: block;
+      }
+    }
+  }
+</style>

Reply via email to