mirror of
https://github.com/apache/cloudstack.git
synced 2025-10-26 08:42:29 +01:00
Merge remote-tracking branch 'origin/4.17'
This commit is contained in:
commit
840c3f6a7a
@ -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;
|
||||
|
||||
@ -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<StoragePoolVO> 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<VolumeVO> volumes = volumeDao.findByPoolId(storagePoolId, null);
|
||||
for (VolumeVO volumeVO : volumes) {
|
||||
volumeVO.setPoolType(StoragePoolType.StorPool);
|
||||
volumeDao.update(volumeVO.getId(), volumeVO);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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());
|
||||
}
|
||||
|
||||
|
||||
@ -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)))) {
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -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<NetworkVO> networkMap = _networksDao.listBy(owner.getId(), network.getId());
|
||||
NetworkPermissionVO networkPermission = _networkPermissionDao.findByNetworkAndAccount(network.getId(), owner.getId());
|
||||
List<NetworkVO> 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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user