Updated Branches:
  refs/heads/master 81e1ba3bb -> eae22d2ff

CLOUDSTACK-741: Granular Global Parameters

Signed-off-by: Abhinandan Prateek <[email protected]>


Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo
Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/eae22d2f
Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/eae22d2f
Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/eae22d2f

Branch: refs/heads/master
Commit: eae22d2ffaee68b5d4443cf8ab1b2dfbb339dab3
Parents: 81e1ba3
Author: Harikrishna Patnala <[email protected]>
Authored: Fri Apr 19 09:27:00 2013 +0530
Committer: Abhinandan Prateek <[email protected]>
Committed: Fri Apr 19 10:36:52 2013 +0530

----------------------------------------------------------------------
 .../api/command/admin/config/ListCfgsByCmd.java    |   24 +++-
 .../api/command/admin/config/UpdateCfgCmd.java     |   22 +++-
 .../api/response/ConfigurationResponse.java        |   12 ++
 .../api/command/test/ListCfgCmdTest.java           |   89 +++++++++++
 .../api/command/test/UpdateCfgCmdTest.java         |  116 +++++++++++++++
 .../datastore/db/StoragePoolDetailsDao.java        |    1 +
 server/src/com/cloud/configuration/Config.java     |   54 ++++++-
 .../cloud/configuration/ConfigurationManager.java  |    2 +-
 .../configuration/ConfigurationManagerImpl.java    |   51 +++++--
 .../cloud/configuration/dao/ConfigurationDao.java  |    1 +
 .../router/VirtualNetworkApplianceManagerImpl.java |    5 +-
 .../src/com/cloud/server/ConfigurationServer.java  |    5 +
 .../com/cloud/server/ConfigurationServerImpl.java  |   93 ++++++++++--
 .../src/com/cloud/server/ManagementServerImpl.java |   24 +++-
 .../storage/dao/StoragePoolDetailsDaoImpl.java     |    9 +
 .../cloud/vpc/MockConfigurationManagerImpl.java    |    5 +-
 test/integration/smoke/test_UpdateCfg.py           |   85 +++++++++++
 17 files changed, 561 insertions(+), 37 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java
----------------------------------------------------------------------
diff --git 
a/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java 
b/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java
index aabfd4a..9f34405 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/config/ListCfgsByCmd.java
@@ -23,8 +23,7 @@ import org.apache.cloudstack.api.APICommand;
 import org.apache.cloudstack.api.ApiConstants;
 import org.apache.cloudstack.api.BaseListCmd;
 import org.apache.cloudstack.api.Parameter;
-import org.apache.cloudstack.api.response.ConfigurationResponse;
-import org.apache.cloudstack.api.response.ListResponse;
+import org.apache.cloudstack.api.response.*;
 import org.apache.log4j.Logger;
 
 import com.cloud.configuration.Configuration;
@@ -46,6 +45,13 @@ public class ListCfgsByCmd extends BaseListCmd {
     @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, 
description = "lists configuration by name")
     private String configName;
 
+    @Parameter(name=ApiConstants.SCOPE, type = CommandType.STRING, description 
= "scope(zone/cluster/pool/account) of the parameter that needs to be updated")
+    private String scope;
+
+    @Parameter(name=ApiConstants.ID, type = CommandType.UUID, entityType = 
{ZoneResponse.class, ClusterResponse.class, StoragePoolResponse.class, 
AccountResponse.class}, description = "corresponding ID of the scope")
+    private Long id;
+
+
     // ///////////////////////////////////////////////////
     // ///////////////// Accessors ///////////////////////
     // ///////////////////////////////////////////////////
@@ -58,6 +64,15 @@ public class ListCfgsByCmd extends BaseListCmd {
         return configName;
     }
 
