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()
|
118
wildfly.py
118
wildfly.py
@ -6,23 +6,30 @@ Ansible action plugin for configuring Wildfly
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
from __future__ import (absolute_import, division, print_function)
|
from __future__ import (absolute_import, division, print_function)
|
||||||
__metaclass__ = type
|
|
||||||
|
import re
|
||||||
|
import json
|
||||||
|
|
||||||
from ansible.plugins.action import ActionBase
|
from ansible.plugins.action import ActionBase
|
||||||
from ansible.utils.display import Display
|
from ansible.utils.display import Display
|
||||||
from ansible.utils.vars import merge_hash
|
from ansible.utils.vars import merge_hash
|
||||||
display = Display()
|
|
||||||
|
|
||||||
import json
|
|
||||||
import re
|
|
||||||
from six import string_types
|
from six import string_types
|
||||||
|
|
||||||
|
|
||||||
|
display = Display()
|
||||||
|
|
||||||
|
|
||||||
class WildflyError(Exception):
|
class WildflyError(Exception):
|
||||||
pass
|
'''
|
||||||
|
Basic error class for this module.
|
||||||
|
'''
|
||||||
|
|
||||||
|
|
||||||
class ActionModule(ActionBase):
|
class ActionModule(ActionBase):
|
||||||
|
'''
|
||||||
|
The action module.
|
||||||
|
'''
|
||||||
|
|
||||||
def run(self, tmp=None, task_vars=None):
|
def run(self, tmp=None, task_vars=None):
|
||||||
super(ActionModule, self).run(tmp, task_vars)
|
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)
|
cli_command, config, dry_run = read_args(task_args, check_mode)
|
||||||
|
|
||||||
# read current config
|
# read current config
|
||||||
# if not self.prev:
|
|
||||||
cur_result = self.execute_command(
|
cur_result = self.execute_command(
|
||||||
'{} --output-json --command="/:read-resource(recursive)"'.format(
|
'{} --output-json --command="/:read-resource(recursive)"'.format(
|
||||||
cli_command),
|
cli_command),
|
||||||
@ -47,10 +53,10 @@ class ActionModule(ActionBase):
|
|||||||
|
|
||||||
try:
|
try:
|
||||||
cur_state = json.loads(cur_result.get('stdout')).get('result')
|
cur_state = json.loads(cur_result.get('stdout')).get('result')
|
||||||
except Exception as e:
|
except Exception as ex:
|
||||||
return merge_hash(cur_result, dict(
|
return merge_hash(cur_result, dict(
|
||||||
failed=True,
|
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
|
# generate batch script
|
||||||
@ -61,25 +67,27 @@ class ActionModule(ActionBase):
|
|||||||
cur_state,
|
cur_state,
|
||||||
item.get('root', '/'),
|
item.get('root', '/'),
|
||||||
item.get('config', {}),
|
item.get('config', {}),
|
||||||
item.get('state', 'present')
|
item.get('state', 'present'),
|
||||||
, False)
|
False)
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as ex:
|
||||||
return merge_hash(cur_result, dict(
|
return merge_hash(cur_result, dict(
|
||||||
failed=True,
|
failed=True,
|
||||||
msg='Error while generating Wildfly batch: {}'.format(str(e)),
|
msg='Error while generating Wildfly batch: {}'.format(
|
||||||
|
str(ex)),
|
||||||
stdout=None,
|
stdout=None,
|
||||||
stdout_lines=[],
|
stdout_lines=[],
|
||||||
config_item=item,
|
config_item=item,
|
||||||
batch_script=batch_script
|
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
|
# apply changes
|
||||||
if batch_script:
|
if batch_script:
|
||||||
batch_script = 'batch\n{}run-batch\n'.format(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:
|
if not dry_run:
|
||||||
self.execute_command(
|
self.execute_command(
|
||||||
@ -90,7 +98,6 @@ class ActionModule(ActionBase):
|
|||||||
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
def execute_command(self, command, stdin=None, check_mode_unsafe=True):
|
def execute_command(self, command, stdin=None, check_mode_unsafe=True):
|
||||||
'''
|
'''
|
||||||
Execute command module and return result
|
Execute command module and return result
|
||||||
@ -107,7 +114,6 @@ class ActionModule(ActionBase):
|
|||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def read_args(task_args, check_mode):
|
def read_args(task_args, check_mode):
|
||||||
'''
|
'''
|
||||||
Read and validate invocation arguments
|
Read and validate invocation arguments
|
||||||
@ -125,9 +131,9 @@ def read_args(task_args, check_mode):
|
|||||||
'Please use "config" argument instead.')
|
'Please use "config" argument instead.')
|
||||||
|
|
||||||
# validate config argument
|
# validate config argument
|
||||||
if type(config) is list:
|
if isinstance(config, list):
|
||||||
pass
|
pass
|
||||||
elif type(config) is dict:
|
elif isinstance(config, dict):
|
||||||
config = [dict(
|
config = [dict(
|
||||||
config=config,
|
config=config,
|
||||||
root=task_args.get('root'),
|
root=task_args.get('root'),
|
||||||
@ -142,7 +148,6 @@ def read_args(task_args, check_mode):
|
|||||||
return cli_command, config, dry_run
|
return cli_command, config, dry_run
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def wildfly_batch(prev, root, attrs, state='present', wrap=True):
|
def wildfly_batch(prev, root, attrs, state='present', wrap=True):
|
||||||
'''
|
'''
|
||||||
Generate Wildfly batch to assert state of configuration item under
|
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 = ''
|
output = ''
|
||||||
|
|
||||||
# check current config
|
# check current config
|
||||||
cur = wildfly_config_query(prev, root)
|
cur = config_query(prev, root)
|
||||||
|
|
||||||
display.v("current config: {}".format(cur))
|
display.v("current config: {}".format(cur))
|
||||||
|
|
||||||
@ -174,7 +179,7 @@ def wildfly_batch(prev, root, attrs, state='present', wrap=True):
|
|||||||
|
|
||||||
if cur:
|
if cur:
|
||||||
# node exists, add missing attrs
|
# node exists, add missing attrs
|
||||||
for k in attrs:
|
for k in sorted(attrs):
|
||||||
if k not in cur or cur[k] != attrs[k]:
|
if k not in cur or cur[k] != attrs[k]:
|
||||||
output = '{}{}:write-attribute(name={},value={})\n'.format(
|
output = '{}{}:write-attribute(name={},value={})\n'.format(
|
||||||
output, root, k, format_attr(attrs[k]))
|
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
|
# node doesn't exist, add it
|
||||||
output = '{}{}:add({})\n'.format(
|
output = '{}{}:add({})\n'.format(
|
||||||
output, root,
|
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:
|
if state.lower() == 'absent' and cur:
|
||||||
# remove existing node
|
# remove existing node
|
||||||
output = '{}{}:remove()\n'.format(output, root)
|
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)
|
output = 'batch\n{}\nrun-batch\n'.format(output)
|
||||||
|
|
||||||
return output
|
return output
|
||||||
|
|
||||||
|
|
||||||
def wildfly_config_query(config, path):
|
def config_query(config, path):
|
||||||
'''
|
'''
|
||||||
Given Wildfly configuration as a dict, follow
|
Given Wildfly configuration as a dict, follow
|
||||||
requested path and return corresponding entry.
|
requested path and return corresponding entry.
|
||||||
@ -207,39 +213,18 @@ def wildfly_config_query(config, path):
|
|||||||
'''
|
'''
|
||||||
path = WildflyPath(path)
|
path = WildflyPath(path)
|
||||||
ptr = config
|
ptr = config
|
||||||
while len(path):
|
while len(path) > 0:
|
||||||
try:
|
try:
|
||||||
qry = path.lpop()
|
qry = path.lpop()
|
||||||
ptr = ptr[qry]
|
ptr = ptr[qry]
|
||||||
except (KeyError, TypeError):
|
except (KeyError, TypeError):
|
||||||
# either ptr is none (Type), or ptr[qry] not found (Key)
|
# either ptr is none (Type), or ptr[qry] not found (Key)
|
||||||
return None
|
return None
|
||||||
except Exception as e:
|
except Exception as ex:
|
||||||
raise WildflyError( "config query error: {}".format(str(e)))
|
raise WildflyError("config query error: {}".format(str(ex)))
|
||||||
return ptr
|
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):
|
def format_attr(attr):
|
||||||
'''
|
'''
|
||||||
Return valid text representation for attribute as understood by
|
Return valid text representation for attribute as understood by
|
||||||
@ -251,19 +236,27 @@ def format_attr(attr):
|
|||||||
if attr is None:
|
if attr is None:
|
||||||
return 'undefined'
|
return 'undefined'
|
||||||
|
|
||||||
|
if isinstance(attr, (float)):
|
||||||
|
return '{:f}'.format(attr)
|
||||||
|
|
||||||
|
if isinstance(attr, (int, bool)):
|
||||||
|
return str(attr)
|
||||||
|
|
||||||
# list => '[ format(item), ... ]'
|
# list => '[ format(item), ... ]'
|
||||||
if isinstance(attr,list):
|
if isinstance(attr, (list,tuple)):
|
||||||
return '[' + ', '.join(
|
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), ... }'
|
# dict => '{ "key" => format(value), ... }'
|
||||||
if isinstance(attr,dict):
|
if isinstance(attr, dict):
|
||||||
return '{' + ', '.join(
|
return '{' + ', '.join(
|
||||||
[ '"{}" => {}'.format(
|
['"{}" => {}'.format(
|
||||||
k_,
|
k_, 'undefined' if attr[k_] is None
|
||||||
'undefined' if attr[k_] is None else format_attr(attr[k_])
|
else format_attr(attr[k_])
|
||||||
) for k_ in list(attr.keys()) ]
|
) for k_ in list(attr.keys())]
|
||||||
) + '}'
|
) + '}'
|
||||||
|
|
||||||
# wrap strings with double quotes
|
# wrap strings with double quotes
|
||||||
@ -283,14 +276,14 @@ class WildflyPath:
|
|||||||
def __init__(self, path):
|
def __init__(self, path):
|
||||||
if isinstance(path, string_types):
|
if isinstance(path, string_types):
|
||||||
self.parts = [
|
self.parts = [
|
||||||
i.replace('\\','').strip()
|
i.replace('\\', '').strip()
|
||||||
for i in re.split(r'((?<!\\)[=/])', path)
|
for i in re.split(r'((?<!\\)[=/])', path)
|
||||||
]
|
]
|
||||||
elif isinstance(path, WildflyPath):
|
elif isinstance(path, WildflyPath):
|
||||||
self.parts = path.parts
|
self.parts = path.parts
|
||||||
elif isinstance(path, list, tuple):
|
elif isinstance(path, list, tuple):
|
||||||
self.parts = [
|
self.parts = [
|
||||||
i.replace('\\','').strip()
|
i.replace('\\', '').strip()
|
||||||
for i in path
|
for i in path
|
||||||
]
|
]
|
||||||
else:
|
else:
|
||||||
@ -298,15 +291,18 @@ class WildflyPath:
|
|||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return ''.join([
|
return ''.join([
|
||||||
(i if i in ('','/','=') else i.replace('/','\\/'))
|
(i if i in ('', '/', '=') else i.replace('/', '\\/'))
|
||||||
for i in self.parts
|
for i in self.parts
|
||||||
])
|
])
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return sum([1 for i in self.parts if i not in ('','=','/')])
|
return sum([1 for i in self.parts if i not in ('', '=', '/')])
|
||||||
|
|
||||||
def lpop(self):
|
def lpop(self):
|
||||||
|
'''
|
||||||
|
remove first path component and return it
|
||||||
|
'''
|
||||||
ret = self.parts.pop(0)
|
ret = self.parts.pop(0)
|
||||||
while ret in ('','/','='):
|
while ret in ('', '/', '='):
|
||||||
ret = self.parts.pop(0)
|
ret = self.parts.pop(0)
|
||||||
return ret
|
return ret
|
||||||
|
Loading…
x
Reference in New Issue
Block a user