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

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


The following commit(s) were added to refs/heads/main by this push:
     new cb62ce67671 Global ACL for VPCs (#7150)
cb62ce67671 is described below

commit cb62ce67671699fa01564b3b4b0d3d83eb3d5acb
Author: Bryan Lima <[email protected]>
AuthorDate: Thu Nov 30 10:51:43 2023 -0300

    Global ACL for VPCs (#7150)
---
 .github/workflows/ci.yml                           |   3 +-
 .../user/network/CreateNetworkACLListCmd.java      |  36 ++-
 .../java/com/cloud/network/vpc/NetworkACLVO.java   |   7 +
 .../java/com/cloud/network/NetworkServiceImpl.java |  17 +-
 .../cloud/network/vpc/NetworkACLServiceImpl.java   | 131 +++++++----
 .../java/com/cloud/network/vpc/VpcManagerImpl.java |  14 +-
 .../network/vpc/NetworkACLServiceImplTest.java     | 145 ++++++++----
 test/integration/smoke/test_global_acls.py         | 245 +++++++++++++++++++++
 8 files changed, 489 insertions(+), 109 deletions(-)

diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index d6b5f5a1c4f..77c9d59505c 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -111,7 +111,8 @@ jobs:
                   smoke/test_reset_configuration_settings
                   smoke/test_reset_vm_on_reboot
                   smoke/test_resource_accounting
-                  smoke/test_resource_detail",
+                  smoke/test_resource_detail
+                  smoke/test_global_acls",
                 "smoke/test_router_dhcphosts
                   smoke/test_router_dns
                   smoke/test_router_dnsservice
diff --git 
a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java
 
b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java
index 14dbfcafd7b..e5dbcc7b6d1 100644
--- 
a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java
+++ 
b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkACLListCmd.java
@@ -16,6 +16,7 @@
 // under the License.
 package org.apache.cloudstack.api.command.user.network;
 
+import com.cloud.exception.PermissionDeniedException;
 import org.apache.cloudstack.acl.RoleType;
 import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiCommandResourceType;
@@ -26,6 +27,7 @@ import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.api.response.NetworkACLResponse;
 import org.apache.cloudstack.api.response.VpcResponse;
+import org.apache.cloudstack.context.CallContext;
 import org.apache.log4j.Logger;
 
 import com.cloud.event.EventTypes;
@@ -35,7 +37,8 @@ import com.cloud.network.vpc.NetworkACL;
 import com.cloud.network.vpc.Vpc;
 import com.cloud.user.Account;
 
-@APICommand(name = "createNetworkACLList", description = "Creates a network 
ACL for the given VPC", responseObject = NetworkACLResponse.class,
+@APICommand(name = "createNetworkACLList", description = "Creates a network 
ACL. If no VPC is given, then it creates a global ACL that can be used by 
everyone.",
+        responseObject = NetworkACLResponse.class,
         requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
 public class CreateNetworkACLListCmd extends BaseAsyncCreateCmd {
     public static final Logger s_logger = 
Logger.getLogger(CreateNetworkACLListCmd.class.getName());
@@ -53,7 +56,6 @@ public class CreateNetworkACLListCmd extends 
BaseAsyncCreateCmd {
 
     @Parameter(name = ApiConstants.VPC_ID,
                type = CommandType.UUID,
-               required = true,
                entityType = VpcResponse.class,
                description = "ID of the VPC associated with this network ACL 
list")
     private Long vpcId;
@@ -77,6 +79,10 @@ public class CreateNetworkACLListCmd extends 
BaseAsyncCreateCmd {
         return vpcId;
     }
 
+    public void setVpcId(Long vpcId) {
+        this.vpcId = vpcId;
+    }
+
     @Override
     public boolean isDisplay() {
         if (display != null) {
@@ -92,6 +98,9 @@ public class CreateNetworkACLListCmd extends 
BaseAsyncCreateCmd {
 
     @Override
     public void create() {
+        if (getVpcId() == null) {
+            setVpcId(0L);
+        }
         NetworkACL result = _networkACLService.createNetworkACL(getName(), 
getDescription(), getVpcId(), isDisplay());
         setEntityId(result.getId());
         setEntityUuid(result.getUuid());
@@ -111,12 +120,21 @@ public class CreateNetworkACLListCmd extends 
BaseAsyncCreateCmd {
 
     @Override
     public long getEntityOwnerId() {
-        Vpc vpc = _entityMgr.findById(Vpc.class, getVpcId());
-        if (vpc == null) {
-            throw new InvalidParameterValueException("Invalid vpcId is given");
-        }
+        Account account;
+        if (isAclAttachedToVpc(this.vpcId)) {
+            Vpc vpc = _entityMgr.findById(Vpc.class, this.vpcId);
+            if (vpc == null) {
+                throw new 
InvalidParameterValueException(String.format("Invalid VPC ID [%s] provided.", 
this.vpcId));
+            }
+            account = _accountService.getAccount(vpc.getAccountId());
+        } else {
+            account = CallContext.current().getCallingAccount();
+            if (!Account.Type.ADMIN.equals(account.getType())) {
+                s_logger.warn(String.format("Only Root Admin can create global 
ACLs. Account [%s] cannot create any global ACL.", account));
+                throw new PermissionDeniedException("Only Root Admin can 
create global ACLs.");
+            }
 
-        Account account = _accountService.getAccount(vpc.getAccountId());
+        }
         return account.getId();
     }
 
@@ -139,4 +157,8 @@ public class CreateNetworkACLListCmd extends 
BaseAsyncCreateCmd {
     public ApiCommandResourceType getApiResourceType() {
         return ApiCommandResourceType.NetworkAcl;
     }
+
+    public boolean isAclAttachedToVpc(Long aclVpcId) {
+        return aclVpcId != null && aclVpcId != 0;
+    }
 }
diff --git 
a/engine/schema/src/main/java/com/cloud/network/vpc/NetworkACLVO.java 
b/engine/schema/src/main/java/com/cloud/network/vpc/NetworkACLVO.java
index 4eaa2b575e0..280d5dfaf4b 100644
--- a/engine/schema/src/main/java/com/cloud/network/vpc/NetworkACLVO.java
+++ b/engine/schema/src/main/java/com/cloud/network/vpc/NetworkACLVO.java
@@ -17,6 +17,8 @@
 
 package com.cloud.network.vpc;
 
+import 
org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
+
 import java.util.UUID;
 
 import javax.persistence.Column;
@@ -85,6 +87,11 @@ public class NetworkACLVO implements NetworkACL {
         return name;
     }
 
+    @Override
+    public String toString() {
+        return ReflectionToStringBuilderUtils.reflectOnlySelectedFields(this, 
"uuid", "name", "vpcId");
+    }
+
     public void setUuid(String uuid) {
         this.uuid = uuid;
     }
diff --git a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java 
b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
index f9f80cb5b76..18f98e6f99f 100644
--- a/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
+++ b/server/src/main/java/com/cloud/network/NetworkServiceImpl.java
@@ -2100,12 +2100,9 @@ public class NetworkServiceImpl extends ManagerBase 
implements NetworkService, C
                                 throw new 
InvalidParameterValueException("Unable to find specified NetworkACL");
                             }
 
-                            if (aclId != NetworkACL.DEFAULT_DENY && aclId != 
NetworkACL.DEFAULT_ALLOW) {
-                                // ACL is not default DENY/ALLOW
-                                // ACL should be associated with a VPC
-                                if (!vpcId.equals(acl.getVpcId())) {
-                                    throw new 
InvalidParameterValueException("ACL: " + aclId + " do not belong to the VPC");
-                                }
+                            Long aclVpcId = acl.getVpcId();
+                            if (!isDefaultAcl(aclId) && 
isAclAttachedToVpc(aclVpcId, vpcId)) {
+                                throw new 
InvalidParameterValueException(String.format("ACL [%s] does not belong to the 
VPC [%s].", aclId, aclVpcId));
                             }
                         }
                         network = 
_vpcMgr.createVpcGuestNetwork(networkOfferingId, name, displayText, gateway, 
cidr, vlanId, networkDomain, owner, sharedDomainId, pNtwk, zoneId, aclType,
@@ -5950,6 +5947,14 @@ public class NetworkServiceImpl extends ManagerBase 
implements NetworkService, C
         return new ConfigKey<?>[] {AllowDuplicateNetworkName, 
AllowEmptyStartEndIpAddress, VRPrivateInterfaceMtu, VRPublicInterfaceMtu, 
AllowUsersToSpecifyVRMtu};
     }
 
+    public boolean isDefaultAcl(Long aclId) {
+        return aclId == NetworkACL.DEFAULT_DENY || aclId == 
NetworkACL.DEFAULT_ALLOW;
+    }
+
+    public boolean isAclAttachedToVpc(Long aclVpcId, Long vpcId) {
+        return aclVpcId != 0 && !vpcId.equals(aclVpcId);
+    }
+
     @Override
     public PublicIpQuarantine 
updatePublicIpAddressInQuarantine(UpdateQuarantinedIpCmd cmd) throws 
CloudRuntimeException {
         Long ipId = cmd.getId();
diff --git 
a/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java 
b/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java
index ed37eb5b375..8139ac1c49e 100644
--- a/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java
+++ b/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java
@@ -24,6 +24,7 @@ import java.util.Map;
 
 import javax.inject.Inject;
 
+import com.cloud.exception.PermissionDeniedException;
 import org.apache.cloudstack.api.ApiErrorCode;
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.api.command.user.network.CreateNetworkACLCmd;
@@ -103,12 +104,15 @@ public class NetworkACLServiceImpl extends ManagerBase 
implements NetworkACLServ
 
     @Override
     public NetworkACL createNetworkACL(final String name, final String 
description, final long vpcId, final Boolean forDisplay) {
-        final Account caller = CallContext.current().getCallingAccount();
-        final Vpc vpc = _entityMgr.findById(Vpc.class, vpcId);
-        if (vpc == null) {
-            throw new InvalidParameterValueException("Unable to find VPC");
+        if (vpcId != 0) {
+            final Account caller = CallContext.current().getCallingAccount();
+            final Vpc vpc = _vpcDao.findById(vpcId);
+            if (vpc == null) {
+                throw new InvalidParameterValueException(String.format("Unable 
to find VPC with ID [%s].", vpcId));
+            }
+            _accountMgr.checkAccess(caller, null, true, vpc);
+
         }
-        _accountMgr.checkAccess(caller, null, true, vpc);
         return _networkAclMgr.createNetworkACL(name, description, vpcId, 
forDisplay);
     }
 
@@ -212,22 +216,17 @@ public class NetworkACLServiceImpl extends ManagerBase 
implements NetworkACLServ
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_NETWORK_ACL_DELETE, 
eventDescription = "Deleting Network ACL List", async = true)
     public boolean deleteNetworkACL(final long id) {
-        final Account caller = CallContext.current().getCallingAccount();
         final NetworkACL acl = _networkACLDao.findById(id);
+        Account account = CallContext.current().getCallingAccount();
         if (acl == null) {
             throw new InvalidParameterValueException("Unable to find specified 
ACL");
         }
 
-        //Do not allow deletion of default ACLs
-        if (acl.getId() == NetworkACL.DEFAULT_ALLOW || acl.getId() == 
NetworkACL.DEFAULT_DENY) {
+        if (isDefaultAcl(acl.getId())) {
             throw new InvalidParameterValueException("Default ACL cannot be 
removed");
         }
 
-        final Vpc vpc = _entityMgr.findById(Vpc.class, acl.getVpcId());
-        if (vpc == null) {
-            throw new InvalidParameterValueException("Unable to find specified 
VPC associated with the ACL");
-        }
-        _accountMgr.checkAccess(caller, null, true, vpc);
+        validateGlobalAclPermissionAndAclAssociatedToVpc(acl, account, "Only 
Root Admin can delete global ACLs.");
         return _networkAclMgr.deleteNetworkACL(acl);
     }
 
@@ -253,7 +252,7 @@ public class NetworkACLServiceImpl extends ManagerBase 
implements NetworkACLServ
             throw new InvalidParameterValueException("Unable to find specified 
vpc id");
         }
 
-        if (aclId != NetworkACL.DEFAULT_DENY && aclId != 
NetworkACL.DEFAULT_ALLOW) {
+        if (!isDefaultAcl(aclId)) {
             final Vpc vpc = _entityMgr.findById(Vpc.class, acl.getVpcId());
             if (vpc == null) {
                 throw new InvalidParameterValueException("Unable to find Vpc 
associated with the NetworkACL");
@@ -293,15 +292,9 @@ public class NetworkACLServiceImpl extends ManagerBase 
implements NetworkACLServ
             throw new InvalidParameterValueException("Network ACL can be 
created just for networks of type " + Networks.TrafficType.Guest);
         }
 
-        if (aclId != NetworkACL.DEFAULT_DENY && aclId != 
NetworkACL.DEFAULT_ALLOW) {
-            //ACL is not default DENY/ALLOW
-            // ACL should be associated with a VPC
-            final Vpc vpc = _entityMgr.findById(Vpc.class, acl.getVpcId());
-            if (vpc == null) {
-                throw new InvalidParameterValueException("Unable to find Vpc 
associated with the NetworkACL");
-            }
+        if (!isDefaultAcl(aclId) && !isGlobalAcl(acl.getVpcId())) {
+            validateAclAssociatedToVpc(acl.getVpcId(), caller, acl.getUuid());
 
-            _accountMgr.checkAccess(caller, null, true, vpc);
             if (!network.getVpcId().equals(acl.getVpcId())) {
                 throw new InvalidParameterValueException("Network: " + 
networkId + " and ACL: " + aclId + " do not belong to the same VPC");
             }
@@ -340,6 +333,11 @@ public class NetworkACLServiceImpl extends ManagerBase 
implements NetworkACLServ
         NetworkACL acl = _networkAclMgr.getNetworkACL(aclId);
 
         validateNetworkAcl(acl);
+        Account caller = CallContext.current().getCallingAccount();
+
+        if (isGlobalAcl(acl.getVpcId()) && 
!Account.Type.ADMIN.equals(caller.getType())) {
+            throw new PermissionDeniedException("Only Root Admins can create 
rules for a global ACL.");
+        }
         validateAclRuleNumber(createNetworkACLCmd, acl);
 
         NetworkACLItem.Action ruleAction = 
validateAndCreateNetworkAclRuleAction(action);
@@ -409,7 +407,8 @@ public class NetworkACLServiceImpl extends ManagerBase 
implements NetworkACLServ
      * <ul>
      *  <li>If the parameter is null, we return an  {@link 
InvalidParameterValueException};
      *  <li>Default ACLs {@link NetworkACL#DEFAULT_ALLOW} and {@link 
NetworkACL#DEFAULT_DENY} cannot be modified. Therefore, if any of them is 
provided we throw a {@link InvalidParameterValueException};
-     *  <li>If the network does not have a VPC, we will throw an {@link 
InvalidParameterValueException}.
+     *  <li>If no VPC is given, then it is a global ACL and there is no need 
to check any VPC ID. However, if a VPC is given and it does not exist, throws an
+     *  {@link InvalidParameterValueException}.
      * </ul>
      *
      * After all validations, we check if the user has access to the given 
network ACL using {@link AccountManager#checkAccess(Account, 
org.apache.cloudstack.acl.SecurityChecker.AccessType, boolean, 
org.apache.cloudstack.acl.ControlledEntity...)}.
@@ -419,16 +418,14 @@ public class NetworkACLServiceImpl extends ManagerBase 
implements NetworkACLServ
             throw new InvalidParameterValueException("Unable to find specified 
ACL.");
         }
 
-        if (acl.getId() == NetworkACL.DEFAULT_DENY || acl.getId() == 
NetworkACL.DEFAULT_ALLOW) {
+        if (isDefaultAcl(acl.getId())) {
             throw new InvalidParameterValueException("Default ACL cannot be 
modified");
         }
 
-        Vpc vpc = _entityMgr.findById(Vpc.class, acl.getVpcId());
-        if (vpc == null) {
-            throw new InvalidParameterValueException(String.format("Unable to 
find Vpc associated with the NetworkACL [%s]", acl.getUuid()));
+        Long aclVpcId = acl.getVpcId();
+        if (!isGlobalAcl(aclVpcId)) {
+            validateAclAssociatedToVpc(aclVpcId, 
CallContext.current().getCallingAccount(), acl.getUuid());
         }
-        Account caller = CallContext.current().getCallingAccount();
-        _accountMgr.checkAccess(caller, null, true, vpc);
     }
 
     /**
@@ -792,17 +789,12 @@ public class NetworkACLServiceImpl extends ManagerBase 
implements NetworkACLServ
         final NetworkACLItemVO aclItem = _networkACLItemDao.findById(ruleId);
         if (aclItem != null) {
             final NetworkACL acl = 
_networkAclMgr.getNetworkACL(aclItem.getAclId());
+            final Account account = CallContext.current().getCallingAccount();
 
-            final Vpc vpc = _entityMgr.findById(Vpc.class, acl.getVpcId());
-
-            if (aclItem.getAclId() == NetworkACL.DEFAULT_ALLOW || 
aclItem.getAclId() == NetworkACL.DEFAULT_DENY) {
+            if (isDefaultAcl(aclItem.getAclId())) {
                 throw new InvalidParameterValueException("ACL Items in default 
ACL cannot be deleted");
             }
-
-            final Account caller = CallContext.current().getCallingAccount();
-
-            _accountMgr.checkAccess(caller, null, true, vpc);
-
+            validateGlobalAclPermissionAndAclAssociatedToVpc(acl, account, 
"Only Root Admin can delete global ACL rules.");
         }
         return _networkAclMgr.revokeNetworkACLItem(ruleId);
     }
@@ -826,6 +818,9 @@ public class NetworkACLServiceImpl extends ManagerBase 
implements NetworkACLServ
         NetworkACL acl = 
_networkAclMgr.getNetworkACL(networkACLItemVo.getAclId());
         validateNetworkAcl(acl);
 
+        Account account = CallContext.current().getCallingAccount();
+        validateGlobalAclPermissionAndAclAssociatedToVpc(acl, account, "Only 
Root Admins can update global ACLs.");
+
         transferDataToNetworkAclRulePojo(updateNetworkACLItemCmd, 
networkACLItemVo, acl);
         validateNetworkACLItem(networkACLItemVo);
         return _networkAclMgr.updateNetworkACLItem(networkACLItemVo);
@@ -912,14 +907,13 @@ public class NetworkACLServiceImpl extends ManagerBase 
implements NetworkACLServ
     }
 
     @Override
-    @ActionEvent(eventType = EventTypes.EVENT_NETWORK_ACL_UPDATE, 
eventDescription = "updating network acl", async = true)
+    @ActionEvent(eventType = EventTypes.EVENT_NETWORK_ACL_UPDATE, 
eventDescription = "Updating Network ACL", async = true)
     public NetworkACL updateNetworkACL(UpdateNetworkACLListCmd 
updateNetworkACLListCmd) {
         Long id = updateNetworkACLListCmd.getId();
         NetworkACLVO acl = _networkACLDao.findById(id);
-        Vpc vpc = _entityMgr.findById(Vpc.class, acl.getVpcId());
+        Account account = CallContext.current().getCallingAccount();
 
-        Account caller = CallContext.current().getCallingAccount();
-        _accountMgr.checkAccess(caller, null, true, vpc);
+        validateGlobalAclPermissionAndAclAssociatedToVpc(acl, account, "Must 
be Root Admin to update a global ACL.");
 
         String name = updateNetworkACLListCmd.getName();
         if (StringUtils.isNotBlank(name)) {
@@ -1149,14 +1143,59 @@ public class NetworkACLServiceImpl extends ManagerBase 
implements NetworkACLServ
         long aclId = ruleBeingMoved.getAclId();
 
         if ((nextRule != null && nextRule.getAclId() != aclId) || 
(previousRule != null && previousRule.getAclId() != aclId)) {
-            throw new InvalidParameterValueException("Cannot use ACL rules 
from differenting ACLs. Rule being moved.");
+            throw new InvalidParameterValueException("Cannot use ACL rules 
from differentiating ACLs. Rule being moved.");
         }
         NetworkACLVO acl = _networkACLDao.findById(aclId);
-        Vpc vpc = _entityMgr.findById(Vpc.class, acl.getVpcId());
+        Account account = CallContext.current().getCallingAccount();
+
+        if (isDefaultAcl(aclId)) {
+            throw new InvalidParameterValueException("Default ACL rules cannot 
be moved.");
+        }
+
+        validateGlobalAclPermissionAndAclAssociatedToVpc(acl, account,"Must be 
Root Admin to move global ACL rules.");
+    }
+
+    /**
+     * Checks if the given ACL is a global ACL. If it is, then checks if the 
account is Root Admin, and throws an exception according to {@code 
exceptionMessage} param if it
+     * does not have permission.
+     */
+    protected void checkGlobalAclPermission(Long aclVpcId, Account account, 
String exceptionMessage) {
+        if (isGlobalAcl(aclVpcId) && 
!Account.Type.ADMIN.equals(account.getType())) {
+            throw new PermissionDeniedException(exceptionMessage);
+        }
+    }
+
+    protected void validateAclAssociatedToVpc(Long aclVpcId, Account account, 
String aclUuid) {
+        final Vpc vpc = _vpcDao.findById(aclVpcId);
         if (vpc == null) {
-            throw new InvalidParameterValueException("Re-ordering rules for a 
default ACL is prohibited");
+            throw new InvalidParameterValueException(String.format("Unable to 
find specified VPC [%s] associated with the ACL [%s].", aclVpcId, aclUuid));
         }
-        Account caller = CallContext.current().getCallingAccount();
-        _accountMgr.checkAccess(caller, null, true, vpc);
+        _accountMgr.checkAccess(account, null, true, vpc);
+    }
+
+    /**
+     * It performs two different verifications depending on if the ACL is 
global or not.
+     * <ul>
+     *     <li> If the given ACL is a Global ACL, i.e. has VPC ID = 0, then 
checks if the account is Root Admin, and throws an exception if it isn't.
+     *     <li> If the given ACL is associated to a VPC, i.e. VPC ID != 0, 
then calls {@link #validateAclAssociatedToVpc(Long, Account, String)} and 
checks if the given {@code
+     *     aclVpcId} is from a valid VPC.
+     * </ul>
+     */
+    protected void validateGlobalAclPermissionAndAclAssociatedToVpc(NetworkACL 
acl, Account account, String exception){
+        if (isGlobalAcl(acl.getVpcId())) {
+            s_logger.info(String.format("Checking if account [%s] has 
permission to manipulate global ACL [%s].", account, acl));
+            checkGlobalAclPermission(acl.getVpcId(), account, exception);
+        } else {
+            s_logger.info(String.format("Validating ACL [%s] associated to VPC 
[%s] with account [%s].", acl, acl.getVpcId(), account));
+            validateAclAssociatedToVpc(acl.getVpcId(), account, acl.getUuid());
+        }
+    }
+
+    protected boolean isGlobalAcl(Long aclVpcId) {
+        return aclVpcId != null && aclVpcId == 0;
+    }
+
+    protected boolean isDefaultAcl(long aclId) {
+        return aclId == NetworkACL.DEFAULT_ALLOW || aclId == 
NetworkACL.DEFAULT_DENY;
     }
 }
diff --git a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java 
b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
index 6bc70a9cef4..1f99d164625 100644
--- a/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
+++ b/server/src/main/java/com/cloud/network/vpc/VpcManagerImpl.java
@@ -1977,16 +1977,14 @@ public class VpcManagerImpl extends ManagerBase 
implements VpcManager, VpcProvis
 
         searchBuilder.and("vpcId", searchBuilder.entity().getVpcId(), Op.IN);
         final SearchCriteria<NetworkACLVO> searchCriteria = 
searchBuilder.create();
-        searchCriteria.setParameters("vpcId", vpcId, 0);
+        searchCriteria.setParameters("vpcId", vpcId);
 
         final Filter filter = new Filter(NetworkACLVO.class, "id", false, 
null, null);
         final Pair<List<NetworkACLVO>, Integer> aclsCountPair =  
_networkAclDao.searchAndCount(searchCriteria, filter);
 
         final List<NetworkACLVO> acls = aclsCountPair.first();
         for (final NetworkACLVO networkAcl : acls) {
-            if (networkAcl.getId() != NetworkACL.DEFAULT_ALLOW && 
networkAcl.getId() != NetworkACL.DEFAULT_DENY) {
-                _networkAclMgr.deleteNetworkACL(networkAcl);
-            }
+            _networkAclMgr.deleteNetworkACL(networkAcl);
         }
 
         VpcVO vpc = vpcDao.findById(vpcId);
@@ -3175,4 +3173,12 @@ public class VpcManagerImpl extends ManagerBase 
implements VpcManager, VpcProvis
         }
         return filteredDomainIds;
     }
+
+    protected boolean isGlobalAcl(Long aclVpcId) {
+        return aclVpcId != null && aclVpcId == 0;
+    }
+
+    protected boolean isDefaultAcl(long aclId) {
+        return aclId == NetworkACL.DEFAULT_ALLOW || aclId == 
NetworkACL.DEFAULT_DENY;
+    }
 }
diff --git 
a/server/src/test/java/com/cloud/network/vpc/NetworkACLServiceImplTest.java 
b/server/src/test/java/com/cloud/network/vpc/NetworkACLServiceImplTest.java
index 8dd3f32d6c4..18a072172ad 100644
--- a/server/src/test/java/com/cloud/network/vpc/NetworkACLServiceImplTest.java
+++ b/server/src/test/java/com/cloud/network/vpc/NetworkACLServiceImplTest.java
@@ -17,19 +17,20 @@
 
 package com.cloud.network.vpc;
 
-import com.cloud.exception.InvalidParameterValueException;
-import com.cloud.exception.ResourceUnavailableException;
-import com.cloud.network.Network;
-import com.cloud.network.NetworkModel;
-import com.cloud.network.dao.NetworkVO;
-import com.cloud.network.vpc.NetworkACLItem.Action;
-import com.cloud.network.vpc.NetworkACLItem.TrafficType;
-import com.cloud.network.vpc.dao.NetworkACLDao;
-import com.cloud.user.Account;
-import com.cloud.user.AccountManager;
-import com.cloud.user.User;
-import com.cloud.utils.db.EntityManager;
-import com.cloud.utils.exception.CloudRuntimeException;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.ArgumentMatchers.nullable;
+import static org.mockito.Mockito.times;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.cloud.exception.PermissionDeniedException;
+import com.cloud.network.vpc.dao.VpcDao;
 import org.apache.cloudstack.acl.SecurityChecker.AccessType;
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.api.command.user.network.CreateNetworkACLCmd;
@@ -38,7 +39,6 @@ import 
org.apache.cloudstack.api.command.user.network.UpdateNetworkACLItemCmd;
 import org.apache.cloudstack.api.command.user.network.UpdateNetworkACLListCmd;
 import org.apache.cloudstack.context.CallContext;
 import org.apache.commons.lang3.StringUtils;
-import org.junit.After;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
@@ -46,24 +46,27 @@ import org.junit.runner.RunWith;
 import org.mockito.InOrder;
 import org.mockito.InjectMocks;
 import org.mockito.Mock;
-import org.mockito.MockedStatic;
 import org.mockito.Mockito;
 import org.mockito.Spy;
 import org.mockito.invocation.InvocationOnMock;
-import org.mockito.junit.MockitoJUnitRunner;
 import org.mockito.stubbing.Answer;
 
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-import static org.mockito.ArgumentMatchers.any;
-import static org.mockito.ArgumentMatchers.eq;
-import static org.mockito.ArgumentMatchers.isNull;
-import static org.mockito.ArgumentMatchers.nullable;
-import static org.mockito.Mockito.times;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.exception.ResourceUnavailableException;
+import com.cloud.network.Network;
+import com.cloud.network.NetworkModel;
+import com.cloud.network.dao.NetworkVO;
+import com.cloud.network.vpc.NetworkACLItem.Action;
+import com.cloud.network.vpc.NetworkACLItem.TrafficType;
+import com.cloud.network.vpc.dao.NetworkACLDao;
+import com.cloud.user.Account;
+import com.cloud.user.AccountManager;
+import com.cloud.user.User;
+import com.cloud.utils.db.EntityManager;
+import com.cloud.utils.exception.CloudRuntimeException;
+import org.junit.After;
+import org.mockito.MockedStatic;
+import org.mockito.junit.MockitoJUnitRunner;
 
 @RunWith(MockitoJUnitRunner.class)
 public class NetworkACLServiceImplTest {
@@ -80,6 +83,8 @@ public class NetworkACLServiceImplTest {
     @Mock
     private EntityManager entityManagerMock;
     @Mock
+    private VpcDao vpcDaoMock;
+    @Mock
     private AccountManager accountManagerMock;
     @Mock
     private NetworkACLDao networkAclDaoMock;
@@ -99,10 +104,11 @@ public class NetworkACLServiceImplTest {
     @Mock
     private UpdateNetworkACLListCmd updateNetworkACLListCmdMock;
 
-    private Long networkAclMockId = 1L;
+    private Long networkAclMockId = 5L;
     private Long networkOfferingMockId = 2L;
     private Long networkMockVpcMockId = 3L;
     private long networkAclListId = 1l;
+    private static final String SOME_UUID = "someUuid";
 
     @Mock
     private MoveNetworkAclItemCmd moveNetworkAclItemCmdMock;
@@ -121,6 +127,12 @@ public class NetworkACLServiceImplTest {
     @Mock
     private CallContext callContextMock;
 
+    @Mock
+    private VpcVO vpcVOMock;
+
+    @Mock
+    private Account accountMock;
+
     private MockedStatic<CallContext> callContextMocked;
 
     @Before
@@ -178,9 +190,9 @@ public class NetworkACLServiceImplTest {
             }
         });
 
-        NetworkACLItem netowkrAclRuleCreated = 
networkAclServiceImpl.createNetworkACLItem(createNetworkAclCmdMock);
+        NetworkACLItem networkAclRuleCreated = 
networkAclServiceImpl.createNetworkACLItem(createNetworkAclCmdMock);
 
-        Assert.assertEquals(number == null ? 6 : number, 
netowkrAclRuleCreated.getNumber());
+        Assert.assertEquals(number == null ? 6 : number, 
networkAclRuleCreated.getNumber());
 
         InOrder inOrder = Mockito.inOrder( networkAclServiceImpl, 
networkAclManagerMock, networkAclItemDaoMock);
         
inOrder.verify(networkAclServiceImpl).createAclListIfNeeded(createNetworkAclCmdMock);
@@ -392,13 +404,13 @@ public class NetworkACLServiceImplTest {
     @Test(expected = InvalidParameterValueException.class)
     public void validateNetworkAclTestAclNotDefaulWithoutVpc() {
         Mockito.when(networkAclMock.getId()).thenReturn(3L);
-        Mockito.doReturn(null).when(entityManagerMock).findById(Vpc.class, 
networkMockVpcMockId);
+        Mockito.doReturn(null).when(vpcDaoMock).findById(networkMockVpcMockId);
 
         networkAclServiceImpl.validateNetworkAcl(networkAclMock);
     }
 
     @Test
-    public void validateNetworkAclTestAclNotDefaulWithVpc() {
+    public void validateNetworkAclTestAclNotDefaultWithVpc() {
         CallContext callContextMock = Mockito.mock(CallContext.class);
         
Mockito.doReturn(Mockito.mock(Account.class)).when(callContextMock).getCallingAccount();
 
@@ -407,12 +419,11 @@ public class NetworkACLServiceImplTest {
         Mockito.when(networkAclMock.getId()).thenReturn(3L);
         
Mockito.when(networkAclMock.getVpcId()).thenReturn(networkMockVpcMockId);
 
-        
Mockito.doReturn(Mockito.mock(Vpc.class)).when(entityManagerMock).findById(Vpc.class,
 networkMockVpcMockId);
+        
Mockito.doReturn(vpcVOMock).when(vpcDaoMock).findById(networkMockVpcMockId);
         
Mockito.doNothing().when(accountManagerMock).checkAccess(Mockito.any(Account.class),
 Mockito.isNull(AccessType.class), Mockito.eq(true), Mockito.any(Vpc.class));
 
         networkAclServiceImpl.validateNetworkAcl(networkAclMock);
 
-        Mockito.verify(entityManagerMock).findById(Vpc.class, 
networkMockVpcMockId);
         
Mockito.verify(accountManagerMock).checkAccess(Mockito.any(Account.class), 
Mockito.isNull(AccessType.class), Mockito.eq(true), Mockito.any(Vpc.class));
 
         callContextMocked.verify(() -> CallContext.current());
@@ -702,16 +713,22 @@ public class NetworkACLServiceImplTest {
         
Mockito.doReturn(networkAclItemVoMock).when(networkAclServiceImpl).validateNetworkAclRuleIdAndRetrieveIt(updateNetworkACLItemCmdMock);
         
Mockito.doReturn(networkAclMock).when(networkAclManagerMock).getNetworkACL(networkAclMockId);
         
Mockito.doNothing().when(networkAclServiceImpl).validateNetworkAcl(Mockito.eq(networkAclMock));
+        
Mockito.doNothing().when(networkAclServiceImpl).validateGlobalAclPermissionAndAclAssociatedToVpc(Mockito.any(NetworkACL.class),
 Mockito.any(Account.class), Mockito.anyString());
         
Mockito.doNothing().when(networkAclServiceImpl).transferDataToNetworkAclRulePojo(Mockito.eq(updateNetworkACLItemCmdMock),
 Mockito.eq(networkAclItemVoMock), Mockito.eq(networkAclMock));
         
Mockito.doNothing().when(networkAclServiceImpl).validateNetworkACLItem(networkAclItemVoMock);
         
Mockito.doReturn(networkAclItemVoMock).when(networkAclManagerMock).updateNetworkACLItem(networkAclItemVoMock);
 
+        CallContext callContextMock = Mockito.mock(CallContext.class);
+        
Mockito.doReturn(accountMock).when(callContextMock).getCallingAccount();
+        Mockito.when(CallContext.current()).thenReturn(callContextMock);
+
         
networkAclServiceImpl.updateNetworkACLItem(updateNetworkACLItemCmdMock);
 
         InOrder inOrder = Mockito.inOrder(networkAclServiceImpl, 
networkAclManagerMock);
         
inOrder.verify(networkAclServiceImpl).validateNetworkAclRuleIdAndRetrieveIt(updateNetworkACLItemCmdMock);
         inOrder.verify(networkAclManagerMock).getNetworkACL(networkAclMockId);
         
inOrder.verify(networkAclServiceImpl).validateNetworkAcl(networkAclMock);
+        
inOrder.verify(networkAclServiceImpl).validateGlobalAclPermissionAndAclAssociatedToVpc(networkAclMock,
 accountMock, "Only Root Admins can update global ACLs.");
         
inOrder.verify(networkAclServiceImpl).transferDataToNetworkAclRulePojo(Mockito.eq(updateNetworkACLItemCmdMock),
 Mockito.eq(networkAclItemVoMock), Mockito.eq(networkAclMock));
         
inOrder.verify(networkAclServiceImpl).validateNetworkACLItem(networkAclItemVoMock);
         
inOrder.verify(networkAclManagerMock).updateNetworkACLItem(networkAclItemVoMock);
@@ -865,13 +882,18 @@ public class NetworkACLServiceImplTest {
         
Mockito.when(updateNetworkACLListCmdMock.getCustomId()).thenReturn(customId);
         
Mockito.when(updateNetworkACLListCmdMock.getId()).thenReturn(networkAclListId);
         
Mockito.when(updateNetworkACLListCmdMock.getDisplay()).thenReturn(false);
+        
Mockito.when(networkACLVOMock.getVpcId()).thenReturn(networkMockVpcMockId);
+        
Mockito.doReturn(vpcVOMock).when(vpcDaoMock).findById(networkMockVpcMockId);
+        
Mockito.doNothing().when(accountManagerMock).checkAccess(Mockito.any(Account.class),
+        Mockito.isNull(AccessType.class), Mockito.eq(true), 
Mockito.any(Vpc.class));
+
 
         networkAclServiceImpl.updateNetworkACL(updateNetworkACLListCmdMock);
 
-        InOrder inOrder = Mockito.inOrder(networkAclDaoMock, 
entityManagerMock, entityManagerMock, accountManagerMock, networkACLVOMock);
+        InOrder inOrder = Mockito.inOrder(networkAclDaoMock, vpcDaoMock, 
accountManagerMock, networkACLVOMock);
 
         inOrder.verify(networkAclDaoMock).findById(networkAclListId);
-        inOrder.verify(entityManagerMock).findById(Mockito.eq(Vpc.class), 
Mockito.anyLong());
+        inOrder.verify(vpcDaoMock).findById(Mockito.anyLong());
         
inOrder.verify(accountManagerMock).checkAccess(Mockito.any(Account.class), 
Mockito.isNull(AccessType.class), Mockito.eq(true), nullable(Vpc.class));
 
 
@@ -1063,13 +1085,17 @@ public class NetworkACLServiceImplTest {
         
Mockito.when(updateNetworkACLListCmdMock.getCustomId()).thenReturn(null);
         
Mockito.when(updateNetworkACLListCmdMock.getId()).thenReturn(networkAclListId);
         
Mockito.when(updateNetworkACLListCmdMock.getDisplay()).thenReturn(null);
+        
Mockito.when(networkACLVOMock.getVpcId()).thenReturn(networkMockVpcMockId);
+        
Mockito.doReturn(vpcVOMock).when(vpcDaoMock).findById(networkMockVpcMockId);
+        
Mockito.doNothing().when(accountManagerMock).checkAccess(Mockito.any(Account.class),
+        Mockito.isNull(AccessType.class), Mockito.eq(true), 
Mockito.any(Vpc.class));
 
         networkAclServiceImpl.updateNetworkACL(updateNetworkACLListCmdMock);
 
-        InOrder inOrder = Mockito.inOrder(networkAclDaoMock, 
entityManagerMock, accountManagerMock, networkACLVOMock);
+        InOrder inOrder = Mockito.inOrder(networkAclDaoMock, vpcDaoMock, 
accountManagerMock, networkACLVOMock);
 
         inOrder.verify(networkAclDaoMock).findById(networkAclListId);
-        inOrder.verify(entityManagerMock).findById(eq(Vpc.class), 
Mockito.anyLong());
+        inOrder.verify(vpcDaoMock).findById(Mockito.anyLong());
         inOrder.verify(accountManagerMock).checkAccess(any(Account.class), 
isNull(), eq(true), nullable(Vpc.class));
 
         Mockito.verify(networkACLVOMock, Mockito.times(0)).setName(null);
@@ -1086,21 +1112,18 @@ public class NetworkACLServiceImplTest {
         Mockito.when(nextAclRuleMock.getAclId()).thenReturn(networkAclMockId);
         
Mockito.when(previousAclRuleMock.getAclId()).thenReturn(networkAclMockId);
 
-        
Mockito.doReturn(networkAclMock).when(networkAclDaoMock).findById(networkAclMockId);
-        
Mockito.doReturn(Mockito.mock(Vpc.class)).when(entityManagerMock).findById(Vpc.class,
 networkMockVpcMockId);
-
         CallContext callContextMock = Mockito.mock(CallContext.class);
         
Mockito.doReturn(Mockito.mock(Account.class)).when(callContextMock).getCallingAccount();
 
+        
Mockito.doReturn(networkAclMock).when(networkAclDaoMock).findById(networkAclMockId);
         Mockito.when(CallContext.current()).thenReturn(callContextMock);
 
-        
Mockito.doNothing().when(accountManagerMock).checkAccess(Mockito.any(Account.class),
 Mockito.isNull(AccessType.class), Mockito.eq(true), Mockito.any(Vpc.class));
+        
Mockito.doNothing().when(networkAclServiceImpl).validateGlobalAclPermissionAndAclAssociatedToVpc(Mockito.any(NetworkACL.class),
 Mockito.any(Account.class), Mockito.anyString());
 
         networkAclServiceImpl.validateMoveAclRulesData(aclRuleBeingMovedMock, 
previousAclRuleMock, nextAclRuleMock);
 
         Mockito.verify(networkAclDaoMock).findById(networkAclMockId);
-        Mockito.verify(entityManagerMock).findById(Vpc.class, 
networkMockVpcMockId);
-        
Mockito.verify(accountManagerMock).checkAccess(Mockito.any(Account.class), 
Mockito.isNull(AccessType.class), Mockito.eq(true), Mockito.any(Vpc.class));
+        
Mockito.verify(networkAclServiceImpl).validateGlobalAclPermissionAndAclAssociatedToVpc(Mockito.any(NetworkACL.class),
 Mockito.any(Account.class), Mockito.anyString());
     }
 
     @Test
@@ -1359,9 +1382,41 @@ public class NetworkACLServiceImplTest {
         ArrayList<NetworkACLItemVO> allAclRules = new ArrayList<>();
         allAclRules.add(networkAclItemVoMock);
 
-        Mockito.doReturn("someUuid").when(networkAclItemVoMock).getUuid();
+        Mockito.doReturn(SOME_UUID).when(networkAclItemVoMock).getUuid();
         
networkAclServiceImpl.validateAclConsistency(moveNetworkAclItemCmdMock, 
networkACLVOMock, allAclRules);
 
         Mockito.verify(moveNetworkAclItemCmdMock, 
Mockito.times(1)).getAclConsistencyHash();
     }
+
+    @Test
+    public void 
checkGlobalAclPermissionTestGlobalAclWithRootAccountShouldWork() {
+        Mockito.doReturn(Account.Type.ADMIN).when(accountMock).getType();
+        
Mockito.doReturn(true).when(networkAclServiceImpl).isGlobalAcl(Mockito.anyLong());
+
+        networkAclServiceImpl.checkGlobalAclPermission(networkMockVpcMockId, 
accountMock, "exception");
+    }
+
+    @Test(expected = PermissionDeniedException.class)
+    public void 
checkGlobalAclPermissionTestGlobalAclWithNonRootAccountShouldThrow() {
+        Mockito.doReturn(Account.Type.NORMAL).when(accountMock).getType();
+        
Mockito.doReturn(true).when(networkAclServiceImpl).isGlobalAcl(Mockito.anyLong());
+
+        networkAclServiceImpl.checkGlobalAclPermission(networkMockVpcMockId, 
accountMock, "exception");
+    }
+
+    @Test
+    public void validateAclAssociatedToVpcTestNonNullVpcShouldCheckAccess() {
+        
Mockito.doReturn(vpcVOMock).when(vpcDaoMock).findById(Mockito.anyLong());
+
+        networkAclServiceImpl.validateAclAssociatedToVpc(networkMockVpcMockId, 
accountMock, SOME_UUID);
+
+        Mockito.verify(accountManagerMock, 
Mockito.times(1)).checkAccess(Mockito.any(Account.class), isNull(), 
Mockito.anyBoolean(), Mockito.any(Vpc.class));
+    }
+
+    @Test(expected = InvalidParameterValueException.class)
+    public void 
validateAclAssociatedToVpcTestNullVpcShouldThrowInvalidParameterValueException()
 {
+        Mockito.doReturn(null).when(vpcDaoMock).findById(Mockito.anyLong());
+
+        networkAclServiceImpl.validateAclAssociatedToVpc(networkMockVpcMockId, 
accountMock, SOME_UUID);
+    }
 }
diff --git a/test/integration/smoke/test_global_acls.py 
b/test/integration/smoke/test_global_acls.py
new file mode 100644
index 00000000000..47db858c121
--- /dev/null
+++ b/test/integration/smoke/test_global_acls.py
@@ -0,0 +1,245 @@
+# 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.
+from marvin.cloudstackTestCase import cloudstackTestCase
+from marvin.lib.utils import cleanup_resources
+from marvin.lib.base import (Network, NetworkACLList, NetworkOffering, 
VpcOffering, VPC, NetworkACL)
+from marvin.lib.common import (get_domain, get_zone)
+from nose.plugins.attrib import attr
+from marvin.cloudstackException import CloudstackAPIException
+
+
+class Services:
+    """Test Global ACLs
+    """
+
+    def __init__(self):
+        self.services = {
+            "root_domain": {
+                "name": "ROOT",
+            },
+            "domain": {
+                "name": "Domain",
+            },
+            "user": {
+                "username": "user",
+                "roletype": 0,
+            },
+            "domain_admin": {
+                "username": "Domain admin",
+                "roletype": 2,
+            },
+            "root_admin": {
+                "username": "Root admin",
+                "roletype": 1,
+            },
+            "vpc": {
+                "name": "vpc-networkacl",
+                "displaytext": "vpc-networkacl",
+                "cidr": "10.1.1.0/24",
+            },
+            "vpcnetwork": {
+                "name": "vpcnetwork",
+                "displaytext": "vpcnetwork",
+            },
+            "rule": {
+                "protocol": "all",
+                "traffictype": "ingress",
+            }
+        }
+
+
+class TestGlobalACLs(cloudstackTestCase):
+
+    @classmethod
+    def setUpClass(cls):
+        cls.testClient = super(TestGlobalACLs, cls).getClsTestClient()
+        cls.apiclient = cls.testClient.getApiClient()
+
+        cls.services = Services().services
+        cls.domain = get_domain(cls.apiclient)
+        cls.zone = get_zone(cls.apiclient, cls.testClient.getZoneForTests())
+        return
+
+    def setUp(self):
+        self.user_apiclient = 
self.testClient.getUserApiClient(self.services["user"]["username"],
+                                                               
self.services["domain"]["name"],
+                                                               
self.services["user"]["roletype"])
+
+        self.domain_admin_apiclient = 
self.testClient.getUserApiClient(self.services["domain_admin"]["username"],
+                                                                       
self.services["domain"]["name"],
+                                                                       
self.services["domain_admin"]["roletype"])
+
+        self.admin_apiclient = 
self.testClient.getUserApiClient(self.services["root_admin"]["username"],
+                                                                
self.services["root_domain"]["name"],
+                                                                
self.services["root_admin"]["roletype"])
+
+        self.cleanup = []
+        return
+
+    def tearDown(self):
+        super(TestGlobalACLs, self).tearDown()
+
+    @attr(tags=["advanced", "basic"], required_hardware="false")
+    def test_create_global_acl(self):
+        """ Test create global ACL as a normal user, domain admin and root 
admin users.
+        """
+
+        self.debug("Creating ACL list as a normal user, should raise 
exception.")
+        self.assertRaisesRegex(CloudstackAPIException, "Only Root Admin can 
create global ACLs.",
+                               NetworkACLList.create, 
apiclient=self.user_apiclient, services={},
+                               name="acl", description="acl")
+
+        self.debug("Creating ACL list as a domain admin, should raise 
exception.")
+        self.assertRaisesRegex(CloudstackAPIException, "Only Root Admin can 
create global ACLs.",
+                               NetworkACLList.create, 
apiclient=self.domain_admin_apiclient, services={},
+                               name="acl", description="acl")
+
+        self.debug("Creating ACL list as a root admin, should work.")
+        acl = NetworkACLList.create(apiclient=self.admin_apiclient, 
services={}, name="acl", description="acl")
+        self.cleanup.append(acl)
+        self.assertIsNotNone(acl, "A root admin user should be able to create 
a global ACL.")
+
+        return
+
+    @attr(tags=["advanced", "basic"], required_hardware="false")
+    def test_replace_acl_of_network(self):
+        """ Test to replace ACL of a VPC as a normal user, domain admin and 
root admin users.
+        """
+        # Get network offering
+        networkOffering = NetworkOffering.list(self.apiclient, 
name="DefaultIsolatedNetworkOfferingForVpcNetworks")
+        self.assertTrue(networkOffering is not None and len(networkOffering) > 
0, "No VPC network offering")
+
+        # Getting VPC offering
+        vpcOffering = VpcOffering.list(self.apiclient, name="Default VPC 
offering")
+        self.assertTrue(vpcOffering is not None and len(vpcOffering) > 0, "No 
VPC offerings found")
+
+        # Creating VPC
+        vpc = VPC.create(
+            apiclient=self.apiclient,
+            services=self.services["vpc"],
+            networkDomain="vpc.networkacl",
+            vpcofferingid=vpcOffering[0].id,
+            zoneid=self.zone.id,
+            domainid=self.domain.id
+        )
+        self.cleanup.append(vpc)
+        self.assertTrue(vpc is not None, "VPC creation failed")
+
+        # Creating ACL list
+        acl = NetworkACLList.create(apiclient=self.apiclient, services={}, 
name="acl", description="acl")
+
+        # Creating tier on VPC with ACL list
+        network = Network.create(
+            apiclient=self.apiclient,
+            services=self.services["vpcnetwork"],
+            accountid="Admin",
+            domainid=self.domain.id,
+            networkofferingid=networkOffering[0].id,
+            zoneid=self.zone.id,
+            vpcid=vpc.id,
+            aclid=acl.id,
+            gateway="10.1.1.1",
+            netmask="255.255.255.192"
+        )
+        self.cleanup.append(network)
+
+        # User should be able to replace ACL
+        network.replaceACLList(apiclient=self.user_apiclient, aclid=acl.id)
+        # Domain Admin should be able to replace ACL
+        network.replaceACLList(apiclient=self.domain_admin_apiclient, 
aclid=acl.id)
+        # Admin should be able to replace ACL
+        network.replaceACLList(apiclient=self.admin_apiclient, aclid=acl.id)
+
+        return
+
+    @attr(tags=["advanced", "basic"], required_hardware="false")
+    def test_create_acl_rule(self):
+        """ Test to create ACL rule as a normal user, domain admin and root 
admin users.
+        """
+        # Creating ACL list
+        acl = NetworkACLList.create(apiclient=self.admin_apiclient, 
services={}, name="acl", description="acl")
+        self.cleanup.append(acl)
+
+        self.debug("Creating ACL rule as a user, should raise exception.")
+        self.assertRaisesRegex(CloudstackAPIException, "Only Root Admins can 
create rules for a global ACL.",
+                               NetworkACL.create, self.user_apiclient, 
services=self.services["rule"], aclid=acl.id)
+        self.debug("Creating ACL rule as a domain admin, should raise 
exception.")
+        self.assertRaisesRegex(CloudstackAPIException, "Only Root Admins can 
create rules for a global ACL.",
+                               NetworkACL.create, self.domain_admin_apiclient, 
services=self.services["rule"], aclid=acl.id)
+        self.debug("Creating ACL rule as a root admin, should work.")
+        acl_rule = NetworkACL.create(self.admin_apiclient, 
services=self.services["rule"], aclid=acl.id)
+        self.cleanup.append(acl_rule)
+
+        return
+
+    @attr(tags=["advanced", "basic"], required_hardware="false")
+    def test_delete_acl_rule(self):
+        """ Test to delete ACL rule as a normal user, domain admin and root 
admin users.
+        """
+        # Creating ACL list
+        acl = NetworkACLList.create(apiclient=self.apiclient, services={}, 
name="acl", description="acl")
+        self.cleanup.append(acl)
+
+        # Creating ACL rule
+        acl_rule = NetworkACL.create(self.apiclient, 
services=self.services["rule"], aclid=acl.id)
+        self.cleanup.append(acl_rule)
+
+        self.debug("Deleting ACL rule as a user, should raise exception.")
+        self.assertRaisesRegex(Exception, "Only Root Admin can delete global 
ACL rules.",
+                               NetworkACL.delete, acl_rule, 
self.user_apiclient)
+        self.debug("Deleting ACL rule as a domain admin, should raise 
exception.")
+        self.assertRaisesRegex(Exception, "Only Root Admin can delete global 
ACL rules.",
+                               NetworkACL.delete, acl_rule, 
self.domain_admin_apiclient)
+
+        self.debug("Deleting ACL rule as a root admin, should work.")
+        NetworkACL.delete(acl_rule, self.admin_apiclient)
+        self.cleanup.remove(acl_rule)
+
+        # Verify if the number of ACL rules is equal to four, i.e. the number 
of rules
+        # for the default ACLs `default_allow` (2 rules) and `default_deny` (2 
rules) ACLs
+        number_of_acl_rules = acl_rule.list(apiclient=self.admin_apiclient)
+        self.assertEqual(len(number_of_acl_rules), 4)
+
+        return
+
+
+    @attr(tags=["advanced", "basic"], required_hardware="false")
+    def test_delete_global_acl(self):
+        """ Test delete global ACL as a normal user, domain admin and root 
admin users.
+        """
+
+        # Creating ACL list. Not adding to cleanup as it will be deleted in 
this method
+        acl = NetworkACLList.create(apiclient=self.apiclient, services={}, 
name="acl", description="acl")
+        self.cleanup.append(acl)
+
+        self.debug("Deleting ACL list as a normal user, should raise 
exception.")
+        self.assertRaisesRegex(Exception, "Only Root Admin can delete global 
ACLs.",
+                               NetworkACLList.delete, acl, 
apiclient=self.user_apiclient)
+
+        self.debug("Deleting ACL list as a domain admin, should raise 
exception.")
+        self.assertRaisesRegex(Exception, "Only Root Admin can delete global 
ACLs.",
+                               NetworkACLList.delete, acl, 
apiclient=self.domain_admin_apiclient)
+
+        self.debug("Deleting ACL list as a root admin, should work.")
+        acl.delete(apiclient=self.admin_apiclient)
+        self.cleanup.remove(acl)
+
+        # Verify if number of ACLs is equal to two, i.e. the number of default 
ACLs `default_allow` and `default_deny`
+        number_of_acls = NetworkACLList.list(apiclient=self.admin_apiclient)
+        self.assertEqual(len(number_of_acls), 2)
+
+        return

Reply via email to