diff --git a/api/src/main/java/com/cloud/storage/Storage.java b/api/src/main/java/com/cloud/storage/Storage.java index d44628a198a..300944559d6 100644 --- a/api/src/main/java/com/cloud/storage/Storage.java +++ b/api/src/main/java/com/cloud/storage/Storage.java @@ -148,7 +148,8 @@ public class Storage { PowerFlex(true, true), // Dell EMC PowerFlex/ScaleIO (formerly VxFlexOS) ManagedNFS(true, false), Linstor(true, true), - DatastoreCluster(true, true); // for VMware, to abstract pool of clusters + DatastoreCluster(true, true), // for VMware, to abstract pool of clusters + StorPool(true, true); private final boolean shared; private final boolean overprovisioning; diff --git a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41700to41710.java b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41700to41710.java index 6841e7de3b7..5959dd46990 100644 --- a/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41700to41710.java +++ b/engine/schema/src/main/java/com/cloud/upgrade/dao/Upgrade41700to41710.java @@ -16,18 +16,30 @@ // under the License. package com.cloud.upgrade.dao; -import com.cloud.upgrade.SystemVmTemplateRegistration; -import com.cloud.utils.exception.CloudRuntimeException; -import org.apache.log4j.Logger; - import java.io.InputStream; import java.sql.Connection; +import java.util.List; + +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; +import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDaoImpl; +import org.apache.cloudstack.storage.datastore.db.StoragePoolVO; +import org.apache.log4j.Logger; + +import com.cloud.storage.Storage.StoragePoolType; +import com.cloud.storage.VolumeVO; +import com.cloud.storage.dao.VolumeDao; +import com.cloud.storage.dao.VolumeDaoImpl; +import com.cloud.upgrade.SystemVmTemplateRegistration; +import com.cloud.utils.exception.CloudRuntimeException; public class Upgrade41700to41710 implements DbUpgrade, DbUpgradeSystemVmTemplate { final static Logger LOG = Logger.getLogger(Upgrade41610to41700.class); private SystemVmTemplateRegistration systemVmTemplateRegistration; + private PrimaryDataStoreDao storageDao; + private VolumeDao volumeDao; + @Override public String[] getUpgradableVersionRange() { return new String[] {"4.17.0.0", "4.17.1.0"}; @@ -56,6 +68,7 @@ public class Upgrade41700to41710 implements DbUpgrade, DbUpgradeSystemVmTemplate @Override public void performDataMigration(Connection conn) { + updateStorPoolStorageType(); } @Override @@ -83,4 +96,25 @@ public class Upgrade41700to41710 implements DbUpgrade, DbUpgradeSystemVmTemplate throw new CloudRuntimeException("Failed to find / register SystemVM template(s)"); } } + + private void updateStorPoolStorageType() { + storageDao = new PrimaryDataStoreDaoImpl(); + List storPoolPools = storageDao.findPoolsByProvider("StorPool"); + for (StoragePoolVO storagePoolVO : storPoolPools) { + if (StoragePoolType.SharedMountPoint == storagePoolVO.getPoolType()) { + storagePoolVO.setPoolType(StoragePoolType.StorPool); + storageDao.update(storagePoolVO.getId(), storagePoolVO); + } + updateStorageTypeForStorPoolVolumes(storagePoolVO.getId()); + } + } + + private void updateStorageTypeForStorPoolVolumes(long storagePoolId) { + volumeDao = new VolumeDaoImpl(); + List volumes = volumeDao.findByPoolId(storagePoolId, null); + for (VolumeVO volumeVO : volumes) { + volumeVO.setPoolType(StoragePoolType.StorPool); + volumeDao.update(volumeVO.getId(), volumeVO); + } + } } diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index 097aafe06e5..e59ddaeac9a 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -2848,7 +2848,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv dataStoreUrl = "nfs://" + psHost + File.separator + psPath; physicalDisk = getPhysicalDiskFromNfsStore(dataStoreUrl, data); } else if (primaryDataStoreTO.getPoolType().equals(StoragePoolType.SharedMountPoint) || - primaryDataStoreTO.getPoolType().equals(StoragePoolType.Filesystem)) { + primaryDataStoreTO.getPoolType().equals(StoragePoolType.Filesystem) || + primaryDataStoreTO.getPoolType().equals(StoragePoolType.StorPool)) { physicalDisk = getPhysicalDiskPrimaryStore(primaryDataStoreTO, data); } } @@ -2868,7 +2869,8 @@ public class LibvirtComputingResource extends ServerResourceBase implements Serv && (pool.getType() == StoragePoolType.NetworkFilesystem || pool.getType() == StoragePoolType.SharedMountPoint || pool.getType() == StoragePoolType.Filesystem - || pool.getType() == StoragePoolType.Gluster)) { + || pool.getType() == StoragePoolType.Gluster + || pool.getType() == StoragePoolType.StorPool)) { setBackingFileFormat(physicalDisk.getPath()); } diff --git a/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/storage/StorPoolStorageAdaptor.java b/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/storage/StorPoolStorageAdaptor.java index a35787c205b..d0fe5adaeee 100644 --- a/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/storage/StorPoolStorageAdaptor.java +++ b/plugins/storage/volume/storpool/src/main/java/com/cloud/hypervisor/kvm/storage/StorPoolStorageAdaptor.java @@ -39,7 +39,7 @@ import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.script.OutputInterpreter; import com.cloud.utils.script.Script; -@StorageAdaptorInfo(storagePoolType=StoragePoolType.SharedMountPoint) +@StorageAdaptorInfo(storagePoolType=StoragePoolType.StorPool) public class StorPoolStorageAdaptor implements StorageAdaptor { public static void SP_LOG(String fmt, Object... args) { try (PrintWriter spLogFile = new PrintWriter(new BufferedWriter(new FileWriter("/var/log/cloudstack/agent/storpool-agent.log", true)))) { diff --git a/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/driver/StorPoolPrimaryDataStoreDriver.java b/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/driver/StorPoolPrimaryDataStoreDriver.java index e9429c274fc..c5c2bc71a40 100644 --- a/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/driver/StorPoolPrimaryDataStoreDriver.java +++ b/plugins/storage/volume/storpool/src/main/java/org/apache/cloudstack/storage/datastore/driver/StorPoolPrimaryDataStoreDriver.java @@ -233,7 +233,6 @@ public class StorPoolPrimaryDataStoreDriver implements PrimaryDataStoreDriver { VolumeVO volume = volumeDao.findById(vinfo.getId()); volume.setPoolId(dataStore.getId()); - volume.setPoolType(StoragePoolType.SharedMountPoint); volume.setPath(path); volumeDao.update(volume.getId(), volume); @@ -716,7 +715,7 @@ public class StorPoolPrimaryDataStoreDriver implements PrimaryDataStoreDriver { final String name = StorPoolStorageAdaptor.getVolumeNameFromPath(srcTO.getPath(), true); StorPoolUtil.spLog("StorpoolPrimaryDataStoreDriverImpl.copyAsnc DST tmpSnapName=%s ,srcUUID=%s", name, srcTO.getUuid()); - if (checkStoragePool != null && checkStoragePool.getPoolType().equals(StoragePoolType.SharedMountPoint)) { + if (checkStoragePool != null && checkStoragePool.getPoolType().equals(StoragePoolType.StorPool)) { SpConnectionDesc conn = StorPoolUtil.getSpConnection(dstData.getDataStore().getUuid(), dstData.getDataStore().getId(), storagePoolDetailsDao, primaryStoreDao); String baseOn = StorPoolStorageAdaptor.getVolumeNameFromPath(srcTO.getPath(), true); //uuid tag will be the same as srcData.uuid 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 8ed39327f39..4dbc7e4a22c 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 @@ -164,7 +164,7 @@ public class StorPoolPrimaryDataStoreLifeCycle implements PrimaryDataStoreLifeCy parameters.setUuid(conn.getTemplateName() + ";" + UUID.randomUUID().toString()); parameters.setZoneId(zoneId); parameters.setProviderName(providerName); - parameters.setType(StoragePoolType.SharedMountPoint); + parameters.setType(StoragePoolType.StorPool); parameters.setHypervisorType(HypervisorType.KVM); parameters.setManaged(false); parameters.setHost("n/a"); diff --git a/server/src/main/java/com/cloud/network/NetworkModelImpl.java b/server/src/main/java/com/cloud/network/NetworkModelImpl.java index 66d79cc3504..c601c13e6ad 100644 --- a/server/src/main/java/com/cloud/network/NetworkModelImpl.java +++ b/server/src/main/java/com/cloud/network/NetworkModelImpl.java @@ -1659,7 +1659,7 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi } @Override - public void checkNetworkPermissions(Account owner, Network network) { + public void checkNetworkPermissions(Account caller, Network network) { // dahn 20140310: I was thinking of making this an assert but // as we hardly ever test with asserts I think // we better make sure at runtime. @@ -1672,11 +1672,11 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi if (networkOwner == null) throw new PermissionDeniedException("Unable to use network with id= " + ((NetworkVO)network).getUuid() + ", network does not have an owner"); - if (owner.getType() != Account.Type.PROJECT && networkOwner.getType() == Account.Type.PROJECT) { - checkProjectNetworkPermissions(owner, networkOwner, network); + if (!Account.Type.PROJECT.equals(caller.getType()) && Account.Type.PROJECT.equals(networkOwner.getType())) { + checkProjectNetworkPermissions(caller, networkOwner, network); } else { - List networkMap = _networksDao.listBy(owner.getId(), network.getId()); - NetworkPermissionVO networkPermission = _networkPermissionDao.findByNetworkAndAccount(network.getId(), owner.getId()); + List networkMap = _networksDao.listBy(caller.getId(), network.getId()); + NetworkPermissionVO networkPermission = _networkPermissionDao.findByNetworkAndAccount(network.getId(), caller.getId()); if (CollectionUtils.isEmpty(networkMap) && networkPermission == null) { throw new PermissionDeniedException("Unable to use network with id= " + ((NetworkVO)network).getUuid() + ", permission denied"); @@ -1684,13 +1684,13 @@ public class NetworkModelImpl extends ManagerBase implements NetworkModel, Confi } } else { - if (!isNetworkAvailableInDomain(network.getId(), owner.getDomainId())) { - DomainVO ownerDomain = _domainDao.findById(owner.getDomainId()); - if (ownerDomain == null) { - throw new CloudRuntimeException("cannot check permission on account " + owner.getAccountName() + " whose domain does not exist"); + if (!isNetworkAvailableInDomain(network.getId(), caller.getDomainId())) { + DomainVO callerDomain = _domainDao.findById(caller.getDomainId()); + if (callerDomain == null) { + throw new CloudRuntimeException("cannot check permission on account " + caller.getAccountName() + " whose domain does not exist"); } throw new PermissionDeniedException("Shared network id=" + ((NetworkVO)network).getUuid() + " is not available in domain id=" + - ownerDomain.getUuid()); + callerDomain.getUuid()); } } } diff --git a/server/src/main/java/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java b/server/src/main/java/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java index 1c9af7a334d..d9f1db616f5 100644 --- a/server/src/main/java/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java +++ b/server/src/main/java/org/apache/cloudstack/network/lb/ApplicationLoadBalancerManagerImpl.java @@ -113,7 +113,7 @@ public class ApplicationLoadBalancerManagerImpl extends ManagerBase implements A } Account caller = CallContext.current().getCallingAccount(); - _accountMgr.checkAccess(caller, AccessType.UseEntry, false, guestNtwk); + _accountMgr.checkAccess(caller, AccessType.OperateEntry, false, guestNtwk); Network sourceIpNtwk = _networkModel.getNetwork(sourceIpNetworkId); if (sourceIpNtwk == null) { diff --git a/server/src/test/java/com/cloud/network/NetworkModelTest.java b/server/src/test/java/com/cloud/network/NetworkModelTest.java index af14cbd7adc..b52335035fd 100644 --- a/server/src/test/java/com/cloud/network/NetworkModelTest.java +++ b/server/src/test/java/com/cloud/network/NetworkModelTest.java @@ -31,35 +31,50 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.List; +import java.util.Set; -import com.cloud.dc.DataCenter; -import com.cloud.dc.DataCenterVO; -import com.cloud.dc.dao.DataCenterDao; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.network.dao.PhysicalNetworkDao; -import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; -import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; -import com.cloud.network.dao.PhysicalNetworkVO; -import junit.framework.Assert; - +import org.apache.cloudstack.network.NetworkPermissionVO; +import org.apache.cloudstack.network.dao.NetworkPermissionDao; import org.junit.Before; import org.junit.Test; - -import com.cloud.dc.VlanVO; -import com.cloud.dc.dao.VlanDao; -import com.cloud.network.dao.IPAddressDao; -import com.cloud.network.dao.IPAddressVO; -import com.cloud.user.Account; -import com.cloud.utils.db.Filter; -import com.cloud.utils.db.SearchBuilder; -import com.cloud.utils.db.SearchCriteria; -import com.cloud.utils.net.Ip; -import com.cloud.network.Network.Provider; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.MockitoAnnotations; import org.mockito.Spy; +import com.cloud.dc.DataCenter; +import com.cloud.dc.DataCenterVO; +import com.cloud.dc.VlanVO; +import com.cloud.dc.dao.DataCenterDao; +import com.cloud.dc.dao.VlanDao; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.PermissionDeniedException; +import com.cloud.network.Network.Provider; +import com.cloud.network.dao.IPAddressDao; +import com.cloud.network.dao.IPAddressVO; +import com.cloud.network.dao.NetworkDao; +import com.cloud.network.dao.NetworkDomainDao; +import com.cloud.network.dao.NetworkDomainVO; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.projects.dao.ProjectDao; +import com.cloud.user.Account; +import com.cloud.user.AccountVO; +import com.cloud.user.DomainManager; +import com.cloud.user.dao.AccountDao; +import com.cloud.utils.db.Filter; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.Ip; + +import junit.framework.Assert; + public class NetworkModelTest { @Mock @@ -85,6 +100,20 @@ public class NetworkModelTest { private PhysicalNetworkVO physicalNetworkZone2; @Mock private PhysicalNetworkServiceProviderVO providerVO; + @Mock + private AccountDao accountDao; + @Mock + private NetworkDao networkDao; + @Mock + private NetworkPermissionDao networkPermissionDao; + @Mock + private NetworkDomainDao networkDomainDao; + @Mock + private DomainManager domainManager; + @Mock + private DomainDao domainDao; + @Mock + private ProjectDao projectDao; private static final long ZONE_1_ID = 1L; private static final long ZONE_2_ID = 2L; @@ -263,4 +292,116 @@ public class NetworkModelTest { networkModel.checkIp6Parameters(null, null, IPV6_GATEWAY,IPV6_CIDR); } + @Test + public void testCheckNetworkPermissions() { + long accountId = 1L; + AccountVO caller = mock(AccountVO.class); + when(caller.getId()).thenReturn(accountId); + when(caller.getType()).thenReturn(Account.Type.NORMAL); + NetworkVO network = mock(NetworkVO.class); + when(network.getGuestType()).thenReturn(Network.GuestType.Isolated); + when(network.getAccountId()).thenReturn(accountId); + when(accountDao.findById(accountId)).thenReturn(caller); + when(networkDao.listBy(caller.getId(), network.getId())).thenReturn(List.of(network)); + when(networkPermissionDao.findByNetworkAndAccount(network.getId(), caller.getId())).thenReturn(mock(NetworkPermissionVO.class)); + networkModel.checkNetworkPermissions(caller, network); + } + + @Test(expected = CloudRuntimeException.class) + public void testCheckNetworkPermissionsNullNetwork() { + AccountVO caller = mock(AccountVO.class); + NetworkVO network = null; + networkModel.checkNetworkPermissions(caller, network); + } + + @Test(expected = PermissionDeniedException.class) + public void testCheckNetworkPermissionsNoOwner() { + long accountId = 1L; + AccountVO caller = mock(AccountVO.class); + when(caller.getId()).thenReturn(accountId); + when(caller.getType()).thenReturn(Account.Type.NORMAL); + NetworkVO network = mock(NetworkVO.class); + when(network.getGuestType()).thenReturn(Network.GuestType.Isolated); + when(network.getAccountId()).thenReturn(accountId); + when(accountDao.findById(accountId)).thenReturn(null); + networkModel.checkNetworkPermissions(caller, network); + } + + @Test(expected = PermissionDeniedException.class) + public void testCheckNetworkPermissionsNoPermission() { + long accountId = 1L; + AccountVO caller = mock(AccountVO.class); + when(caller.getId()).thenReturn(accountId); + when(caller.getType()).thenReturn(Account.Type.NORMAL); + NetworkVO network = mock(NetworkVO.class); + when(network.getGuestType()).thenReturn(Network.GuestType.Isolated); + when(network.getAccountId()).thenReturn(accountId); + when(accountDao.findById(accountId)).thenReturn(caller); + when(networkDao.listBy(caller.getId(), network.getId())).thenReturn(null); + when(networkPermissionDao.findByNetworkAndAccount(network.getId(), caller.getId())).thenReturn(null); + networkModel.checkNetworkPermissions(caller, network); + } + + @Test + public void testCheckNetworkPermissionsSharedNetwork() { + long id = 1L; + long subDomainId = 2L; + AccountVO caller = mock(AccountVO.class); + when(caller.getId()).thenReturn(id); + when(caller.getDomainId()).thenReturn(id); + when(caller.getType()).thenReturn(Account.Type.NORMAL); + NetworkVO network = mock(NetworkVO.class); + when(network.getGuestType()).thenReturn(Network.GuestType.Shared); + when(network.getId()).thenReturn(id); + when(networkDao.findById(network.getId())).thenReturn(network); + NetworkDomainVO networkDomainVO = mock(NetworkDomainVO.class); + when(networkDomainVO.getDomainId()).thenReturn(id); + when(networkDomainDao.getDomainNetworkMapByNetworkId(id)).thenReturn(networkDomainVO); + networkModel.checkNetworkPermissions(caller, network); + when(caller.getDomainId()).thenReturn(subDomainId); + networkDomainVO.subdomainAccess = Boolean.TRUE; + when(domainManager.getDomainParentIds(subDomainId)).thenReturn(Set.of(id)); + networkModel.checkNetworkPermissions(caller, network); + } + + @Test(expected = PermissionDeniedException.class) + public void testCheckNetworkPermissionsSharedNetworkNoSubDomainAccess() { + long id = 1L; + long subDomainId = 2L; + AccountVO caller = mock(AccountVO.class); + when(caller.getId()).thenReturn(id); + when(caller.getDomainId()).thenReturn(subDomainId); + when(caller.getType()).thenReturn(Account.Type.NORMAL); + NetworkVO network = mock(NetworkVO.class); + when(network.getGuestType()).thenReturn(Network.GuestType.Shared); + when(network.getId()).thenReturn(id); + when(networkDao.findById(network.getId())).thenReturn(network); + when(domainDao.findById(caller.getDomainId())).thenReturn(mock(DomainVO.class)); + NetworkDomainVO networkDomainVO = mock(NetworkDomainVO.class); + when(networkDomainVO.getDomainId()).thenReturn(id); + networkDomainVO.subdomainAccess = Boolean.FALSE; + when(networkDomainDao.getDomainNetworkMapByNetworkId(id)).thenReturn(networkDomainVO); + networkModel.checkNetworkPermissions(caller, network); + } + + @Test(expected = PermissionDeniedException.class) + public void testCheckNetworkPermissionsSharedNetworkNotSubDomain() { + long id = 1L; + long subDomainId = 2L; + AccountVO caller = mock(AccountVO.class); + when(caller.getId()).thenReturn(id); + when(caller.getDomainId()).thenReturn(subDomainId); + when(caller.getType()).thenReturn(Account.Type.NORMAL); + NetworkVO network = mock(NetworkVO.class); + when(network.getGuestType()).thenReturn(Network.GuestType.Shared); + when(network.getId()).thenReturn(id); + when(networkDao.findById(network.getId())).thenReturn(network); + when(domainDao.findById(caller.getDomainId())).thenReturn(mock(DomainVO.class)); + NetworkDomainVO networkDomainVO = mock(NetworkDomainVO.class); + when(networkDomainVO.getDomainId()).thenReturn(id); + networkDomainVO.subdomainAccess = Boolean.TRUE; + when(networkDomainDao.getDomainNetworkMapByNetworkId(id)).thenReturn(networkDomainVO); + when(domainManager.getDomainParentIds(subDomainId)).thenReturn(Set.of(0L)); + networkModel.checkNetworkPermissions(caller, network); + } }