You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by sr...@apache.org on 2014/10/25 00:35:20 UTC
git commit: AMBARI-7966. delete and set action does not work for
configs.sh script
Repository: ambari
Updated Branches:
refs/heads/branch-1.7.0 8d3febe2e -> 367b90430
AMBARI-7966. delete and set action does not work for configs.sh script
Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/367b9043
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/367b9043
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/367b9043
Branch: refs/heads/branch-1.7.0
Commit: 367b90430ac141f04af48076bef2e598c69450e6
Parents: 8d3febe
Author: Srimanth Gunturi <sg...@hortonworks.com>
Authored: Fri Oct 24 15:15:49 2014 -0700
Committer: Srimanth Gunturi <sg...@hortonworks.com>
Committed: Fri Oct 24 15:15:49 2014 -0700
----------------------------------------------------------------------
.../src/main/resources/scripts/configs.py | 254 +++++++++++++++++++
.../src/main/resources/scripts/configs.sh | 111 +++++---
ambari-server/src/test/python/TestConfigs.py | 186 ++++++++++++++
3 files changed, 509 insertions(+), 42 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ambari/blob/367b9043/ambari-server/src/main/resources/scripts/configs.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/scripts/configs.py b/ambari-server/src/main/resources/scripts/configs.py
new file mode 100644
index 0000000..b524461
--- /dev/null
+++ b/ambari-server/src/main/resources/scripts/configs.py
@@ -0,0 +1,254 @@
+#!/usr/bin/env python
+
+'''
+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.
+'''
+
+import sys
+import urllib2
+import time
+import json
+import base64
+
+HTTP_PROTOCOL = 'http'
+HTTPS_PROTOCOL = 'https'
+
+SET_ACTION = 'set'
+GET_ACTION = 'get'
+DELETE_ACTION = 'delete'
+
+GET_REQUEST_TYPE = 'GET'
+PUT_REQUEST_TYPE = 'PUT'
+
+# JSON Keywords
+PROPERTIES = 'properties'
+ATTRIBUTES = 'properties_attributes'
+CLUSTERS = 'Clusters'
+DESIRED_CONFIGS = 'desired_configs'
+TYPE = 'type'
+TAG = 'tag'
+ITEMS = 'items'
+TAG_PREFIX = 'version'
+
+CLUSTERS_URL = '/api/v1/clusters/{0}'
+DESIRED_CONFIGS_URL = CLUSTERS_URL + '?fields=Clusters/desired_configs'
+CONFIGURATION_URL = CLUSTERS_URL + '/configurations?type={1}&tag={2}'
+
+FILE_FORMAT = \
+"""
+"properties": {
+ "key1": "value1"
+ "key2": "value2"
+},
+"properties_attributes": {
+ "attribute": {
+ "key1": "value1"
+ "key2": "value2"
+ }
+}
+"""
+
+class UsageException(Exception):
+ pass
+
+def api_accessor(host, login, password, protocol, port):
+ def do_request(api_url, request_type=GET_REQUEST_TYPE, request_body=''):
+ try:
+ url = '{0}://{1}:{2}{3}'.format(protocol, host, port, api_url)
+ admin_auth = base64.encodestring('%s:%s' % (login, password)).replace('\n', '')
+ request = urllib2.Request(url)
+ request.add_header('Authorization', 'Basic %s' % admin_auth)
+ request.add_header('X-Requested-By', 'ambari')
+ request.add_data(request_body)
+ request.get_method = lambda: request_type
+ response = urllib2.urlopen(request)
+ response_body = response.read()
+ except Exception as exc:
+ raise Exception('Problem with accessing api. Reason: {0}'.format(exc))
+ return response_body
+ return do_request
+
+def get_config_tag(cluster, config_type, accessor):
+ response = accessor(DESIRED_CONFIGS_URL.format(cluster))
+ try:
+ desired_tags = json.loads(response)
+ current_config_tag = desired_tags[CLUSTERS][DESIRED_CONFIGS][config_type][TAG]
+ except Exception as exc:
+ raise Exception('"{0}" not found in server response. Response:\n{1}'.format(config_type, response))
+ return current_config_tag
+
+def create_new_desired_config(cluster, config_type, properties, attributes, accessor):
+ new_tag = TAG_PREFIX + str(int(time.time() * 1000000))
+ new_config = {
+ CLUSTERS: {
+ DESIRED_CONFIGS: {
+ TYPE: config_type,
+ TAG: new_tag,
+ PROPERTIES: properties
+ }
+ }
+ }
+ if len(attributes.keys()) > 0:
+ new_config[CLUSTERS][DESIRED_CONFIGS][ATTRIBUTES] = attributes
+ request_body = json.dumps(new_config)
+ new_file = 'doSet_{0}.json'.format(new_tag)
+ print '### PUTting json into: {0}'.format(new_file)
+ output_to_file(new_file)(new_config)
+ accessor(CLUSTERS_URL.format(cluster), PUT_REQUEST_TYPE, request_body)
+ print '### NEW Site:{0}, Tag:{1}'.format(config_type, new_tag)
+
+def get_current_config(cluster, config_type, accessor):
+ config_tag = get_config_tag(cluster, config_type, accessor)
+ print "### on (Site:{0}, Tag:{1})".format(config_type, config_tag)
+ response = accessor(CONFIGURATION_URL.format(cluster, config_type, config_tag))
+ config_by_tag = json.loads(response)
+ current_config = config_by_tag[ITEMS][0]
+ return current_config[PROPERTIES], current_config.get(ATTRIBUTES, {})
+
+def update_config(cluster, config_type, config_updater, accessor):
+ properties, attributes = config_updater(cluster, config_type, accessor)
+ create_new_desired_config(cluster, config_type, properties, attributes, accessor)
+
+def update_specific_property(config_name, config_value):
+ def update(cluster, config_type, accessor):
+ properties, attributes = get_current_config(cluster, config_type, accessor)
+ properties[config_name] = config_value
+ return properties, attributes
+ return update
+
+def update_from_file(config_file):
+ def update(cluster, config_type, accessor):
+ try:
+ with open(config_file) as in_file:
+ file_content = in_file.read()
+ except Exception as e:
+ raise Exception('Cannot find file "{0}" to PUT'.format(config_file))
+ try:
+ file_properties = json.loads('{' + file_content + '}')
+ except Exception as e:
+ raise Exception('File "{0}" should be in the following JSON format ("properties_attributes" is optional):\n{1}'.format(config_file, FILE_FORMAT))
+ new_properties = file_properties.get(PROPERTIES, {})
+ new_attributes = file_properties.get(ATTRIBUTES, {})
+ print '### PUTting file: "{0}"'.format(config_file)
+ return new_properties, new_attributes
+ return update
+
+def delete_specific_property(config_name):
+ def update(cluster, config_type, accessor):
+ properties, attributes = get_current_config(cluster, config_type, accessor)
+ properties.pop(config_name, None)
+ for attribute_values in attributes.values():
+ attribute_values.pop(config_name, None)
+ return properties, attributes
+ return update
+
+def format_json(dictionary, tab_level=0):
+ output = ''
+ tab = ' ' * 2 * tab_level
+ for key, value in dictionary.iteritems():
+ output += ',\n{0}"{1}": '.format(tab, key)
+ if isinstance(value, dict):
+ output += '{\n' + format_json(value, tab_level + 1) + tab + '}'
+ else:
+ output += '"{0}"'.format(value)
+ output += '\n'
+ return output[2:]
+
+def output_to_file(filename):
+ def output(config):
+ with open(filename, 'w') as out_file:
+ out_file.write(format_json(config))
+ return output
+
+def output_to_console(config):
+ print format_json(config)
+
+def get_config(cluster, config_type, accessor, output):
+ properties, attributes = get_current_config(cluster, config_type, accessor)
+ config = {PROPERTIES: properties}
+ if len(attributes.keys()) > 0:
+ config[ATTRIBUTES] = attributes
+ output(config)
+
+def set_properties(cluster, config_type, args, accessor):
+ print '### Performing "set" content:'
+ if len(args) == 0:
+ raise UsageException("Not enough arguments. Expected config key and value or filename.")
+
+ if len(args) == 1:
+ config_file = args[0]
+ updater = update_from_file(config_file)
+ print '### from file "{0}"'.format(config_file)
+ else:
+ config_name = args[0]
+ config_value = args[1]
+ updater = update_specific_property(config_name, config_value)
+ print '### new property - "{0}":"{1}"'.format(config_name, config_value)
+ update_config(cluster, config_type, updater, accessor)
+
+def delete_properties(cluster, config_type, args, accessor):
+ print '### Performing "delete":'
+ if len(args) == 0:
+ raise UsageException("Not enough arguments. Expected config key.")
+
+ config_name = args[0]
+ print '### on property "{0}"'.format(config_name)
+ update_config(cluster, config_type, delete_specific_property(config_name), accessor)
+
+def get_properties(cluster, config_type, args, accessor):
+ print '### Performing "get" content:'
+ if len(args) > 0:
+ filename = args[0]
+ output = output_to_file(filename)
+ print '### to file "{0}"'.format(filename)
+ else:
+ output = output_to_console
+ get_config(cluster, config_type, accessor, output)
+
+def main():
+ if len(sys.argv) < 9:
+ raise UsageException('Not enough arguments.')
+ args = sys.argv[1:]
+ user = args[0]
+ password = args[1]
+ port = args[2]
+ protocol = args[3]
+ action = args[4]
+ host = args[5]
+ cluster = args[6]
+ config_type = args[7]
+ action_args = args[8:]
+ accessor = api_accessor(host, user, password, protocol, port)
+ if action == SET_ACTION:
+ set_properties(cluster, config_type, action_args, accessor)
+ elif action == GET_ACTION:
+ get_properties(cluster, config_type, action_args, accessor)
+ elif action == DELETE_ACTION:
+ delete_properties(cluster, config_type, action_args, accessor)
+ else:
+ raise UsageException('Action "{0}" is not supported. Supported actions: "get", "set", "delete".'.format(action))
+
+if __name__ == "__main__":
+ try:
+ main()
+ except UsageException as usage_exc:
+ print '[ERROR] {0}'.format(usage_exc)
+ sys.exit(2)
+ except Exception as exc:
+ for line in str(exc).split('\n'):
+ print '[ERROR] {0}'.format(line)
+ sys.exit(1)
http://git-wip-us.apache.org/repos/asf/ambari/blob/367b9043/ambari-server/src/main/resources/scripts/configs.sh
----------------------------------------------------------------------
diff --git a/ambari-server/src/main/resources/scripts/configs.sh b/ambari-server/src/main/resources/scripts/configs.sh
index 57fd2aa..0c5cbc0 100755
--- a/ambari-server/src/main/resources/scripts/configs.sh
+++ b/ambari-server/src/main/resources/scripts/configs.sh
@@ -115,45 +115,60 @@ doConfigUpdate () {
MODE=$1
currentSiteTag
echo "########## Performing '$MODE' $CONFIGKEY:$CONFIGVALUE on (Site:$SITE, Tag:$SITETAG)";
- propertiesStarted=0;
+ propertiesStarted=0
+ attributesStarted=0
+ currentLevel=0
curl -k -s -u $USERID:$PASSWD "$AMBARIURL/api/v1/clusters/$CLUSTER/configurations?type=$SITE&tag=$SITETAG" | while read -r line; do
- ## echo ">>> $line";
- if [ "$propertiesStarted" -eq 0 -a "`echo $line | grep "\"properties\""`" ]; then
- propertiesStarted=1
- fi;
- if [ "$propertiesStarted" -eq 1 ]; then
- if [ "$line" == "}" ]; then
+ if [ "$propertiesStarted" -eq 0 -a "$attributesStarted" -eq 0 ]; then
+ if [ "$line" = "\"properties_attributes\" : {" ]; then
+ attributesStarted=$currentLevel
+ elif [ "$line" = "\"properties\" : {" ]; then
+ propertiesStarted=$currentLevel
+ fi
+ fi
+ if [ "$propertiesStarted" -gt 0 ]; then
+ if [ "`echo $line | grep -E "},?$"`" ]; then
## Properties ended
## Add property
+ # Remove the last ,
+ propLen=${#newProperties}
+ lastChar=${newProperties:$propLen-1:1}
+ if [ "$lastChar" == "," ]; then
+ newProperties=${newProperties:0:$propLen-1}
+ fi
if [ "$MODE" == "set" ]; then
- newProperties="$newProperties, \"$CONFIGKEY\" : \"$CONFIGVALUE\" ";
- elif [ "$MODE" == "delete" ]; then
- # Remove the last ,
- propLen=${#newProperties}
- lastChar=${newProperties:$propLen-1:1}
- if [ "$lastChar" == "," ]; then
- newProperties=${newProperties:0:$propLen-1}
- fi
+ newProperties="$newProperties, \"$CONFIGKEY\" : \"$CONFIGVALUE\" "
fi
newProperties=$newProperties$line
- propertiesStarted=0;
-
- newTag=`date "+%s%N"`
- newTag="version${newTag}"
- finalJson="{ \"Clusters\": { \"desired_config\": {\"type\": \"$SITE\", \"tag\":\"$newTag\", $newProperties}}}"
- newFile="doSet_$newTag.json"
- echo "########## PUTting json into: $newFile"
- echo $finalJson > $newFile
- curl -k -u $USERID:$PASSWD -X PUT -H "X-Requested-By: ambari" "$AMBARIURL/api/v1/clusters/$CLUSTER" --data @$newFile
- currentSiteTag
- echo "########## NEW Site:$SITE, Tag:$SITETAG";
- elif [ "`echo $line | grep "\"$CONFIGKEY\""`" ]; then
+ propertiesStarted=0
+ elif [ "`echo $line | grep "\\\"$CONFIGKEY\\\""`" ]; then
echo "########## Config found. Skipping origin value"
else
newProperties=$newProperties$line
fi
+ elif [ "$attributesStarted" -gt 0 ]; then
+ newProperties=$newProperties$line
fi
- done;
+ if [ "`echo $line | grep -E "{$"`" ]; then
+ currentLevel=$((currentLevel+1))
+ elif [ "`echo $line | grep -E "},?$"`" ]; then
+ currentLevel=$((currentLevel-1))
+ if [ "$currentLevel" == 1 ]; then
+ newTag=`date "+%s%N"`
+ newTag="version${newTag}"
+ finalJson="{ \"Clusters\": { \"desired_config\": {\"type\": \"$SITE\", \"tag\":\"$newTag\", $newProperties}}}"
+ newFile="doSet_$newTag.json"
+ echo "########## PUTting json into: $newFile"
+ echo $finalJson > $newFile
+ curl -k -u $USERID:$PASSWD -X PUT -H "X-Requested-By: ambari" "$AMBARIURL/api/v1/clusters/$CLUSTER" --data @$newFile
+ currentSiteTag
+ echo "########## NEW Site:$SITE, Tag:$SITETAG";
+ fi
+ fi
+ if [ "$attributesStarted" -eq "$currentLevel" ]; then
+ attributesStarted=0
+ fi
+ done
}
#############################################
@@ -163,22 +178,28 @@ doConfigUpdate () {
doConfigFileUpdate () {
FILENAME=$1
if [ -f $FILENAME ]; then
- if [ "1" == "`grep -n \"\"properties\"\" $FILENAME | cut -d : -f 1`" ]; then
+ if [ "1" == "`grep -n \"\\\"properties\\\"\" $FILENAME | cut -d : -f 1`" ]; then
newTag=`date "+%s%N"`
newTag="version${newTag}"
newProperties=`cat $FILENAME`;
finalJson="{ \"Clusters\": { \"desired_config\": {\"type\": \"$SITE\", \"tag\":\"$newTag\", $newProperties}}}"
- newFile="$FILENAME"
+ newFile="doSet_$newTag.json"
echo $finalJson>$newFile
echo "########## PUTting file:\"$FILENAME\" into config(type:\"$SITE\", tag:$newTag) via $newFile"
curl -k -u $USERID:$PASSWD -X PUT -H "X-Requested-By: ambari" "$AMBARIURL/api/v1/clusters/$CLUSTER" --data @$newFile
currentSiteTag
echo "########## NEW Site:$SITE, Tag:$SITETAG";
else
- echo "[ERROR] File \"$FILENAME\" should be in the following JSON format:";
+ echo "[ERROR] File \"$FILENAME\" should be in the following JSON format (\"properties_attributes\" is optional):";
echo "[ERROR] \"properties\": {";
echo "[ERROR] \"key1\": \"value1\",";
echo "[ERROR] \"key2\": \"value2\",";
+ echo "[ERROR] },";
+ echo "[ERROR] \"properties_attributes\": {";
+ echo "[ERROR] \"final\": {";
+ echo "[ERROR] \"key1\": \"value1\",";
+ echo "[ERROR] \"key2\": \"value2\",";
+ echo "[ERROR] }";
echo "[ERROR] }";
exit 1;
fi
@@ -196,28 +217,34 @@ doConfigFileUpdate () {
doGet () {
FILENAME=$1
if [ -n $FILENAME -a -f $FILENAME ]; then
- rm -f $FILENAME;
+ rm -f $FILENAME
fi
currentSiteTag
echo "########## Performing 'GET' on (Site:$SITE, Tag:$SITETAG)";
- propertiesStarted=0;
+ propertiesStarted=0
curl -k -s -u $USERID:$PASSWD "$AMBARIURL/api/v1/clusters/$CLUSTER/configurations?type=$SITE&tag=$SITETAG" | while read -r line; do
- ## echo ">>> $line";
- if [ "$propertiesStarted" -eq 0 -a "`echo $line | grep "\"properties\""`" ]; then
- propertiesStarted=1
- fi;
- if [ "$propertiesStarted" -eq 1 ]; then
- if [ "$line" == "}" ]; then
- ## Properties ended
- propertiesStarted=0;
+ # echo ">>> $line";
+ if [ "$propertiesStarted" -eq 0 ]; then
+ if [ "`echo $line | grep "\"properties\""`" -o "`echo $line | grep "\"properties_attributes\""`" ]; then
+ propertiesStarted=$currentLevel
fi
+ fi
+ if [ "$propertiesStarted" -gt "0" ]; then
if [ -z $FILENAME ]; then
echo $line
else
echo $line >> $FILENAME
fi
fi
- done;
+ if [ "`echo $line | grep -E "{$"`" ]; then
+ currentLevel=$((currentLevel+1))
+ elif [ "`echo $line | grep -E "},?$"`" ]; then
+ currentLevel=$((currentLevel-1))
+ fi
+ if [ "$propertiesStarted" -eq "$currentLevel" ]; then
+ propertiesStarted=0
+ fi
+ done
}
case "$1" in
http://git-wip-us.apache.org/repos/asf/ambari/blob/367b9043/ambari-server/src/test/python/TestConfigs.py
----------------------------------------------------------------------
diff --git a/ambari-server/src/test/python/TestConfigs.py b/ambari-server/src/test/python/TestConfigs.py
new file mode 100644
index 0000000..cc6cb31
--- /dev/null
+++ b/ambari-server/src/test/python/TestConfigs.py
@@ -0,0 +1,186 @@
+'''
+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.
+'''
+
+import StringIO
+import imp
+import os
+import sys
+import json
+from mock.mock import patch, MagicMock
+from unittest import TestCase
+
+def get_configs():
+ test_directory = os.path.dirname(os.path.abspath(__file__))
+ configs_path = os.path.join(test_directory, '../../main/resources/scripts/configs.py')
+ with open(configs_path, 'rb') as fp:
+ return imp.load_module('configs', fp, configs_path, ('.py', 'rb', imp.PY_SOURCE))
+
+configs = get_configs()
+
+class TestConfigs(TestCase):
+ def setUp(self):
+ out = StringIO.StringIO()
+ sys.stdout = out
+
+ def tearDown(self):
+ sys.stdout = sys.__stdout__
+
+ def get_url_open_side_effect(self, response_mapping):
+ def urlopen_side_effect(request):
+ response = MagicMock()
+ request_type = request.get_method()
+ request_url = request.get_full_url()
+ if request_type in response_mapping:
+ req_type = response_mapping[request_type]
+ type_responses = req_type.get('body', None)
+ if type_responses is not None:
+ response_data = type_responses[request_url]
+ response.read.side_effect = [response_data]
+ request_check = req_type.get('request_assertion', None)
+ if request_check is not None:
+ request_body = json.loads(request.get_data())
+ request_check.get(request_url, lambda x: None)(request_body)
+ return response
+ return urlopen_side_effect
+
+ @patch.object(configs, 'output_to_file')
+ @patch('urllib2.urlopen')
+ def test_get_config_to_file(self, urlopen_method, to_file_method):
+ response_mapping = {
+ 'GET': {
+ 'body': {
+ 'http://localhost:8081/api/v1/clusters/cluster1?fields=Clusters/desired_configs' : '{"Clusters":{"desired_configs":{"hdfs-site":{"tag":"version1"}}}}',
+ 'http://localhost:8081/api/v1/clusters/cluster1/configurations?type=hdfs-site&tag=version1': '{"items":[{"properties":{"config1": "value1", "config2": "value2"}}]}'
+ }
+ }
+ }
+ def config_assertion(config):
+ self.assertEquals(config['properties'], {'config1': 'value1', 'config2': 'value2'})
+ urlopen_method.side_effect = self.get_url_open_side_effect(response_mapping)
+ to_file_method.return_value = config_assertion
+ sys.argv = ['configs.py', 'user', 'password', '8081', 'http', 'get', 'localhost', 'cluster1', 'hdfs-site', '1.conf']
+ configs.main()
+
+ @patch.object(configs, 'output_to_file')
+ @patch('urllib2.urlopen')
+ def test_update_specific_config(self, urlopen_method, to_file_method):
+ response_mapping = {
+ 'GET': {
+ 'body': {
+ 'https://localhost:8081/api/v1/clusters/cluster1?fields=Clusters/desired_configs' : '{"Clusters":{"desired_configs":{"hdfs-site":{"tag":"version1"}}}}',
+ 'https://localhost:8081/api/v1/clusters/cluster1/configurations?type=hdfs-site&tag=version1': '{"items":[{"properties":{"config1": "value1", "config2": "value2"}}]}'
+ }
+ },
+ 'PUT': {
+ 'request_assertion': {
+ 'https://localhost:8081/api/v1/clusters/cluster1':
+ lambda request_body: self.assertEquals(request_body['Clusters']['desired_configs']['properties'], {"config1": "value3", "config2": "value2"})
+ }
+ }
+ }
+ urlopen_method.side_effect = self.get_url_open_side_effect(response_mapping)
+ sys.argv = ['configs.py', 'user', 'password', '8081', 'https', 'set', 'localhost', 'cluster1', 'hdfs-site', 'config1', 'value3']
+ configs.main()
+
+ @patch.object(configs, 'output_to_file')
+ @patch('urllib2.urlopen')
+ def test_update_from_file(self, urlopen_method, to_file_method):
+ response_mapping = {
+ 'GET': {
+ 'body': {
+ 'https://localhost:8081/api/v1/clusters/cluster1?fields=Clusters/desired_configs' : '{"Clusters":{"desired_configs":{"hdfs-site":{"tag":"version1"}}}}',
+ 'https://localhost:8081/api/v1/clusters/cluster1/configurations?type=hdfs-site&tag=version1': '{"items":[{"properties":{"config1": "value1", "config2": "value2"}}]}'
+ }
+ },
+ 'PUT': {
+ 'request_assertion': {
+ 'https://localhost:8081/api/v1/clusters/cluster1':
+ lambda request_body: self.assertEquals(request_body['Clusters']['desired_configs']['properties'], {"config1": "value3", "config2": "value2"})
+ }
+ }
+ }
+ urlopen_method.side_effect = self.get_url_open_side_effect(response_mapping)
+ sys.argv = ['configs.py', 'user', 'password', '8081', 'https', 'set', 'localhost', 'cluster1', 'hdfs-site', 'config1', 'value3']
+ configs.main()
+
+ @patch.object(configs, 'output_to_file')
+ @patch('urllib2.urlopen')
+ def test_update_specific_config_with_attributes(self, urlopen_method, to_file_method):
+ def update_check(request_body):
+ self.assertEquals(request_body['Clusters']['desired_configs']['properties'], {"config1": "value4", "config2": "value2", "config3": "value3"})
+ self.assertEquals(request_body['Clusters']['desired_configs']['properties_attributes'], {"final":{"config1": "true", "config3": "true"}})
+ response_mapping = {
+ 'GET': {
+ 'body': {
+ 'https://localhost:8081/api/v1/clusters/cluster2?fields=Clusters/desired_configs' : '{"Clusters":{"desired_configs":{"hdfs-site":{"tag":"version12"}}}}',
+ 'https://localhost:8081/api/v1/clusters/cluster2/configurations?type=hdfs-site&tag=version12': '{"items":[{"properties":{"config1": "value1", "config2": "value2", "config3": "value3"}, "properties_attributes":{"final":{"config1": "true", "config3": "true"}}}]}',
+ }
+ },
+ 'PUT': {
+ 'request_assertion': {
+ 'https://localhost:8081/api/v1/clusters/cluster2': update_check
+ }
+ }
+ }
+ urlopen_method.side_effect = self.get_url_open_side_effect(response_mapping)
+ sys.argv = ['configs.py', 'user', 'password', '8081', 'https', 'set', 'localhost', 'cluster2', 'hdfs-site', 'config1', 'value4']
+ configs.main()
+
+ @patch.object(configs, 'output_to_file')
+ @patch('urllib2.urlopen')
+ def test_delete_config(self, urlopen_method, to_file_method):
+ response_mapping = {
+ 'GET': {
+ 'body': {
+ 'https://localhost:8081/api/v1/clusters/cluster1?fields=Clusters/desired_configs' : '{"Clusters":{"desired_configs":{"hdfs-site":{"tag":"version1"}}}}',
+ 'https://localhost:8081/api/v1/clusters/cluster1/configurations?type=hdfs-site&tag=version1': '{"items":[{"properties":{"config1": "value1", "config2": "value2"}}]}'
+ }
+ },
+ 'PUT': {
+ 'request_assertion': {
+ 'https://localhost:8081/api/v1/clusters/cluster1':
+ lambda request_body: self.assertEquals(request_body['Clusters']['desired_configs']['properties'], {"config2": "value2"})
+ }
+ }
+ }
+ urlopen_method.side_effect = self.get_url_open_side_effect(response_mapping)
+ sys.argv = ['configs.py', 'user', 'password', '8081', 'https', 'delete', 'localhost', 'cluster1', 'hdfs-site', 'config1']
+ configs.main()
+
+ @patch.object(configs, 'output_to_file')
+ @patch('urllib2.urlopen')
+ def test_delete_config_with_attributes(self, urlopen_method, to_file_method):
+ def delete_check(request_body):
+ self.assertEquals(request_body['Clusters']['desired_configs']['properties'], {"config2": "value2", "config3": "value3"})
+ self.assertEquals(request_body['Clusters']['desired_configs']['properties_attributes'], {"final":{"config3": "true"}})
+ response_mapping = {
+ 'GET': {
+ 'body': {
+ 'https://localhost:8081/api/v1/clusters/cluster2?fields=Clusters/desired_configs' : '{"Clusters":{"desired_configs":{"hdfs-site":{"tag":"version12"}}}}',
+ 'https://localhost:8081/api/v1/clusters/cluster2/configurations?type=hdfs-site&tag=version12': '{"items":[{"properties":{"config1": "value1", "config2": "value2", "config3": "value3"}, "properties_attributes":{"final":{"config1": "true", "config3": "true"}}}]}',
+ }
+ },
+ 'PUT': {
+ 'request_assertion': {
+ 'https://localhost:8081/api/v1/clusters/cluster2': delete_check
+ }
+ }
+ }
+ urlopen_method.side_effect = self.get_url_open_side_effect(response_mapping)
+ sys.argv = ['configs.py', 'user', 'password', '8081', 'https', 'delete', 'localhost', 'cluster2', 'hdfs-site', 'config1']
+ configs.main()