Skip to content
This repository has been archived by the owner on Jan 14, 2020. It is now read-only.

Commit

Permalink
Adding ability to read Ambari-style XML configurations
Browse files Browse the repository at this point in the history
  • Loading branch information
ZacBlanco committed Jul 11, 2016
1 parent 31c9b38 commit 1ef3364
Show file tree
Hide file tree
Showing 6 changed files with 209 additions and 6 deletions.
23 changes: 22 additions & 1 deletion docs/config.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,4 +39,25 @@ Example:

This method will search for a directory named `conf` in the local directory structure. It will return the path to this directory.

The method is used when searching for a configuration file in the `read_config` method. However, it may be used outside of the `config` module if other modules utilize the `conf` directory.
The method is used when searching for a configuration file in the `read_config` method. However, it may be used outside of the `config` module if other modules utilize the `conf` directory.


### `Ambari.get_config()`

This method retrieves and reads a all XML files stored in the `configurations` directory and returns an embedded dictionary object where all of the key-value pairs are stored in the form below:

conf = config.get_config()
conf['configurations']['FILENAME']['PROPERTY_NAME'] = PROPERTY_VALUE


i.e. if we had the file `service-config.xml` then we would access it's properties via:

conf['configurations']['service-config']


### `Ambari.read_xml_config(config_file)`

This method retrieves and reads a configuration file `configurations` directory and returns a dictionary object where all of the key-value pairs are stored

conf = config.read_xml_config(FILE_PATH)
conf['PROPERTY_NAME'] = PROPERTY_VALUE
53 changes: 49 additions & 4 deletions package/util/config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import os, ConfigParser
import os, ConfigParser, glob
import xml.etree.ElementTree as ET


# readConfig
Expand All @@ -15,7 +16,7 @@ def read_config(configFile):
path = get_conf_dir() + configFile

if not os.path.isfile(path):
raise IOError('could not find file at '+path )
raise IOError('could not find file at ' + path )

config = ConfigParser.ConfigParser()
config.read(path)
Expand All @@ -28,6 +29,51 @@ def read_config(configFile):

return params

def read_xml_config(configFile):

path = get_conf_dir() + configFile

if not os.path.isfile(path):
raise IOError('could not find file at ' + path )

config_root = ET.parse(path).getroot()
conf = {}
# Get all property elements
for prop in config_root.findall('property'):

nm = prop.find('name')
val = prop.find('value')
if not (nm == None or val == None):
conf[nm.text] = val.text

return conf

# returns a dict with dict['configurations'] containing
# another dict with a list of file names
# Under each filename is the parameters

def get_config():
conf = {}
conf['configurations'] = {}

conf_dir = get_conf_dir()
dir_entries = glob.glob(conf_dir + "*.xml" )
for conf_file in dir_entries:
if os.path.isfile(conf_file):
head, tail = os.path.split(conf_file)
try:
params = read_xml_config(tail)
except IOError:
pass
conf['configurations'][tail] = params

return conf





# Gets full path to configuration directory. Always ends with a forward slash (/)
def get_conf_dir():
dirs = [str(os.getcwd()), str(os.curdir), '../', os.path.dirname(os.path.abspath(__file__)) + '/..']

Expand All @@ -36,9 +82,8 @@ def get_conf_dir():
loc += '/'
loc += 'configuration/'
if(os.path.exists(loc)):
print('LOCATION: ' + loc)
# print('LOCATION: ' + loc)
return loc
print(str(dirs))
raise EnvironmentError('Could not find conf directory')


Expand Down
27 changes: 27 additions & 0 deletions tests/res/config/test-conf-1.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<configuration>
<property>
<name>name.prop.1</name>
<value>val1</value>
<description></description>
</property>
<property>
<name>name.prop.2</name>
<value>val2</value>
<description></description>
</property>
<property>
<name>name.prop.3</name>
<value>val3</value>
<description></description>
</property>
<property>
<name>name.prop.4</name>
<value>val4</value>
<description></description>
</property>
<property>
<name>name.prop.5</name>
<value>val5</value>
<description></description>
</property>
</configuration>
27 changes: 27 additions & 0 deletions tests/res/config/test-conf-2.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
<configuration>
<property>
<name>name.prop.1</name>
<value>val1</value>
<description></description>
</property>
<property>
<name>name.prop.2</name>
<value>val2</value>
<description></description>
</property>
<property>
<name>name.prop.3</name>
<value>val3</value>
<description></description>
</property>
<property>
<name>name.prop.4</name>
<value>val4</value>
<description></description>
</property>
<property>
<name>name.prop.5</name>
<value>val5</value>
<description></description>
</property>
</configuration>
25 changes: 25 additions & 0 deletions tests/res/config/test-conf-3.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<configuration>
<property>
<value>val1</value>
<description></description>
</property>
<property>
<name>name.prop.2</name>
<description></description>
</property>
<property>
<name>name.prop.3</name>
<value>val3</value>
<description></description>
</property>
<property>
<name>name.prop.4</name>
<value>val4</value>
<description></description>
</property>
<property>
<name>name.prop.5</name>
<value>val5</value>
<description></description>
</property>
</configuration>
60 changes: 59 additions & 1 deletion tests/test_config.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import mock, unittest, env
import mock, unittest, env, os
from package.util import config
from ConfigParser import MissingSectionHeaderError

Expand Down Expand Up @@ -50,3 +50,61 @@ def test_good_env(self, mock1, mock2):
assert 'configuration/' in cdir
except EnvironmentError as e:
assert str(e) == 'Could not find conf directory'

@mock.patch('package.util.config.get_conf_dir', return_value='')
def test_xml_tree(self, mock1):
try:
conf = config.read_xml_config('res/config/test-conf-1.xml')
print(conf.keys())
for i in range(1, 5):
assert (conf['name.prop.' + str(i)] == 'val' + str(i))
except IOError as e:
self.fail(e)

@mock.patch('package.util.config.get_conf_dir', return_value='')
def test_bad_xml_tree(self, mock1):
try:
conf = config.read_xml_config('res/config/test-conf-3.xml')
for i in range(3, 5):
assert (conf['name.prop.' + str(i)] == 'val' + str(i))
try:
v = conf['name.prop.1']
self.fail('Should have thrown KeyError')
except KeyError as e:
pass
try:
v = conf['name.prop.2']
self.fail('Should have thrown KeyError')
except KeyError as e:
pass

except IOError as e:
self.fail(e)


@mock.patch('package.util.config.get_conf_dir', return_value=os.path.dirname(os.path.abspath(__file__)) + "/res/config/")
def test_xml_tree(self, mock1):
try:
conf = config.get_config()
print(conf.keys())
print(conf['configurations'].keys())
files = ['test-conf-1.xml', 'test-conf-2.xml']
for f in files:
for i in range(1, 5):
assert (conf['configurations'][f]['name.prop.' + str(i)] == 'val' + str(i))
except IOError as e:
self.fail(e)














0 comments on commit 1ef3364

Please sign in to comment.