chore: linting and basic unit tests
This commit is contained in:
parent
82f0ae24ef
commit
6a5b430597
137
test_wildfly.py
Normal file
137
test_wildfly.py
Normal file
@ -0,0 +1,137 @@
|
||||
'''
|
||||
Unit tests for wildfly module
|
||||
'''
|
||||
|
||||
import unittest
|
||||
from six import string_types
|
||||
from wildfly import WildflyPath, format_attr, config_query, wildfly_batch
|
||||
|
||||
class TestWildflyPath(unittest.TestCase):
|
||||
'''
|
||||
Tests for WildflyPath class.
|
||||
'''
|
||||
|
||||
def setUp(self):
|
||||
test_input = r'''
|
||||
/subsystem=undertow/server=default-server/host=default-host
|
||||
/location=\/myapp\/multimedia
|
||||
'''
|
||||
self.instance = WildflyPath(test_input)
|
||||
|
||||
def test_wildfly_path_str(self):
|
||||
self.assertEqual(
|
||||
str(self.instance),
|
||||
r'/subsystem=undertow/server=default-server/host=default-host'
|
||||
r'/location=\/myapp\/multimedia'
|
||||
)
|
||||
|
||||
def test_wildfly_path_len(self):
|
||||
self.assertEqual(len(self.instance), 8)
|
||||
|
||||
def test_wildfly_path_lpop(self):
|
||||
self.instance.lpop()
|
||||
self.instance.lpop()
|
||||
self.assertEqual(
|
||||
str(self.instance),
|
||||
r'/server=default-server/host=default-host'
|
||||
r'/location=\/myapp\/multimedia'
|
||||
)
|
||||
|
||||
|
||||
class TestFormatAttr(unittest.TestCase):
|
||||
'''
|
||||
Tests for format_attr function.
|
||||
'''
|
||||
|
||||
def test_format_attr_return_type(self):
|
||||
for input_ in (None, True, 1234, 1234.5, ['123',243],
|
||||
'hello', {'a': 123}):
|
||||
self.assertIsInstance(format_attr(input_), string_types)
|
||||
|
||||
def test_format_attr_true(self):
|
||||
self.assertEqual(format_attr(True), 'True')
|
||||
|
||||
def test_format_attr_false(self):
|
||||
self.assertEqual(format_attr(False), 'False')
|
||||
|
||||
def test_format_attr_none(self):
|
||||
self.assertEqual(format_attr(None), 'undefined')
|
||||
|
||||
def test_format_attr_float(self):
|
||||
self.assertEqual(format_attr(1234.5), '1234.500000')
|
||||
|
||||
def test_format_attr_int(self):
|
||||
self.assertEqual(format_attr(1234), '1234')
|
||||
|
||||
def test_format_attr_bigint(self):
|
||||
self.assertEqual(format_attr(1e10), '10000000000.000000')
|
||||
|
||||
def test_format_attr_string(self):
|
||||
self.assertEqual(format_attr('hello'), '"hello"')
|
||||
|
||||
def test_format_attr_stripquotes(self):
|
||||
self.assertEqual(format_attr('"hello"'), '"hello"')
|
||||
|
||||
|
||||
class TestConfigQueryFunction(unittest.TestCase):
|
||||
'''
|
||||
Tests for config_query function.
|
||||
'''
|
||||
|
||||
def setUp(self):
|
||||
self.config0 = {'core-service': {'management': {'security-realm': {
|
||||
'ManagementRealm': {'plug-in': None, 'server-identity': None}}}}}
|
||||
self.path0 = ('/core-service=management/security-realm=ManagementRealm'
|
||||
'/server-identity=ssl')
|
||||
self.config1 = {'core-service': {'management': {'security-realm': {
|
||||
'ManagementRealm': {'server-identity': {'ssl': {
|
||||
'alias': 'wildfly',
|
||||
'key-password': 'changeit',
|
||||
'keystore-password': 'changeit',
|
||||
'keystore-path': 'server-admin.keystore',
|
||||
'keystore-relative-to': 'jboss.server.config.dir',
|
||||
}}}}}}}
|
||||
|
||||
def test_config_query_none(self):
|
||||
self.assertEqual(config_query(self.config0, self.path0), None)
|
||||
|
||||
|
||||
class TestBatch(unittest.TestCase):
|
||||
'''
|
||||
Tests for wildfly_batch function.
|
||||
'''
|
||||
|
||||
def setUp(self):
|
||||
self.config0 = {'core-service': {'management': {'security-realm': {
|
||||
'ManagementRealm': {'plug-in': None, 'server-identity': None}}}}}
|
||||
self.path0 = ('/core-service=management/security-realm=ManagementRealm'
|
||||
'/server-identity=ssl')
|
||||
self.attrs0 = {
|
||||
'alias': 'wildfly',
|
||||
'key-password': 'changeit',
|
||||
'keystore-password': 'changeit',
|
||||
'keystore-path': 'server-admin.keystore',
|
||||
'keystore-relative-to': 'jboss.server.config.dir',
|
||||
}
|
||||
self.batch0 = '''\
|
||||
/core-service=management/security-realm=ManagementRealm\
|
||||
/server-identity=ssl:add(alias="wildfly",key-password="changeit",\
|
||||
keystore-password="changeit",keystore-path="server-admin.keystore",\
|
||||
keystore-relative-to="jboss.server.config.dir")
|
||||
'''
|
||||
self.config1 = {'core-service': {'management': {'security-realm': {
|
||||
'ManagementRealm': {'plug-in': None, 'server-identity': {'ssl': {
|
||||
'alias': 'wildfly',
|
||||
'key-password': 'changeit',
|
||||
'keystore-password': 'changeit',
|
||||
'keystore-path': 'server-admin.keystore',
|
||||
'keystore-relative-to': 'jboss.server.config.dir',
|
||||
}}}}}}}
|
||||
|
||||
def test_batch_add_node(self):
|
||||
self.assertEqual(wildfly_batch(self.config0, self.path0, self.attrs0,
|
||||
wrap=False), self.batch0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
unittest.main()
|
102
wildfly.py
102
wildfly.py
@ -6,23 +6,30 @@ Ansible action plugin for configuring Wildfly
|
||||
'''
|
||||
|
||||
from __future__ import (absolute_import, division, print_function)
|
||||
__metaclass__ = type
|
||||
|
||||
import re
|
||||
import json
|
||||
|
||||
from ansible.plugins.action import ActionBase
|
||||
from ansible.utils.display import Display
|
||||
from ansible.utils.vars import merge_hash
|
||||
display = Display()
|
||||
|
||||
import json
|
||||
import re
|
||||
from six import string_types
|
||||
|
||||
|
||||
display = Display()
|
||||
|
||||
|
||||
class WildflyError(Exception):
|
||||
pass
|
||||
'''
|
||||
Basic error class for this module.
|
||||
'''
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
'''
|
||||
The action module.
|
||||
'''
|
||||
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
super(ActionModule, self).run(tmp, task_vars)
|
||||
@ -36,7 +43,6 @@ class ActionModule(ActionBase):
|
||||
cli_command, config, dry_run = read_args(task_args, check_mode)
|
||||
|
||||
# read current config
|
||||
# if not self.prev:
|
||||
cur_result = self.execute_command(
|
||||
'{} --output-json --command="/:read-resource(recursive)"'.format(
|
||||
cli_command),
|
||||
@ -47,10 +53,10 @@ class ActionModule(ActionBase):
|
||||
|
||||
try:
|
||||
cur_state = json.loads(cur_result.get('stdout')).get('result')
|
||||
except Exception as e:
|
||||
except Exception as ex:
|
||||
return merge_hash(cur_result, dict(
|
||||
failed=True,
|
||||
msg='Error parsing JSON from Wildfly CLI: {}'.format(str(e))
|
||||
msg='Error parsing JSON from Wildfly CLI: {}'.format(str(ex))
|
||||
))
|
||||
|
||||
# generate batch script
|
||||
@ -61,25 +67,27 @@ class ActionModule(ActionBase):
|
||||
cur_state,
|
||||
item.get('root', '/'),
|
||||
item.get('config', {}),
|
||||
item.get('state', 'present')
|
||||
, False)
|
||||
item.get('state', 'present'),
|
||||
False)
|
||||
|
||||
except Exception as e:
|
||||
except Exception as ex:
|
||||
return merge_hash(cur_result, dict(
|
||||
failed=True,
|
||||
msg='Error while generating Wildfly batch: {}'.format(str(e)),
|
||||
msg='Error while generating Wildfly batch: {}'.format(
|
||||
str(ex)),
|
||||
stdout=None,
|
||||
stdout_lines=[],
|
||||
config_item=item,
|
||||
batch_script=batch_script
|
||||
))
|
||||
|
||||
result = dict(changed=False,batch_script=batch_script)
|
||||
result = dict(changed=False, batch_script=batch_script,
|
||||
previous_state=cur_state)
|
||||
|
||||
# apply changes
|
||||
if batch_script:
|
||||
batch_script = 'batch\n{}run-batch\n'.format(batch_script)
|
||||
result = dict(changed=True,batch_script=batch_script)
|
||||
result = merge_hash(result, dict(changed=True))
|
||||
|
||||
if not dry_run:
|
||||
self.execute_command(
|
||||
@ -90,7 +98,6 @@ class ActionModule(ActionBase):
|
||||
|
||||
return result
|
||||
|
||||
|
||||
def execute_command(self, command, stdin=None, check_mode_unsafe=True):
|
||||
'''
|
||||
Execute command module and return result
|
||||
@ -107,7 +114,6 @@ class ActionModule(ActionBase):
|
||||
)
|
||||
|
||||
|
||||
|
||||
def read_args(task_args, check_mode):
|
||||
'''
|
||||
Read and validate invocation arguments
|
||||
@ -125,9 +131,9 @@ def read_args(task_args, check_mode):
|
||||
'Please use "config" argument instead.')
|
||||
|
||||
# validate config argument
|
||||
if type(config) is list:
|
||||
if isinstance(config, list):
|
||||
pass
|
||||
elif type(config) is dict:
|
||||
elif isinstance(config, dict):
|
||||
config = [dict(
|
||||
config=config,
|
||||
root=task_args.get('root'),
|
||||
@ -142,7 +148,6 @@ def read_args(task_args, check_mode):
|
||||
return cli_command, config, dry_run
|
||||
|
||||
|
||||
|
||||
def wildfly_batch(prev, root, attrs, state='present', wrap=True):
|
||||
'''
|
||||
Generate Wildfly batch to assert state of configuration item under
|
||||
@ -166,7 +171,7 @@ def wildfly_batch(prev, root, attrs, state='present', wrap=True):
|
||||
output = ''
|
||||
|
||||
# check current config
|
||||
cur = wildfly_config_query(prev, root)
|
||||
cur = config_query(prev, root)
|
||||
|
||||
display.v("current config: {}".format(cur))
|
||||
|
||||
@ -174,7 +179,7 @@ def wildfly_batch(prev, root, attrs, state='present', wrap=True):
|
||||
|
||||
if cur:
|
||||
# node exists, add missing attrs
|
||||
for k in attrs:
|
||||
for k in sorted(attrs):
|
||||
if k not in cur or cur[k] != attrs[k]:
|
||||
output = '{}{}:write-attribute(name={},value={})\n'.format(
|
||||
output, root, k, format_attr(attrs[k]))
|
||||
@ -185,21 +190,22 @@ def wildfly_batch(prev, root, attrs, state='present', wrap=True):
|
||||
# node doesn't exist, add it
|
||||
output = '{}{}:add({})\n'.format(
|
||||
output, root,
|
||||
','.join(['{}={}'.format(k,format_attr(attrs[k])) for k in attrs])
|
||||
','.join(['{}={}'.format(
|
||||
k, format_attr(attrs[k])) for k in sorted(attrs)])
|
||||
)
|
||||
wildfly_config_add_node(prev, root, attrs)
|
||||
# config_add_node(prev, root, attrs)
|
||||
|
||||
if state.lower() == 'absent' and cur:
|
||||
# remove existing node
|
||||
output = '{}{}:remove()\n'.format(output, root)
|
||||
|
||||
if len(output) and wrap:
|
||||
if len(output) > 0 and wrap:
|
||||
output = 'batch\n{}\nrun-batch\n'.format(output)
|
||||
|
||||
return output
|
||||
|
||||
|
||||
def wildfly_config_query(config, path):
|
||||
def config_query(config, path):
|
||||
'''
|
||||
Given Wildfly configuration as a dict, follow
|
||||
requested path and return corresponding entry.
|
||||
@ -207,39 +213,18 @@ def wildfly_config_query(config, path):
|
||||
'''
|
||||
path = WildflyPath(path)
|
||||
ptr = config
|
||||
while len(path):
|
||||
while len(path) > 0:
|
||||
try:
|
||||
qry = path.lpop()
|
||||
ptr = ptr[qry]
|
||||
except (KeyError, TypeError):
|
||||
# either ptr is none (Type), or ptr[qry] not found (Key)
|
||||
return None
|
||||
except Exception as e:
|
||||
raise WildflyError( "config query error: {}".format(str(e)))
|
||||
except Exception as ex:
|
||||
raise WildflyError("config query error: {}".format(str(ex)))
|
||||
return ptr
|
||||
|
||||
|
||||
def wildfly_config_add_node(config, path, node):
|
||||
'''
|
||||
Given Wildfly configuration as a dict, follow
|
||||
requested path and add given node.
|
||||
|
||||
'''
|
||||
path = WildflyPath(path)
|
||||
ptr = config
|
||||
while len(path):
|
||||
try:
|
||||
qry = path.lpop()
|
||||
ptr = ptr[qry]
|
||||
except TypeError:
|
||||
ptr = dict()
|
||||
except KeyError:
|
||||
ptr[qry] = dict()
|
||||
except Exception as e:
|
||||
raise Exception( "unknown error: {}".format(str(e)))
|
||||
ptr = merge_hash(ptr,node)
|
||||
|
||||
|
||||
def format_attr(attr):
|
||||
'''
|
||||
Return valid text representation for attribute as understood by
|
||||
@ -251,18 +236,26 @@ def format_attr(attr):
|
||||
if attr is None:
|
||||
return 'undefined'
|
||||
|
||||
if isinstance(attr, (float)):
|
||||
return '{:f}'.format(attr)
|
||||
|
||||
if isinstance(attr, (int, bool)):
|
||||
return str(attr)
|
||||
|
||||
# list => '[ format(item), ... ]'
|
||||
if isinstance(attr,list):
|
||||
if isinstance(attr, (list,tuple)):
|
||||
return '[' + ', '.join(
|
||||
[ '{}'.format( 'undefined' if k_ is None else format_attr(k_)) for k_ in attr ]
|
||||
['{}'.format(
|
||||
'undefined' if k_ is None
|
||||
else format_attr(k_)) for k_ in attr]
|
||||
) + ']'
|
||||
|
||||
# dict => '{ "key" => format(value), ... }'
|
||||
if isinstance(attr, dict):
|
||||
return '{' + ', '.join(
|
||||
['"{}" => {}'.format(
|
||||
k_,
|
||||
'undefined' if attr[k_] is None else format_attr(attr[k_])
|
||||
k_, 'undefined' if attr[k_] is None
|
||||
else format_attr(attr[k_])
|
||||
) for k_ in list(attr.keys())]
|
||||
) + '}'
|
||||
|
||||
@ -306,6 +299,9 @@ class WildflyPath:
|
||||
return sum([1 for i in self.parts if i not in ('', '=', '/')])
|
||||
|
||||
def lpop(self):
|
||||
'''
|
||||
remove first path component and return it
|
||||
'''
|
||||
ret = self.parts.pop(0)
|
||||
while ret in ('', '/', '='):
|
||||
ret = self.parts.pop(0)
|
||||
|
Loading…
x
Reference in New Issue
Block a user