You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cloudstack.apache.org by ra...@apache.org on 2018/04/10 11:46:56 UTC

[cloudstack] branch master updated: [CLOUDSTACK-10301] Allow updating the network ACL list name and Description (#2462)

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

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


The following commit(s) were added to refs/heads/master by this push:
     new b08f9e0  [CLOUDSTACK-10301] Allow updating the network ACL list name and Description (#2462)
b08f9e0 is described below

commit b08f9e053ff301d59dc81283704be37dc1871905
Author: Rafael Weingärtner <ra...@gmail.com>
AuthorDate: Tue Apr 10 08:46:52 2018 -0300

    [CLOUDSTACK-10301] Allow updating the network ACL list name and Description (#2462)
    
    * [CLOUDSTACK-10301] Allow updating the network ACL list name and description
    
    * Fixes suggested by Daan
---
 .../com/cloud/network/vpc/NetworkACLService.java   |  5 +-
 .../user/network/UpdateNetworkACLListCmd.java      | 22 ++++-
 .../java/com/cloud/network/vpc/NetworkACLVO.java   |  8 ++
 .../cloud/network/vpc/NetworkACLServiceImpl.java   | 25 ++++--
 .../network/vpc/NetworkACLServiceImplTest.java     | 94 +++++++++++++++++++---
 ui/l10n/ar.js                                      |  1 +
 ui/l10n/ca.js                                      |  1 +
 ui/l10n/de_DE.js                                   |  1 +
 ui/l10n/en.js                                      |  1 +
 ui/l10n/es.js                                      |  1 +
 ui/l10n/fr_FR.js                                   |  1 +
 ui/l10n/hu.js                                      |  1 +
 ui/l10n/it_IT.js                                   |  1 +
 ui/l10n/ja_JP.js                                   |  1 +
 ui/l10n/ko_KR.js                                   |  1 +
 ui/l10n/nb_NO.js                                   |  1 +
 ui/l10n/nl_NL.js                                   |  1 +
 ui/l10n/pl.js                                      |  1 +
 ui/l10n/pt_BR.js                                   |  1 +
 ui/l10n/ru_RU.js                                   |  1 +
 ui/l10n/zh_CN.js                                   |  1 +
 ui/scripts/ui/widgets/detailView.js                |  2 +-
 ui/scripts/vpc.js                                  | 35 +++++++-
 23 files changed, 180 insertions(+), 27 deletions(-)

diff --git a/api/src/main/java/com/cloud/network/vpc/NetworkACLService.java b/api/src/main/java/com/cloud/network/vpc/NetworkACLService.java
index dd7c862..378b15c 100644
--- a/api/src/main/java/com/cloud/network/vpc/NetworkACLService.java
+++ b/api/src/main/java/com/cloud/network/vpc/NetworkACLService.java
@@ -22,6 +22,7 @@ import org.apache.cloudstack.api.command.user.network.CreateNetworkACLCmd;
 import org.apache.cloudstack.api.command.user.network.ListNetworkACLListsCmd;
 import org.apache.cloudstack.api.command.user.network.ListNetworkACLsCmd;
 import org.apache.cloudstack.api.command.user.network.UpdateNetworkACLItemCmd;
+import org.apache.cloudstack.api.command.user.network.UpdateNetworkACLListCmd;
 
 import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.utils.Pair;
@@ -38,7 +39,7 @@ public interface NetworkACLService {
     NetworkACL getNetworkACL(long id);
 
     /**
-     * List NetworkACLs by Id/Name/Network or Vpc it belongs to
+     * List NetworkACLs by Id/Name/Network or VPC it belongs to
      */
     Pair<List<? extends NetworkACL>, Integer> listNetworkACLs(ListNetworkACLListsCmd cmd);
 
@@ -87,6 +88,6 @@ public interface NetworkACLService {
      */
     boolean replaceNetworkACLonPrivateGw(long aclId, long privateGatewayId) throws ResourceUnavailableException;
 
-    NetworkACL updateNetworkACL(Long id, String customId, Boolean forDisplay);
+    NetworkACL updateNetworkACL(UpdateNetworkACLListCmd updateNetworkACLListCmd);
 
 }
diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/network/UpdateNetworkACLListCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/network/UpdateNetworkACLListCmd.java
index aa1f557..22eaf21 100644
--- a/api/src/main/java/org/apache/cloudstack/api/command/user/network/UpdateNetworkACLListCmd.java
+++ b/api/src/main/java/org/apache/cloudstack/api/command/user/network/UpdateNetworkACLListCmd.java
@@ -31,8 +31,7 @@ import com.cloud.exception.ResourceUnavailableException;
 import com.cloud.network.vpc.NetworkACL;
 import com.cloud.user.Account;
 
-@APICommand(name = "updateNetworkACLList", description = "Updates network ACL list", responseObject = SuccessResponse.class, since = "4.4",
-        requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
+@APICommand(name = "updateNetworkACLList", description = "Updates network ACL list", responseObject = SuccessResponse.class, since = "4.4", requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
 public class UpdateNetworkACLListCmd extends BaseAsyncCustomIdCmd {
     public static final Logger s_logger = Logger.getLogger(UpdateNetworkACLListCmd.class.getName());
     private static final String s_name = "updatenetworkacllistresponse";
@@ -44,9 +43,16 @@ public class UpdateNetworkACLListCmd extends BaseAsyncCustomIdCmd {
     @Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = NetworkACLResponse.class, required = true, description = "the ID of the network ACL")
     private Long id;
 
-    @Parameter(name = ApiConstants.FOR_DISPLAY, type = CommandType.BOOLEAN, description = "an optional field, whether to the display the list to the end user or not", since = "4.4", authorized = {RoleType.Admin})
+    @Parameter(name = ApiConstants.FOR_DISPLAY, type = CommandType.BOOLEAN, description = "an optional field, whether to the display the list to the end user or not", since = "4.4", authorized = {
+            RoleType.Admin})
     private Boolean display;
 
+    @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "Name of the network ACL list")
+    private String name;
+
+    @Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, description = "Description of the network ACL list")
+    private String description;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -85,7 +91,7 @@ public class UpdateNetworkACLListCmd extends BaseAsyncCustomIdCmd {
 
     @Override
     public void execute() throws ResourceUnavailableException {
-        NetworkACL acl = _networkACLService.updateNetworkACL(id, this.getCustomId(), getDisplay());
+        NetworkACL acl = _networkACLService.updateNetworkACL(this);
         NetworkACLResponse aclResponse = _responseGenerator.createNetworkACLResponse(acl);
         setResponseObject(aclResponse);
         aclResponse.setResponseName(getCommandName());
@@ -97,4 +103,12 @@ public class UpdateNetworkACLListCmd extends BaseAsyncCustomIdCmd {
             _uuidMgr.checkUuid(this.getCustomId(), NetworkACL.class);
         }
     }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public String getName() {
+        return name;
+    }
 }
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 fb6a239..4eaa2b5 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
@@ -101,4 +101,12 @@ public class NetworkACLVO implements NetworkACL {
     public boolean isDisplay() {
         return display;
     }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
 }
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 5369ffa..18d3f8d 100644
--- a/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java
+++ b/server/src/main/java/com/cloud/network/vpc/NetworkACLServiceImpl.java
@@ -28,6 +28,7 @@ import org.apache.cloudstack.api.command.user.network.CreateNetworkACLCmd;
 import org.apache.cloudstack.api.command.user.network.ListNetworkACLListsCmd;
 import org.apache.cloudstack.api.command.user.network.ListNetworkACLsCmd;
 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.collections.CollectionUtils;
 import org.apache.commons.lang.StringUtils;
@@ -907,20 +908,30 @@ public class NetworkACLServiceImpl extends ManagerBase implements NetworkACLServ
 
     @Override
     @ActionEvent(eventType = EventTypes.EVENT_NETWORK_ACL_UPDATE, eventDescription = "updating network acl", async = true)
-    public NetworkACL updateNetworkACL(final Long id, final String customId, final Boolean forDisplay) {
-        final NetworkACLVO acl = _networkACLDao.findById(id);
-        final Vpc vpc = _entityMgr.findById(Vpc.class, acl.getVpcId());
-        final Account caller = CallContext.current().getCallingAccount();
+    public NetworkACL updateNetworkACL(UpdateNetworkACLListCmd updateNetworkACLListCmd) {
+        Long id = updateNetworkACLListCmd.getId();
+        NetworkACLVO acl = _networkACLDao.findById(id);
+        Vpc vpc = _entityMgr.findById(Vpc.class, acl.getVpcId());
+
+        Account caller = CallContext.current().getCallingAccount();
         _accountMgr.checkAccess(caller, null, true, vpc);
 
-        if (customId != null) {
+        String name = updateNetworkACLListCmd.getName();
+        if (StringUtils.isNotBlank(name)) {
+            acl.setName(name);
+        }
+        String description = updateNetworkACLListCmd.getDescription();
+        if (StringUtils.isNotBlank(description)) {
+            acl.setDescription(description);
+        }
+        String customId = updateNetworkACLListCmd.getCustomId();
+        if (StringUtils.isNotBlank(customId)) {
             acl.setUuid(customId);
         }
-
+        Boolean forDisplay = updateNetworkACLListCmd.getDisplay();
         if (forDisplay != null) {
             acl.setDisplay(forDisplay);
         }
-
         _networkACLDao.update(id, acl);
         return _networkACLDao.findById(id);
     }
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 ed8602b..540a104 100644
--- a/server/src/test/java/com/cloud/network/vpc/NetworkACLServiceImplTest.java
+++ b/server/src/test/java/com/cloud/network/vpc/NetworkACLServiceImplTest.java
@@ -23,6 +23,7 @@ import org.apache.cloudstack.acl.SecurityChecker.AccessType;
 import org.apache.cloudstack.api.ServerApiException;
 import org.apache.cloudstack.api.command.user.network.CreateNetworkACLCmd;
 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.junit.Assert;
 import org.junit.Before;
@@ -46,12 +47,14 @@ 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.utils.db.EntityManager;
 import com.cloud.utils.exception.CloudRuntimeException;
 
 @RunWith(PowerMockRunner.class)
+@PrepareForTest(CallContext.class)
 public class NetworkACLServiceImplTest {
 
     @Spy
@@ -64,9 +67,11 @@ public class NetworkACLServiceImplTest {
     @Mock
     private NetworkACLItemDao networkAclItemDaoMock;
     @Mock
-    private EntityManager EntityManagerMock;
+    private EntityManager entityManagerMock;
     @Mock
-    private AccountManager AccountManager;
+    private AccountManager accountManagerMock;
+    @Mock
+    private NetworkACLDao networkAclDaoMock;
 
     @Mock
     private CreateNetworkACLCmd createNetworkAclCmdMock;
@@ -78,13 +83,22 @@ public class NetworkACLServiceImplTest {
     private NetworkACL networkAclMock;
     @Mock
     private NetworkACLItemVO networkAclItemVoMock;
+    @Mock
+    private NetworkACLVO networkACLVOMock;
+    @Mock
+    private UpdateNetworkACLListCmd updateNetworkACLListCmdMock;
 
     private Long networkAclMockId = 1L;
     private Long networkOfferingMockId = 2L;
     private Long networkMockVpcMockId = 3L;
+    private long networkAclListId = 1l;
 
     @Before
     public void befoteTest() {
+        PowerMockito.mockStatic(CallContext.class);
+        PowerMockito.when(CallContext.current()).thenReturn(Mockito.mock(CallContext.class));
+
+        Mockito.when(networkAclDaoMock.findById(networkAclListId)).thenReturn(networkACLVOMock);
         Mockito.when(createNetworkAclCmdMock.getNetworkId()).thenReturn(1L);
         Mockito.when(createNetworkAclCmdMock.getProtocol()).thenReturn("tcp");
 
@@ -215,7 +229,7 @@ public class NetworkACLServiceImplTest {
     @Test(expected = InvalidParameterValueException.class)
     public void createAclListForNetworkAndReturnAclListIdTestServicesSupportedByNetworkOfferingButVpcNotFound() {
         Mockito.doReturn(true).when(networkModelMock).areServicesSupportedByNetworkOffering(networkOfferingMockId, Network.Service.NetworkACL);
-        Mockito.doReturn(null).when(EntityManagerMock).findById(Vpc.class, networkMockVpcMockId);
+        Mockito.doReturn(null).when(entityManagerMock).findById(Vpc.class, networkMockVpcMockId);
 
         networkAclServiceImpl.createAclListForNetworkAndReturnAclListId(createNetworkAclCmdMock, networkMock);
     }
@@ -223,7 +237,7 @@ public class NetworkACLServiceImplTest {
     @Test(expected = CloudRuntimeException.class)
     public void createAclListForNetworkAndReturnAclListIdTestCreateNetworkAclReturnsNull() {
         Mockito.doReturn(true).when(networkModelMock).areServicesSupportedByNetworkOffering(networkOfferingMockId, Network.Service.NetworkACL);
-        Mockito.doReturn(Mockito.mock(Vpc.class)).when(EntityManagerMock).findById(Vpc.class, networkMockVpcMockId);
+        Mockito.doReturn(Mockito.mock(Vpc.class)).when(entityManagerMock).findById(Vpc.class, networkMockVpcMockId);
         Mockito.doReturn(null).when(networkAclManager).createNetworkACL(Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyBoolean());
 
         networkAclServiceImpl.createAclListForNetworkAndReturnAclListId(createNetworkAclCmdMock, networkMock);
@@ -232,7 +246,7 @@ public class NetworkACLServiceImplTest {
     @Test(expected = CloudRuntimeException.class)
     public void createAclListForNetworkAndReturnAclListIdTestAclNetworkIsCreatedButNotApplied() throws ResourceUnavailableException {
         Mockito.doReturn(true).when(networkModelMock).areServicesSupportedByNetworkOffering(networkOfferingMockId, Network.Service.NetworkACL);
-        Mockito.doReturn(Mockito.mock(Vpc.class)).when(EntityManagerMock).findById(Vpc.class, networkMockVpcMockId);
+        Mockito.doReturn(Mockito.mock(Vpc.class)).when(entityManagerMock).findById(Vpc.class, networkMockVpcMockId);
         Mockito.doReturn(Mockito.mock(NetworkACL.class)).when(networkAclManager).createNetworkACL(Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyBoolean());
         Mockito.doReturn(false).when(networkAclManager).replaceNetworkACL(Mockito.any(NetworkACL.class), Mockito.any(NetworkVO.class));
 
@@ -246,7 +260,7 @@ public class NetworkACLServiceImplTest {
     @Test(expected = CloudRuntimeException.class)
     public void createAclListForNetworkAndReturnAclListIdTestAclNetworkIsCreatedButNotAppliedWithException() throws ResourceUnavailableException {
         Mockito.doReturn(true).when(networkModelMock).areServicesSupportedByNetworkOffering(networkOfferingMockId, Network.Service.NetworkACL);
-        Mockito.doReturn(Mockito.mock(Vpc.class)).when(EntityManagerMock).findById(Vpc.class, networkMockVpcMockId);
+        Mockito.doReturn(Mockito.mock(Vpc.class)).when(entityManagerMock).findById(Vpc.class, networkMockVpcMockId);
         Mockito.doReturn(Mockito.mock(NetworkACL.class)).when(networkAclManager).createNetworkACL(Mockito.anyString(), Mockito.anyString(), Mockito.anyLong(), Mockito.anyBoolean());
 
         Mockito.doThrow(ResourceUnavailableException.class).when(networkAclManager).replaceNetworkACL(Mockito.any(NetworkACL.class), Mockito.any(NetworkVO.class));
@@ -261,7 +275,7 @@ public class NetworkACLServiceImplTest {
     @Test
     public void createAclListForNetworkAndReturnAclListIdTestAclIsCreatedAndAppliedWithSuccess() throws ResourceUnavailableException {
         Mockito.doReturn(true).when(networkModelMock).areServicesSupportedByNetworkOffering(networkOfferingMockId, Network.Service.NetworkACL);
-        Mockito.doReturn(Mockito.mock(Vpc.class)).when(EntityManagerMock).findById(Vpc.class, networkMockVpcMockId);
+        Mockito.doReturn(Mockito.mock(Vpc.class)).when(entityManagerMock).findById(Vpc.class, networkMockVpcMockId);
 
         NetworkACL networkAclMock = Mockito.mock(NetworkACL.class);
         Long expectedNetworkAclId = 5L;
@@ -339,7 +353,7 @@ 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(entityManagerMock).findById(Vpc.class, networkMockVpcMockId);
         ;
 
         networkAclServiceImpl.validateNetworkAcl(networkAclMock);
@@ -357,13 +371,13 @@ 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.doNothing().when(AccountManager).checkAccess(Mockito.any(Account.class), Mockito.isNull(AccessType.class), Mockito.eq(true), Mockito.any(Vpc.class));
+        Mockito.doReturn(Mockito.mock(Vpc.class)).when(entityManagerMock).findById(Vpc.class, 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(AccountManager).checkAccess(Mockito.any(Account.class), Mockito.isNull(AccessType.class), Mockito.eq(true), Mockito.any(Vpc.class));
+        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));
 
         PowerMockito.verifyStatic();
         CallContext.current();
@@ -808,4 +822,60 @@ public class NetworkACLServiceImplTest {
         Mockito.verify(networkAclServiceImpl).validateAndCreateNetworkAclRuleAction("deny");
     }
 
+    @Test
+    @PrepareForTest(CallContext.class)
+    public void updateNetworkACLTestParametersNotNull() {
+        String name = "name";
+        String description = "desc";
+        String customId = "customId";
+
+        Mockito.when(updateNetworkACLListCmdMock.getName()).thenReturn(name);
+        Mockito.when(updateNetworkACLListCmdMock.getDescription()).thenReturn(description);
+        Mockito.when(updateNetworkACLListCmdMock.getCustomId()).thenReturn(customId);
+        Mockito.when(updateNetworkACLListCmdMock.getId()).thenReturn(networkAclListId);
+        Mockito.when(updateNetworkACLListCmdMock.getDisplay()).thenReturn(false);
+
+        networkAclServiceImpl.updateNetworkACL(updateNetworkACLListCmdMock);
+
+        InOrder inOrder = Mockito.inOrder(networkAclDaoMock, entityManagerMock, entityManagerMock, accountManagerMock, networkACLVOMock);
+
+        inOrder.verify(networkAclDaoMock).findById(networkAclListId);
+        inOrder.verify(entityManagerMock).findById(Mockito.eq(Vpc.class), Mockito.anyLong());
+        inOrder.verify(accountManagerMock).checkAccess(Mockito.any(Account.class), Mockito.isNull(AccessType.class), Mockito.eq(true), Mockito.any(Vpc.class));
+
+        inOrder.verify(networkACLVOMock).setName(name);
+        inOrder.verify(networkACLVOMock).setDescription(description);
+        inOrder.verify(networkACLVOMock).setUuid(customId);
+        inOrder.verify(networkACLVOMock).setDisplay(false);
+
+        inOrder.verify(networkAclDaoMock).update(networkAclListId, networkACLVOMock);
+        inOrder.verify(networkAclDaoMock).findById(networkAclListId);
+    }
+
+    @Test
+    @PrepareForTest(CallContext.class)
+    public void updateNetworkACLTestParametersWithNullValues() {
+        Mockito.when(updateNetworkACLListCmdMock.getName()).thenReturn(null);
+        Mockito.when(updateNetworkACLListCmdMock.getDescription()).thenReturn(null);
+        Mockito.when(updateNetworkACLListCmdMock.getCustomId()).thenReturn(null);
+        Mockito.when(updateNetworkACLListCmdMock.getId()).thenReturn(networkAclListId);
+        Mockito.when(updateNetworkACLListCmdMock.getDisplay()).thenReturn(null);
+
+        networkAclServiceImpl.updateNetworkACL(updateNetworkACLListCmdMock);
+
+        InOrder inOrder = Mockito.inOrder(networkAclDaoMock, entityManagerMock, entityManagerMock, accountManagerMock, networkACLVOMock);
+
+        inOrder.verify(networkAclDaoMock).findById(networkAclListId);
+        inOrder.verify(entityManagerMock).findById(Mockito.eq(Vpc.class), Mockito.anyLong());
+        inOrder.verify(accountManagerMock).checkAccess(Mockito.any(Account.class), Mockito.isNull(AccessType.class), Mockito.eq(true), Mockito.any(Vpc.class));
+
+        Mockito.verify(networkACLVOMock, Mockito.times(0)).setName(null);
+        inOrder.verify(networkACLVOMock, Mockito.times(0)).setDescription(null);
+        inOrder.verify(networkACLVOMock, Mockito.times(0)).setUuid(null);
+        inOrder.verify(networkACLVOMock, Mockito.times(0)).setDisplay(false);
+
+        inOrder.verify(networkAclDaoMock).update(networkAclListId, networkACLVOMock);
+        inOrder.verify(networkAclDaoMock).findById(networkAclListId);
+    }
+
 }
diff --git a/ui/l10n/ar.js b/ui/l10n/ar.js
index db0dab0..c8129b1 100644
--- a/ui/l10n/ar.js
+++ b/ui/l10n/ar.js
@@ -318,6 +318,7 @@ var dictionary = {
     "label.add.accounts": "إضافة حسابات",
     "label.add.accounts.to": "إضافة حسابات إلى",
     "label.add.acl.list": "Add ACL List",
+    "label.edit.acl.list": "Edit ACL List",
     "label.add.affinity.group": "Add new affinity group",
     "label.add.baremetal.dhcp.device": "Add Baremetal DHCP Device",
     "label.add.baremetal.rack.configuration": "Add Baremetal Rack Configuration",
diff --git a/ui/l10n/ca.js b/ui/l10n/ca.js
index 5d98467..5f4f55b 100644
--- a/ui/l10n/ca.js
+++ b/ui/l10n/ca.js
@@ -318,6 +318,7 @@ var dictionary = {
     "label.add.accounts": "Afegir comptes",
     "label.add.accounts.to": "Afegir comptes a",
     "label.add.acl.list": "Add ACL List",
+    "label.edit.acl.list": "Edit ACL List",
     "label.add.affinity.group": "Add new affinity group",
     "label.add.baremetal.dhcp.device": "Add Baremetal DHCP Device",
     "label.add.baremetal.rack.configuration": "Add Baremetal Rack Configuration",
diff --git a/ui/l10n/de_DE.js b/ui/l10n/de_DE.js
index 4decf80..382f7c4 100644
--- a/ui/l10n/de_DE.js
+++ b/ui/l10n/de_DE.js
@@ -318,6 +318,7 @@ var dictionary = {
     "label.add.accounts": "Konten hinzufügen",
     "label.add.accounts.to": "Konten hinzufügen zu",
     "label.add.acl.list": "ACL-Liste hinzufügen",
+    "label.edit.acl.list": "Edit ACL List",
     "label.add.affinity.group": "Neue Affinitätsgruppe hinzufügen",
     "label.add.baremetal.dhcp.device": "Baremetal DHCP-Gerät hinzufügen",
     "label.add.baremetal.rack.configuration": "Baremetal Rackkonfiguration hinzufügen",
diff --git a/ui/l10n/en.js b/ui/l10n/en.js
index ae7ca7b..342e883 100644
--- a/ui/l10n/en.js
+++ b/ui/l10n/en.js
@@ -320,6 +320,7 @@ var dictionary = {
 "label.add.accounts":"Add accounts",
 "label.add.accounts.to":"Add accounts to",
 "label.add.acl.list":"Add ACL List",
+"label.edit.acl.list": "Edit ACL List",
 "label.add.affinity.group":"Add new affinity group",
 "label.add.baremetal.dhcp.device":"Add Baremetal DHCP Device",
 "label.add.baremetal.rack.configuration":"Add Baremetal Rack Configuration",
diff --git a/ui/l10n/es.js b/ui/l10n/es.js
index cbdf787..2f4727f 100644
--- a/ui/l10n/es.js
+++ b/ui/l10n/es.js
@@ -318,6 +318,7 @@ var dictionary = {
     "label.add.accounts": "Agregar Cuentas",
     "label.add.accounts.to": "Agregar Cuentas a",
     "label.add.acl.list": "Agregar Lista ACL",
+    "label.edit.acl.list": "Edit ACL List",
     "label.add.affinity.group": "Agregar un nuevo grupo de afinidad",
     "label.add.baremetal.dhcp.device": "Agregar dispositivo DHCP Baremetal",
     "label.add.baremetal.rack.configuration": "Agregar Configuración de Rack Baremetal",
diff --git a/ui/l10n/fr_FR.js b/ui/l10n/fr_FR.js
index 42f93c0..be31c1c 100644
--- a/ui/l10n/fr_FR.js
+++ b/ui/l10n/fr_FR.js
@@ -318,6 +318,7 @@ var dictionary = {
     "label.add.accounts": "Ajouter des comptes",
     "label.add.accounts.to": "Ajouter des comptes sur",
     "label.add.acl.list": "Ajouter Liste ACL",
+    "label.edit.acl.list": "Edit ACL List",
     "label.add.affinity.group": "Ajouter nouveau groupe d'affinité",
     "label.add.baremetal.dhcp.device": "Ajouter un DHCP Baremetal",
     "label.add.baremetal.rack.configuration": "Ajouter Configuration Rack Baremetal",
diff --git a/ui/l10n/hu.js b/ui/l10n/hu.js
index 41edd47..8337b5a 100644
--- a/ui/l10n/hu.js
+++ b/ui/l10n/hu.js
@@ -318,6 +318,7 @@ var dictionary = {
     "label.add.accounts": "Számlák felvétele",
     "label.add.accounts.to": "Számla felvétele:",
     "label.add.acl.list": "ACL lista felvétele",
+    "label.edit.acl.list": "Edit ACL List",
     "label.add.affinity.group": "Új affinítási csoport felvétele",
     "label.add.baremetal.dhcp.device": "Baremetal DHCP eszköz felvétele",
     "label.add.baremetal.rack.configuration": "Baremetal rack konfiguráció felvétele",
diff --git a/ui/l10n/it_IT.js b/ui/l10n/it_IT.js
index 30d0b32..a54f177 100644
--- a/ui/l10n/it_IT.js
+++ b/ui/l10n/it_IT.js
@@ -318,6 +318,7 @@ var dictionary = {
     "label.add.accounts": "Aggiungere utenti",
     "label.add.accounts.to": "Aggiungere utenti a",
     "label.add.acl.list": "Add ACL List",
+    "label.edit.acl.list": "Edit ACL List",
     "label.add.affinity.group": "Aggiungere un nuovo gruppo di affinità",
     "label.add.baremetal.dhcp.device": "Add Baremetal DHCP Device",
     "label.add.baremetal.rack.configuration": "Add Baremetal Rack Configuration",
diff --git a/ui/l10n/ja_JP.js b/ui/l10n/ja_JP.js
index 24f99e7..d02b62c 100644
--- a/ui/l10n/ja_JP.js
+++ b/ui/l10n/ja_JP.js
@@ -318,6 +318,7 @@ var dictionary = {
     "label.add.accounts": "アカウントの追加",
     "label.add.accounts.to": "アカウントの追加先:",
     "label.add.acl.list": "ACL 一覧の追加",
+    "label.edit.acl.list": "Edit ACL List",
     "label.add.affinity.group": "新しいアフィニティ グループの追加",
     "label.add.baremetal.dhcp.device": "ベアメタル DHCP デバイスの追加",
     "label.add.baremetal.rack.configuration": "ベアメタルラック設定の追加",
diff --git a/ui/l10n/ko_KR.js b/ui/l10n/ko_KR.js
index 19d80fb..731ccac 100644
--- a/ui/l10n/ko_KR.js
+++ b/ui/l10n/ko_KR.js
@@ -318,6 +318,7 @@ var dictionary = {
     "label.add.accounts": "계정 정보 추가",
     "label.add.accounts.to": "계정 정보 추가:",
     "label.add.acl.list": "Add ACL List",
+    "label.edit.acl.list": "Edit ACL List",
     "label.add.affinity.group": "Add new affinity group",
     "label.add.baremetal.dhcp.device": "Add Baremetal DHCP Device",
     "label.add.baremetal.rack.configuration": "Add Baremetal Rack Configuration",
diff --git a/ui/l10n/nb_NO.js b/ui/l10n/nb_NO.js
index 6adc995..7785ea8 100644
--- a/ui/l10n/nb_NO.js
+++ b/ui/l10n/nb_NO.js
@@ -318,6 +318,7 @@ var dictionary = {
     "label.add.accounts": "Legg til kontoer",
     "label.add.accounts.to": "Legg kontoer til",
     "label.add.acl.list": "Legg til ACL liste",
+    "label.edit.acl.list": "Edit ACL List",
     "label.add.affinity.group": "Legg til affinitetsgruppe",
     "label.add.baremetal.dhcp.device": "Legg Til Barmetall DHCP Enhet",
     "label.add.baremetal.rack.configuration": "Legg Til Barmetall Rack Konfigurering",
diff --git a/ui/l10n/nl_NL.js b/ui/l10n/nl_NL.js
index f460214..1b3fd0e 100644
--- a/ui/l10n/nl_NL.js
+++ b/ui/l10n/nl_NL.js
@@ -318,6 +318,7 @@ var dictionary = {
     "label.add.accounts": "Voeg accounts toe",
     "label.add.accounts.to": "Voeg accounts toe aan",
     "label.add.acl.list": "voeg een ACL lijst toe",
+    "label.edit.acl.list": "Verander een ACL lijst",
     "label.add.affinity.group": "Nieuwe affinity groep toevoegen",
     "label.add.baremetal.dhcp.device": "Voeg Baremetal DHCP Apparaat toe",
     "label.add.baremetal.rack.configuration": "voeg baremetal rek configuratie toe",
diff --git a/ui/l10n/pl.js b/ui/l10n/pl.js
index 0d89f1e..6cb486b 100644
--- a/ui/l10n/pl.js
+++ b/ui/l10n/pl.js
@@ -318,6 +318,7 @@ var dictionary = {
     "label.add.accounts": "Dodaj konta",
     "label.add.accounts.to": "Dodaj konto do",
     "label.add.acl.list": "Add ACL List",
+    "label.edit.acl.list": "Edit ACL List",
     "label.add.affinity.group": "Add new affinity group",
     "label.add.baremetal.dhcp.device": "Add Baremetal DHCP Device",
     "label.add.baremetal.rack.configuration": "Add Baremetal Rack Configuration",
diff --git a/ui/l10n/pt_BR.js b/ui/l10n/pt_BR.js
index 52066c3..04d129c 100644
--- a/ui/l10n/pt_BR.js
+++ b/ui/l10n/pt_BR.js
@@ -318,6 +318,7 @@ var dictionary = {
     "label.add.accounts": "Adicionar contas",
     "label.add.accounts.to": "Adicionar contas para",
     "label.add.acl.list": "Adiciona Lista ACL",
+    "label.edit.acl.list": "Edit ACL List",
     "label.add.affinity.group": "Adicionar um grupo de afinidade",
     "label.add.baremetal.dhcp.device": "Adiciona Dispositivo DHCP Baremetal",
     "label.add.baremetal.rack.configuration": "Adicionar Configuração de Rack de Baremetal",
diff --git a/ui/l10n/ru_RU.js b/ui/l10n/ru_RU.js
index b297b40..5d3d3de 100644
--- a/ui/l10n/ru_RU.js
+++ b/ui/l10n/ru_RU.js
@@ -318,6 +318,7 @@ var dictionary = {
     "label.add.accounts": "Добавить учётные записи",
     "label.add.accounts.to": "Добавить учётные записи",
     "label.add.acl.list": "Add ACL List",
+    "label.edit.acl.list": "Edit ACL List",
     "label.add.affinity.group": "Добавить новую affinity group",
     "label.add.baremetal.dhcp.device": "Add Baremetal DHCP Device",
     "label.add.baremetal.rack.configuration": "Add Baremetal Rack Configuration",
diff --git a/ui/l10n/zh_CN.js b/ui/l10n/zh_CN.js
index c6965c6..e733b44 100644
--- a/ui/l10n/zh_CN.js
+++ b/ui/l10n/zh_CN.js
@@ -318,6 +318,7 @@ var dictionary = {
     "label.add.accounts": "添加帐户",
     "label.add.accounts.to": "添加帐户至",
     "label.add.acl.list": "添加 ACL 列表",
+    "label.edit.acl.list": "Edit ACL List",
     "label.add.affinity.group": "添加新关联性组",
     "label.add.baremetal.dhcp.device": "添加裸机 DHCP 设备",
     "label.add.baremetal.rack.configuration": "添加 Baremetal Rack 配置",
diff --git a/ui/scripts/ui/widgets/detailView.js b/ui/scripts/ui/widgets/detailView.js
index 2ce72a2..350ee83 100644
--- a/ui/scripts/ui/widgets/detailView.js
+++ b/ui/scripts/ui/widgets/detailView.js
@@ -606,7 +606,7 @@
                                 } else {
                                     $loading.appendTo($detailView);
                                     cloudStack.ui.notifications.add(
-                                        $.extend(true, {}, action.notification, notificationArgs),
+                                        $.extend(true, {}, notificationArgs, action.notification),
                                         function(args) {
                                             replaceListViewItem($detailView, data);
 
diff --git a/ui/scripts/vpc.js b/ui/scripts/vpc.js
index 7eb589e..d7980c9 100644
--- a/ui/scripts/vpc.js
+++ b/ui/scripts/vpc.js
@@ -1330,6 +1330,37 @@
                                 notification: {
                                     poll: pollAsyncJobResult
                                 }
+                            },
+                            edit: {
+                                label: 'label.edit.acl.list',
+                                action: function(args) {
+                                    var data = args.data;
+                                    data.id = args.context.aclLists[0].id;
+                                    $.ajax({
+                                        url: createURL('updateNetworkACLList'),
+                                        type: "POST",
+                                        data: data,
+                                        success: function(json) {
+                                            var jid = json.updatenetworkacllistresponse.jobid;
+                                            args.response.success({
+                                                _custom: {
+                                                    jobId: jid,
+                                                    getUpdatedItem: function() {
+                                                        $(window).trigger('cloudStack.fullRefresh');
+                                                        jQuery('div[id=breadcrumbs] ul:visible li span').last().html(data.name);
+                                                    }
+                                                }
+                                            });
+                                        },
+                                        error: function(json) {
+                                            args.response.error(parseXMLHttpResponse(json));
+                                        }
+                                    });
+                                },
+                                notification: {
+                                    poll: pollAsyncJobResult,
+                                    desc: 'label.edit.acl.list'
+                                }
                             }
                         },
 
@@ -1342,7 +1373,8 @@
                                         isEditable: true
                                     },
                                     description: {
-                                        label: 'label.description'
+                                        label: 'label.description',
+                                        isEditable: true  
                                     },
                                     id: {
                                         label: 'label.id'
@@ -1357,6 +1389,7 @@
                                                 var allowedActions = [];
                                                 if (items.vpcid != null) {
                                                     allowedActions.push("remove");
+                                                    allowedActions.push("edit");
                                                 }
                                                 return allowedActions;
                                             }

-- 
To stop receiving notification emails like this one, please contact
rafael@apache.org.