+    public String getScope() {
+        return scope;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+
     @Override
     public Long getPageSizeVal() {
         Long pageSizeVal = 500L;
@@ -85,6 +100,11 @@ public class ListCfgsByCmd extends BaseListCmd {
         for (Configuration cfg : result.first()) {
             ConfigurationResponse cfgResponse = 
_responseGenerator.createConfigurationResponse(cfg);
             cfgResponse.setObjectName("configuration");
+            if (scope != null) {
+                cfgResponse.setScope(scope);
+            } else {
+                cfgResponse.setScope("global");
+            }
             configResponses.add(cfgResponse);
         }
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
----------------------------------------------------------------------
diff --git 
a/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java 
b/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
index ffeb586..074c5a3 100644
--- a/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
+++ b/api/src/org/apache/cloudstack/api/command/admin/config/UpdateCfgCmd.java
@@ -22,7 +22,7 @@ import org.apache.cloudstack.api.ApiErrorCode;
 import org.apache.cloudstack.api.BaseCmd;
 import org.apache.cloudstack.api.Parameter;
 import org.apache.cloudstack.api.ServerApiException;
-import org.apache.cloudstack.api.response.ConfigurationResponse;
+import org.apache.cloudstack.api.response.*;
 import org.apache.log4j.Logger;
 
 import com.cloud.configuration.Configuration;
@@ -43,6 +43,12 @@ public class UpdateCfgCmd extends BaseCmd {
     @Parameter(name=ApiConstants.VALUE, type=CommandType.STRING, 
description="the value of the configuration", length=4095)
     private String value;
 
+    @Parameter(name=ApiConstants.SCOPE, type = CommandType.STRING, description 
= "scope(zone/cluster/pool/account) of the parameter that needs to be updated")
+    private String scope;
+
+    @Parameter(name=ApiConstants.ID, type = CommandType.UUID, entityType = 
{ZoneResponse.class, ClusterResponse.class, StoragePoolResponse.class, 
AccountResponse.class}, description = "corresponding ID of the scope")
+    private Long id;
+
     /////////////////////////////////////////////////////
     /////////////////// Accessors ///////////////////////
     /////////////////////////////////////////////////////
@@ -55,6 +61,14 @@ public class UpdateCfgCmd extends BaseCmd {
         return value;
     }
 
+    public String getScope() {
+        return scope;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
     /////////////////////////////////////////////////////
     /////////////// API Implementation///////////////////
     /////////////////////////////////////////////////////
@@ -75,6 +89,12 @@ public class UpdateCfgCmd extends BaseCmd {
         if (cfg != null) {
             ConfigurationResponse response = 
_responseGenerator.createConfigurationResponse(cfg);
             response.setResponseName(getCommandName());
+            if (scope != null) {
+                response.setScope(scope);
+                response.setValue(value);
+            } else {
+                response.setScope("global");
+            }
             this.setResponseObject(response);
         } else {
             throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed 
to update config");

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/api/src/org/apache/cloudstack/api/response/ConfigurationResponse.java
----------------------------------------------------------------------
diff --git 
a/api/src/org/apache/cloudstack/api/response/ConfigurationResponse.java 
b/api/src/org/apache/cloudstack/api/response/ConfigurationResponse.java
index 95b8af2..176c47a 100644
--- a/api/src/org/apache/cloudstack/api/response/ConfigurationResponse.java
+++ b/api/src/org/apache/cloudstack/api/response/ConfigurationResponse.java
@@ -32,9 +32,13 @@ public class ConfigurationResponse extends BaseResponse {
     @SerializedName(ApiConstants.VALUE) @Param(description="the value of the 
configuration")
     private String value;
 
+    @SerializedName(ApiConstants.SCOPE) 
@Param(description="scope(zone/cluster/pool/account) of the parameter that 
needs to be updated")
+    private String scope;
+
     @SerializedName(ApiConstants.DESCRIPTION) @Param(description="the 
description of the configuration")
     private String description;
 
+
     public String getCategory() {
         return category;
     }
@@ -66,4 +70,12 @@ public class ConfigurationResponse extends BaseResponse {
     public void setDescription(String description) {
         this.description = description;
     }
+
+    public String getScope() {
+        return scope;
+    }
+
+    public void setScope(String scope) {
+        this.scope = scope;
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/api/test/org/apache/cloudstack/api/command/test/ListCfgCmdTest.java
----------------------------------------------------------------------
diff --git 
a/api/test/org/apache/cloudstack/api/command/test/ListCfgCmdTest.java 
b/api/test/org/apache/cloudstack/api/command/test/ListCfgCmdTest.java
new file mode 100644
index 0000000..7c05eaf
--- /dev/null
+++ b/api/test/org/apache/cloudstack/api/command/test/ListCfgCmdTest.java
@@ -0,0 +1,89 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.test;
+
+import com.cloud.configuration.Configuration;
+import com.cloud.configuration.ConfigurationService;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.resource.ResourceService;
+import com.cloud.server.ManagementService;
+import com.cloud.utils.Pair;
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.cloudstack.api.ResponseGenerator;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd;
+import org.apache.cloudstack.api.response.ConfigurationResponse;
+import org.apache.cloudstack.api.response.ListResponse;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class ListCfgCmdTest extends TestCase{
+
+    private ListCfgsByCmd listCfgsByCmd;
+    private ManagementService mgr;
+    private ResponseGenerator responseGenerator;
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Before
+    public void setUp() {
+        responseGenerator = Mockito.mock(ResponseGenerator.class);
+        mgr = Mockito.mock(ManagementService.class);
+        listCfgsByCmd = new ListCfgsByCmd();
+    }
+
+    @Test
+    public void testCreateSuccess() {
+
+        Configuration cfg = Mockito.mock(Configuration.class);
+        listCfgsByCmd._mgr = mgr;
+        listCfgsByCmd._responseGenerator = responseGenerator;
+
+
+
+        List<Configuration> configList = new ArrayList<Configuration>();
+        configList.add(cfg);
+
+        Pair<List<? extends Configuration>, Integer> result = new Pair<List<? 
extends Configuration>, Integer>(configList, 1);
+
+        try {
+            Mockito.when(
+                    mgr.searchForConfigurations(listCfgsByCmd))
+                    .thenReturn(result);
+        }catch (Exception e){
+            Assert.fail("Received exception when success expected " + 
e.getMessage());
+        }
+        ConfigurationResponse cfgResponse = new ConfigurationResponse();
+        cfgResponse.setName("Test case");
+        
Mockito.when(responseGenerator.createConfigurationResponse(cfg)).thenReturn(cfgResponse);
+
+        listCfgsByCmd.execute();
+        Mockito.verify(responseGenerator).createConfigurationResponse(cfg);
+
+        ListResponse<ConfigurationResponse> actualResponse = 
(ListResponse<ConfigurationResponse>) listCfgsByCmd.getResponseObject();
+        Assert.assertEquals(cfgResponse, actualResponse.getResponses().get(0));
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java
----------------------------------------------------------------------
diff --git 
a/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java 
b/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java
new file mode 100644
index 0000000..27000cf
--- /dev/null
+++ b/api/test/org/apache/cloudstack/api/command/test/UpdateCfgCmdTest.java
@@ -0,0 +1,116 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+package org.apache.cloudstack.api.command.test;
+
+import com.cloud.configuration.Configuration;
+import com.cloud.configuration.ConfigurationService;
+import com.cloud.exception.InvalidParameterValueException;
+import com.cloud.resource.ResourceService;
+import junit.framework.Assert;
+import junit.framework.TestCase;
+import org.apache.cloudstack.api.ResponseGenerator;
+import org.apache.cloudstack.api.ServerApiException;
+import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
+import org.apache.cloudstack.api.response.ConfigurationResponse;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+import org.mockito.Mockito;
+
+public class UpdateCfgCmdTest extends TestCase{
+
+    private UpdateCfgCmd updateCfgCmd;
+    private ConfigurationService configService;
+    private ResponseGenerator responseGenerator;
+
+    @Rule
+    public ExpectedException expectedException = ExpectedException.none();
+
+    @Before
+    public void setUp() {
+        responseGenerator = Mockito.mock(ResponseGenerator.class);
+        configService = Mockito.mock(ConfigurationService.class);
+        updateCfgCmd = new UpdateCfgCmd();
+    }
+
+    @Test
+    public void testExecuteForEmptyResult() {
+        updateCfgCmd._configService = configService;
+
+        try {
+            updateCfgCmd.execute();
+        } catch (ServerApiException exception) {
+            Assert.assertEquals("Failed to update config",
+                    exception.getDescription());
+        }
+
+    }
+
+    @Test
+    public void testExecuteForNullResult() {
+
+        updateCfgCmd._configService = configService;
+
+        try {
+            Mockito.when(
+                    configService.updateConfiguration(updateCfgCmd))
+                    .thenReturn(null);
+        } catch (InvalidParameterValueException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        } catch (IllegalArgumentException e) {
+            // TODO Auto-generated catch block
+            e.printStackTrace();
+        }
+        try {
+            updateCfgCmd.execute();
+        } catch (ServerApiException exception) {
+            Assert.assertEquals("Failed to update config",
+                    exception.getDescription());
+        }
+
+    }
+
+
+    @Test
+    public void testCreateSuccess() {
+
+        Configuration cfg = Mockito.mock(Configuration.class);
+        updateCfgCmd._configService = configService;
+        updateCfgCmd._responseGenerator = responseGenerator;
+
+        try {
+            Mockito.when(
+                    configService.updateConfiguration(updateCfgCmd))
+                    .thenReturn(cfg);
+        }catch (Exception e){
+            Assert.fail("Received exception when success expected " + 
e.getMessage());
+        }
+
+        ConfigurationResponse response = new ConfigurationResponse();
+        response.setName("Test case");
+        
Mockito.when(responseGenerator.createConfigurationResponse(cfg)).thenReturn(response);
+
+        updateCfgCmd.execute();
+        Mockito.verify(responseGenerator).createConfigurationResponse(cfg);
+        ConfigurationResponse actualResponse = (ConfigurationResponse) 
updateCfgCmd.getResponseObject();
+        Assert.assertEquals(response, actualResponse);
+        Assert.assertEquals("updateconfigurationresponse", 
response.getResponseName());
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolDetailsDao.java
----------------------------------------------------------------------
diff --git 
a/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolDetailsDao.java
 
b/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolDetailsDao.java
index be71670..237f235 100644
--- 
a/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolDetailsDao.java
+++ 
b/engine/api/src/org/apache/cloudstack/storage/datastore/db/StoragePoolDetailsDao.java
@@ -25,4 +25,5 @@ public interface StoragePoolDetailsDao extends 
GenericDao<StoragePoolDetailVO, L
     
     void update(long poolId, Map<String, String> details);
     Map<String, String> getDetails(long poolId);
+    StoragePoolDetailVO findDetail(long poolId, String name);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/src/com/cloud/configuration/Config.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/Config.java 
b/server/src/com/cloud/configuration/Config.java
index 2993966..4d1185a 100755
--- a/server/src/com/cloud/configuration/Config.java
+++ b/server/src/com/cloud/configuration/Config.java
@@ -16,9 +16,7 @@
 // under the License.
 package com.cloud.configuration;
 
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
+import java.util.*;
 
 import org.apache.cloudstack.engine.subsystem.api.storage.StoragePoolAllocator;
 
@@ -339,7 +337,7 @@ public enum Config {
        //disabling lb as cluster sync does not work with distributed cluster
        AgentLbEnable("Advanced", ManagementServer.class, Boolean.class, 
"agent.lb.enabled", "false", "If agent load balancing enabled in cluster 
setup", null),
        SubDomainNetworkAccess("Advanced", NetworkManager.class, Boolean.class, 
"allow.subdomain.network.access", "true", "Allow subdomains to use networks 
dedicated to their parent domain(s)", null),
-       UseExternalDnsServers("Advanced", NetworkManager.class, Boolean.class, 
"use.external.dns", "false", "Bypass internal dns, use external dns1 and dns2", 
null),
+       UseExternalDnsServers("Advanced", NetworkManager.class, Boolean.class, 
"use.external.dns", "false", "Bypass internal dns, use external dns1 and dns2", 
null, ConfigurationParameterScope.zone.toString()),
        EncodeApiResponse("Advanced", ManagementServer.class, Boolean.class, 
"encode.api.response", "false", "Do URL encoding for the api response, false by 
default", null),
        DnsBasicZoneUpdates("Advanced", NetworkManager.class, String.class, 
"network.dns.basiczone.updates", "all", "This parameter can take 2 values: all 
(default) and pod. It defines if DHCP/DNS requests have to be send to all dhcp 
servers in cloudstack, or only to the one in the same pod", "all,pod"),
 
@@ -412,6 +410,35 @@ public enum Config {
     private final String _defaultValue;
     private final String _description;
     private final String _range;
+    private final String _scope; // Parameter can be at different levels 
(Zone/cluster/pool/account), by default every parameter is at global
+
+    public static enum ConfigurationParameterScope {
+        global,
+        zone,
+        cluster,
+        pool,
+        account
+    }
+
+    private static final HashMap<String, List<Config>> _scopeLevelConfigsMap = 
new HashMap<String, List<Config>>();
+    static {
+        _scopeLevelConfigsMap.put(ConfigurationParameterScope.zone.toString(), 
new ArrayList<Config>());
+        
_scopeLevelConfigsMap.put(ConfigurationParameterScope.cluster.toString(), new 
ArrayList<Config>());
+        _scopeLevelConfigsMap.put(ConfigurationParameterScope.pool.toString(), 
new ArrayList<Config>());
+        
_scopeLevelConfigsMap.put(ConfigurationParameterScope.account.toString(), new 
ArrayList<Config>());
+        
_scopeLevelConfigsMap.put(ConfigurationParameterScope.global.toString(), new 
ArrayList<Config>());
+
+        for (Config c : Config.values()) {
+            //Creating group of parameters per each level 
(zone/cluster/pool/account)
+            StringTokenizer tokens = new StringTokenizer(c.getScope(), ",");
+            while (tokens.hasMoreTokens()) {
+                String scope = tokens.nextToken().trim();
+                List<Config> currentConfigs = _scopeLevelConfigsMap.get(scope);
+                currentConfigs.add(c);
+                _scopeLevelConfigsMap.put(scope, currentConfigs);
+            }
+        }
+    }
 
     private static final HashMap<String, List<Config>> _configs = new 
HashMap<String, List<Config>>();
     static {
@@ -447,6 +474,17 @@ public enum Config {
        _defaultValue = defaultValue;
        _description = description;
        _range = range;
+        _scope = ConfigurationParameterScope.global.toString();
+    }
+    private Config(String category, Class<?> componentClass, Class<?> type, 
String name, String defaultValue, String description, String range, String 
scope) {
+        _category = category;
+        _componentClass = componentClass;
+        _type = type;
+        _name = name;
+        _defaultValue = defaultValue;
+        _description = description;
+        _range = range;
+        _scope = scope;
     }
 
     public String getCategory() {
@@ -473,6 +511,10 @@ public enum Config {
         return _componentClass;
     }
 
+    public String getScope() {
+        return _scope;
+    }
+
     public String getComponent() {
        if (_componentClass == ManagementServer.class) {
             return "management-server";
@@ -530,4 +572,8 @@ public enum Config {
        }
        return categories;
     }
+
+    public static List<Config> getConfigListByScope(String scope) {
+        return _scopeLevelConfigsMap.get(scope);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/src/com/cloud/configuration/ConfigurationManager.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java 
b/server/src/com/cloud/configuration/ConfigurationManager.java
index afaf0d6..738c5ba 100755
--- a/server/src/com/cloud/configuration/ConfigurationManager.java
+++ b/server/src/com/cloud/configuration/ConfigurationManager.java
@@ -60,7 +60,7 @@ public interface ConfigurationManager extends 
ConfigurationService, Manager {
      * @param name
      * @param value
      */
-    void updateConfiguration(long userId, String name, String category, String 
value);
+    void updateConfiguration(long userId, String name, String category, String 
value, String scope, Long id);
 
     /**
      * Creates a new service offering

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java 
b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
index 4fc2db7..d142ca6 100755
--- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
+++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java
@@ -39,6 +39,7 @@ import javax.naming.NamingException;
 import javax.naming.directory.DirContext;
 import javax.naming.directory.InitialDirContext;
 
+import com.cloud.dc.dao.*;
 import org.apache.cloudstack.acl.SecurityChecker;
 import org.apache.cloudstack.api.ApiConstants.LDAPParams;
 import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
@@ -78,20 +79,13 @@ import com.cloud.dc.DataCenter.NetworkType;
 import com.cloud.dc.DataCenterIpAddressVO;
 import com.cloud.dc.DataCenterLinkLocalIpAddressVO;
 import com.cloud.dc.DataCenterVO;
+import com.cloud.dc.DcDetailVO;
 import com.cloud.dc.HostPodVO;
 import com.cloud.dc.Pod;
 import com.cloud.dc.PodVlanMapVO;
 import com.cloud.dc.Vlan;
 import com.cloud.dc.Vlan.VlanType;
 import com.cloud.dc.VlanVO;
-import com.cloud.dc.dao.AccountVlanMapDao;
-import com.cloud.dc.dao.ClusterDao;
-import com.cloud.dc.dao.DataCenterDao;
-import com.cloud.dc.dao.DataCenterIpAddressDao;
-import com.cloud.dc.dao.DataCenterLinkLocalIpAddressDao;
-import com.cloud.dc.dao.HostPodDao;
-import com.cloud.dc.dao.PodVlanMapDao;
-import com.cloud.dc.dao.VlanDao;
 import com.cloud.deploy.DataCenterDeployment;
 import com.cloud.domain.Domain;
 import com.cloud.domain.DomainVO;
@@ -188,6 +182,8 @@ public class ConfigurationManagerImpl extends ManagerBase 
implements Configurati
     @Inject
     DataCenterDao _zoneDao;
     @Inject
+    DcDetailsDao _zoneDetailsDao;
+    @Inject
     DomainDao _domainDao;
     @Inject
     SwiftDao _swiftDao;
@@ -327,15 +323,37 @@ public class ConfigurationManagerImpl extends ManagerBase 
implements Configurati
 
     @Override
     @DB
-    public void updateConfiguration(long userId, String name, String category, 
String value) {
+    public void updateConfiguration(long userId, String name, String category, 
String value, String scope, Long resourceId) {
 
-        String validationMsg = validateConfigurationValue(name, value);
+        String validationMsg = validateConfigurationValue(name, value, scope);
 
         if (validationMsg != null) {
             s_logger.error("Invalid configuration option, name: " + name + ", 
value:" + value);
             throw new InvalidParameterValueException(validationMsg);
         }
 
+        // If scope of the parameter is given then it needs to be updated in 
the corresponding details table,
+        // if scope is mentioned as global or not mentioned then it is normal 
global parameter updation
+        if (scope != null && !scope.isEmpty() && 
!Config.ConfigurationParameterScope.global.toString().equalsIgnoreCase(scope)) {
+            if 
(Config.ConfigurationParameterScope.zone.toString().equalsIgnoreCase(scope)) {
+                DataCenterVO zone = _zoneDao.findById(resourceId);
+                if (zone == null) {
+                    throw new InvalidParameterValueException("unable to find 
zone by id " + resourceId);
+                }
+                DcDetailVO dcDetailVO = _zoneDetailsDao.findDetail(resourceId, 
name.toLowerCase());
+                if (dcDetailVO == null) {
+                    dcDetailVO = new DcDetailVO(dcDetailVO.getId(), name, 
value);
+                    _zoneDetailsDao.persist(dcDetailVO);
+                } else {
+                    dcDetailVO.setValue(value);
+                    _zoneDetailsDao.update(resourceId, dcDetailVO);
+                }
+            } else {
+                s_logger.error("TO Do for the remaining levels 
(cluster/pool/account)");
+                throw new InvalidParameterValueException("The scope "+ scope 
+" yet to be implemented");
+            }
+        }
+
         // Execute all updates in a single transaction
         Transaction txn = Transaction.currentTxn();
         txn.start();
@@ -440,6 +458,8 @@ public class ConfigurationManagerImpl extends ManagerBase 
implements Configurati
         Long userId = UserContext.current().getCallerUserId();
         String name = cmd.getCfgName();
         String value = cmd.getValue();
+        String scope = cmd.getScope();
+        Long id = cmd.getId();
         UserContext.current().setEventDetails(" Name: " + name + " New Value: 
" + (((name.toLowerCase()).contains("password")) ? "*****" :
                 (((value == null) ? "" : value))));
         // check if config value exists
@@ -456,7 +476,7 @@ public class ConfigurationManagerImpl extends ManagerBase 
implements Configurati
             value = null;
         }
 
-        updateConfiguration(userId, name, config.getCategory(), value);
+        updateConfiguration(userId, name, config.getCategory(), value, scope, 
id);
         String updatedValue = _configDao.getValue(name);
         if ((value == null && updatedValue == null) || 
updatedValue.equalsIgnoreCase(value)) {
             return _configDao.findByName(name);
@@ -466,13 +486,20 @@ public class ConfigurationManagerImpl extends ManagerBase 
implements Configurati
         }
     }
 
-    private String validateConfigurationValue(String name, String value) {
+    private String validateConfigurationValue(String name, String value, 
String scope) {
 
         Config c = Config.getConfig(name);
         if (c == null) {
             s_logger.error("Missing configuration variable " + name + " in 
configuration table");
             return "Invalid configuration variable.";
         }
+        String configScope = c.getScope();
+        if (scope != null && !scope.isEmpty()) {
+            if (!configScope.contains(scope)) {
+                s_logger.error("Invalid scope " + scope + " for the parameter 
" + name);
+                return "Invalid scope for the parameter.";
+            }
+        }
 
         Class<?> type = c.getType();
 

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/src/com/cloud/configuration/dao/ConfigurationDao.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/configuration/dao/ConfigurationDao.java 
b/server/src/com/cloud/configuration/dao/ConfigurationDao.java
index c86c024..2b09901 100644
--- a/server/src/com/cloud/configuration/dao/ConfigurationDao.java
+++ b/server/src/com/cloud/configuration/dao/ConfigurationDao.java
@@ -17,6 +17,7 @@
 package com.cloud.configuration.dao;
 
 import java.util.Map;
+import java.util.List;
 
 import com.cloud.configuration.ConfigurationVO;
 import com.cloud.utils.db.GenericDao;

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
----------------------------------------------------------------------
diff --git 
a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java 
b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
index ab91059..4c7bc75 100755
--- 
a/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
+++ 
b/server/src/com/cloud/network/router/VirtualNetworkApplianceManagerImpl.java
@@ -40,6 +40,7 @@ import javax.ejb.Local;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import com.cloud.server.ConfigurationServer;
 import org.apache.cloudstack.api.command.admin.router.UpgradeRouterCmd;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
@@ -286,6 +287,8 @@ public class VirtualNetworkApplianceManagerImpl extends 
ManagerBase implements V
     @Inject
     ConfigurationManager _configMgr;
     @Inject
+    ConfigurationServer _configServer;
+    @Inject
     ServiceOfferingDao _serviceOfferingDao = null;
     @Inject
     UserVmDao _userVmDao;
@@ -2094,7 +2097,7 @@ public class VirtualNetworkApplianceManagerImpl extends 
ManagerBase implements V
 
             boolean useExtDns = !dnsProvided;
             /* For backward compatibility */
-            String use_external_dns =  
_configDao.getValue(Config.UseExternalDnsServers.key());
+            String use_external_dns = 
_configServer.getConfigValue(Config.UseExternalDnsServers.key(), 
Config.ConfigurationParameterScope.zone.toString(), dc.getId());
             if (use_external_dns != null && use_external_dns.equals("true")) {
                 useExtDns = true;
             }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/src/com/cloud/server/ConfigurationServer.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ConfigurationServer.java 
b/server/src/com/cloud/server/ConfigurationServer.java
index f441b1f..c1306d5 100644
--- a/server/src/com/cloud/server/ConfigurationServer.java
+++ b/server/src/com/cloud/server/ConfigurationServer.java
@@ -16,6 +16,9 @@
 // under the License.
 package com.cloud.server;
 
+import java.util.List;
+
+import com.cloud.configuration.ConfigurationVO;
 import com.cloud.exception.InternalErrorException;
 
 /**
@@ -30,4 +33,6 @@ public interface ConfigurationServer {
      */
     public void persistDefaultValues() throws InternalErrorException;
     public void updateKeyPairs();
+    public String getConfigValue(String name, String scope, Long resourceId);
+    public List<ConfigurationVO> getConfigListByScope(String scope, Long 
resourceId);
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/src/com/cloud/server/ConfigurationServerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java 
b/server/src/com/cloud/server/ConfigurationServerImpl.java
index c4da1ab..cd890ce 100755
--- a/server/src/com/cloud/server/ConfigurationServerImpl.java
+++ b/server/src/com/cloud/server/ConfigurationServerImpl.java
@@ -36,28 +36,29 @@ import java.util.Map;
 import java.util.Properties;
 import java.util.UUID;
 import java.util.regex.Pattern;
+import java.util.StringTokenizer;
 
 import javax.crypto.KeyGenerator;
 import javax.crypto.SecretKey;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import com.cloud.configuration.*;
+import com.cloud.dc.*;
+import com.cloud.dc.dao.DcDetailsDao;
+import com.cloud.user.*;
+import com.cloud.utils.db.GenericDao;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailVO;
+import org.apache.cloudstack.storage.datastore.db.StoragePoolDetailsDao;
 import org.apache.commons.codec.binary.Base64;
 import org.apache.log4j.Logger;
 import org.springframework.stereotype.Component;
 
-import com.cloud.configuration.Config;
-import com.cloud.configuration.ConfigurationVO;
-import com.cloud.configuration.Resource;
 import com.cloud.configuration.Resource.ResourceOwnerType;
 import com.cloud.configuration.Resource.ResourceType;
-import com.cloud.configuration.ResourceCountVO;
 import com.cloud.configuration.dao.ConfigurationDao;
 import com.cloud.configuration.dao.ResourceCountDao;
 import com.cloud.dc.DataCenter.NetworkType;
-import com.cloud.dc.DataCenterVO;
-import com.cloud.dc.HostPodVO;
-import com.cloud.dc.VlanVO;
 import com.cloud.dc.dao.DataCenterDao;
 import com.cloud.dc.dao.HostPodDao;
 import com.cloud.dc.dao.VlanDao;
@@ -91,9 +92,6 @@ import com.cloud.service.dao.ServiceOfferingDao;
 import com.cloud.storage.DiskOfferingVO;
 import com.cloud.storage.dao.DiskOfferingDao;
 import com.cloud.test.IPRangeConfig;
-import com.cloud.user.Account;
-import com.cloud.user.AccountVO;
-import com.cloud.user.User;
 import com.cloud.user.dao.AccountDao;
 import com.cloud.utils.PasswordGenerator;
 import com.cloud.utils.PropertiesUtil;
@@ -127,6 +125,11 @@ public class ConfigurationServerImpl extends ManagerBase 
implements Configuratio
     @Inject private ResourceCountDao _resourceCountDao;
     @Inject private NetworkOfferingServiceMapDao _ntwkOfferingServiceMapDao;
     @Inject private IdentityDao _identityDao;
+    @Inject private DcDetailsDao _dcDetailsDao;
+    @Inject private ClusterDetailsDao _clusterDetailsDao;
+    @Inject private StoragePoolDetailsDao _storagePoolDetailsDao;
+    @Inject private AccountDetailsDao _accountDetailsDao;
+
 
     public ConfigurationServerImpl() {
        setRunLevel(ComponentLifecycle.RUN_LEVEL_FRAMEWORK_BOOTSTRAP);
@@ -672,6 +675,76 @@ public class ConfigurationServerImpl extends ManagerBase 
implements Configuratio
         }
     }
 
+    @Override
+    public String getConfigValue(String name, String scope, Long resourceId) {
+        // If either of scope or resourceId is null then return global config 
value otherwise return value at the scope
+        Config c = Config.getConfig(name);
+        if (c == null) {
+            throw new CloudRuntimeException("Missing configuration variable " 
+ name + " in configuration table");
+        }
+        String configScope = c.getScope();
+        if (scope != null && !scope.isEmpty()) {
+            if (!configScope.contains(scope)) {
+                throw new CloudRuntimeException("Invalid scope " + scope + " 
for the parameter " + name );
+            }
+            if (resourceId != null) {
+                switch (Config.ConfigurationParameterScope.valueOf(scope)) {
+                    case zone:      DataCenterVO zone = 
_zoneDao.findById(resourceId);
+                                    if (zone == null) {
+                                        throw new 
InvalidParameterValueException("unable to find zone by id " + resourceId);
+                                    }
+                                    DcDetailVO dcDetailVO = 
_dcDetailsDao.findDetail(resourceId, name);
+                                    if (dcDetailVO != null && 
dcDetailVO.getValue() != null) {
+                                        return dcDetailVO.getValue();
+                                    } break;
+
+                    case cluster:   ClusterDetailsVO cluster = 
_clusterDetailsDao.findById(resourceId);
+                                    if (cluster == null) {
+                                        throw new 
InvalidParameterValueException("unable to find cluster by id " + resourceId);
+                                    }
+                                    ClusterDetailsVO clusterDetailsVO = 
_clusterDetailsDao.findDetail(resourceId, name);
+                                    if (clusterDetailsVO != null && 
clusterDetailsVO.getValue() != null) {
+                                        return clusterDetailsVO.getValue();
+                                    } break;
+
+                    case pool:      StoragePoolDetailVO pool = 
_storagePoolDetailsDao.findById(resourceId);
+                                    if (pool == null) {
+                                        throw new 
InvalidParameterValueException("unable to find storage pool by id " + 
resourceId);
+                                    }
+                                    StoragePoolDetailVO storagePoolDetailVO = 
_storagePoolDetailsDao.findDetail(resourceId, name);
+                                    if (storagePoolDetailVO != null && 
storagePoolDetailVO.getValue() != null) {
+                                        return storagePoolDetailVO.getValue();
+                                    } break;
+
+                    case account:   AccountDetailVO account = 
_accountDetailsDao.findById(resourceId);
+                                    if (account == null) {
+                                        throw new 
InvalidParameterValueException("unable to find account by id " + resourceId);
+                                    }
+                                    AccountDetailVO accountDetailVO = 
_accountDetailsDao.findDetail(resourceId, name);
+                                    if (accountDetailVO != null && 
accountDetailVO.getValue() != null) {
+                                        return accountDetailVO.getValue();
+                                    } break;
+                    default:
+                }
+            }
+        }
+        return _configDao.getValue(name);
+    }
+
+    @Override
+    public List<ConfigurationVO> getConfigListByScope(String scope, Long 
resourceId) {
+
+        // Getting the list of parameters defined at the scope
+        List<Config> configList = Config.getConfigListByScope(scope);
+        List<ConfigurationVO> configVOList = new ArrayList<ConfigurationVO>();
+        for (Config param:configList){
+            ConfigurationVO configVo = _configDao.findByName(param.toString());
+            configVo.setValue(getConfigValue(param.toString(), scope, 
resourceId));
+            configVOList.add(configVo);
+        }
+        return configVOList;
+    }
+
     private void writeKeyToDisk(String key, String keyPath) {
         File keyfile = new File(keyPath);
         if (!keyfile.exists()) {

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/src/com/cloud/server/ManagementServerImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/server/ManagementServerImpl.java 
b/server/src/com/cloud/server/ManagementServerImpl.java
index 98f789a..db8db8a 100755
--- a/server/src/com/cloud/server/ManagementServerImpl.java
+++ b/server/src/com/cloud/server/ManagementServerImpl.java
@@ -44,6 +44,7 @@ import javax.crypto.spec.SecretKeySpec;
 import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 
+import com.cloud.configuration.*;
 import com.cloud.storage.dao.*;
 import org.apache.cloudstack.acl.SecurityChecker.AccessType;
 import org.apache.cloudstack.api.ApiConstants;
@@ -106,10 +107,6 @@ import com.cloud.capacity.CapacityVO;
 import com.cloud.capacity.dao.CapacityDao;
 import com.cloud.capacity.dao.CapacityDaoImpl.SummedCapacity;
 import com.cloud.cluster.ClusterManager;
-import com.cloud.configuration.Config;
-import com.cloud.configuration.Configuration;
-import com.cloud.configuration.ConfigurationManager;
-import com.cloud.configuration.ConfigurationVO;
 import com.cloud.configuration.dao.ConfigurationDao;
 import com.cloud.consoleproxy.ConsoleProxyManagementState;
 import com.cloud.consoleproxy.ConsoleProxyManager;
@@ -381,6 +378,9 @@ public class ManagementServerImpl extends ManagerBase 
implements ManagementServe
     @Inject
     S3Manager _s3Mgr;
 
+    @Inject
+    ConfigurationServer _configServer;
+
     private final ScheduledExecutorService _eventExecutor = 
Executors.newScheduledThreadPool(1, new NamedThreadFactory("EventChecker"));
     private final ScheduledExecutorService _alertExecutor = 
Executors.newScheduledThreadPool(1, new NamedThreadFactory("AlertChecker"));
     private KeystoreManager _ksMgr;
@@ -1038,6 +1038,22 @@ public class ManagementServerImpl extends ManagerBase 
implements ManagementServe
         Object name = cmd.getConfigName();
         Object category = cmd.getCategory();
         Object keyword = cmd.getKeyword();
+        Long id = cmd.getId();
+        String scope = cmd.getScope();
+
+        if (scope!= null && !scope.isEmpty()) {
+            // getting the list of parameters at requested scope
+            try {
+                
Config.ConfigurationParameterScope.valueOf(scope.toLowerCase());
+            } catch (Exception e ) {
+                throw new InvalidParameterValueException("Invalid scope " + 
scope + " while listing configuration parameters");
+            }
+            if (id == null) {
+                throw new InvalidParameterValueException("Invalid id null, id 
is needed corresponding to the scope");
+            }
+            List<ConfigurationVO> configList = 
_configServer.getConfigListByScope(scope, id);
+            return new Pair<List<? extends Configuration>, 
Integer>(configList, configList.size());
+        }
 
         if (keyword != null) {
             SearchCriteria<ConfigurationVO> ssc = 
_configDao.createSearchCriteria();

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/src/com/cloud/storage/dao/StoragePoolDetailsDaoImpl.java
----------------------------------------------------------------------
diff --git a/server/src/com/cloud/storage/dao/StoragePoolDetailsDaoImpl.java 
b/server/src/com/cloud/storage/dao/StoragePoolDetailsDaoImpl.java
index 0d797ed..a0d5d0e 100644
--- a/server/src/com/cloud/storage/dao/StoragePoolDetailsDaoImpl.java
+++ b/server/src/com/cloud/storage/dao/StoragePoolDetailsDaoImpl.java
@@ -72,4 +72,13 @@ public class StoragePoolDetailsDaoImpl extends 
GenericDaoBase<StoragePoolDetailV
        
        return detailsMap;
     }
+
+    @Override
+    public StoragePoolDetailVO findDetail(long poolId, String name) {
+        SearchCriteria<StoragePoolDetailVO> sc = PoolSearch.create();
+        sc.setParameters("pool", poolId);
+        sc.setParameters("name", name);
+
+        return findOneIncludingRemovedBy(sc);
+    }
 }

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
----------------------------------------------------------------------
diff --git a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java 
b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
index 9443815..6cda294 100755
--- a/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
+++ b/server/test/com/cloud/vpc/MockConfigurationManagerImpl.java
@@ -25,6 +25,7 @@ import javax.inject.Inject;
 import javax.naming.ConfigurationException;
 import javax.naming.NamingException;
 
+import com.cloud.configuration.ConfigurationVO;
 import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
 import org.apache.cloudstack.api.command.admin.ldap.LDAPConfigCmd;
 import org.apache.cloudstack.api.command.admin.ldap.LDAPRemoveCmd;
@@ -425,9 +426,9 @@ public class MockConfigurationManagerImpl extends 
ManagerBase implements Configu
      * @see 
com.cloud.configuration.ConfigurationManager#updateConfiguration(long, 
java.lang.String, java.lang.String, java.lang.String)
      */
     @Override
-    public void updateConfiguration(long userId, String name, String category, 
String value) {
+    public void updateConfiguration(long userId, String name, String category, 
String value, String scope, Long resourceId) {
         // TODO Auto-generated method stub
-        
+
     }
 
     /* (non-Javadoc)

http://git-wip-us.apache.org/repos/asf/cloudstack/blob/eae22d2f/test/integration/smoke/test_UpdateCfg.py
----------------------------------------------------------------------
diff --git a/test/integration/smoke/test_UpdateCfg.py 
b/test/integration/smoke/test_UpdateCfg.py
new file mode 100644
index 0000000..be501b9
--- /dev/null
+++ b/test/integration/smoke/test_UpdateCfg.py
@@ -0,0 +1,85 @@
+# 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.
+""" P1 tests for updating the granular Configuration parameter with scope and 
resource id provided.
+"""
+#Import Local Modules
+import marvin
+from marvin.cloudstackTestCase import *
+from marvin.cloudstackAPI import *
+from marvin.remoteSSHClient import remoteSSHClient
+from marvin.integration.lib.utils import *
+from marvin.integration.lib.base import *
+from marvin.integration.lib.common import *
+from nose.plugins.attrib import attr
+#Import System modules
+import unittest
+import hashlib
+import random
+
+class TestUpdateConfigWithScope(cloudstackTestCase):
+    """
+    This test updates the value of a configuration parameter
+    which is at zone level(scope)
+    """
+    def setUp(self):
+        """
+        CloudStack internally saves its passwords in md5 form and that is how 
we
+        specify it in the API. Python's hashlib library helps us to quickly 
hash
+        strings as follows
+        """
+        mdf = hashlib.md5()
+        mdf.update('password')
+        mdf_pass = mdf.hexdigest()
+
+        self.apiClient = self.testClient.getApiClient() #Get ourselves an API 
client
+
+
+
+    def test_UpdateConfigParamWithScope(self):
+
+        updateConfigurationCmd = updateConfiguration.updateConfigurationCmd()
+        updateConfigurationCmd.name = "use.external.dns"
+        updateConfigurationCmd.value = "true"
+        updateConfigurationCmd.scope = "zone"
+        updateConfigurationCmd.id = 1
+
+        updateConfigurationResponse = 
self.apiClient.updateConfiguration(updateConfigurationCmd)
+        self.debug("updated the parameter %s with value 
%s"%(updateConfigurationResponse.name, updateConfigurationResponse.value))
+
+        listConfigurationsCmd = listConfigurations.listConfigurationsCmd()
+        listConfigurationsCmd.cfgName = updateConfigurationResponse.name
+        listConfigurationsCmd.scope = "zone"
+        listConfigurationsCmd.id = 1
+        listConfigurationsResponse = 
self.apiClient.listConfigurations(listConfigurationsCmd)
+
+        self.assertNotEqual(len(listConfigurationsResponse), 0, "Check if the 
list API \
+                            returns a non-empty response")
+
+        configParam = listConfigurationsResponse[0]
+
+        self.assertEqual(configParam.value, updateConfigurationResponse.value, 
"Check if the update API returned \
+                         is the same as the one we got in the list API")
+
+
+    def tearDown(self):
+
+        updateConfigurationCmd = updateConfiguration.updateConfigurationCmd()
+        updateConfigurationCmd.name = "use.external.dns"
+        updateConfigurationCmd.value = "false"
+        updateConfigurationCmd.scope = "zone"
+        updateConfigurationCmd.id = 1
+        self.apiClient.updateConfiguration(updateConfigurationCmd)

Reply via email to