Skip to content

Commit ad7e127

Browse files
Merge pull request #36 from ansible-network/bt_add_tests_and_sample
add tests, model changes and a little bit of code Reviewed-by: Bradley A. Thornton https://github.com/cidrblock
2 parents 19c14e2 + d05fbb3 commit ad7e127

File tree

34 files changed

+1855
-21
lines changed

34 files changed

+1855
-21
lines changed

README.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,3 +248,14 @@ def main():
248248
`module_utils/<ansible_network_os>/utils`.
249249

250250
- Utilities for the` <ansible_network_os>` platform.
251+
252+
### Developer Notes
253+
254+
The tests rely on a role generated by the resource module builder. After changes to the resource module builder, the role should be regenerated and the tests modified and run as needed. To generate the role after changes:
255+
256+
```
257+
ansible-playbook -e parent=./tests/roles/my_role \
258+
-e structure=role \
259+
-e model=models/myos/interfaces/myos_interfaces.yml \
260+
site.yml
261+
```

models/myos/interfaces/myos_interfaces.yml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,14 @@ DOCUMENTATION: |
2626
type: list
2727
elements: dict
2828
suboptions:
29+
name:
30+
type: str
31+
description: The name of the <resource>
2932
some_string:
3033
type: str
3134
description:
3235
- The some_string_01
33-
chocies:
36+
choices:
3437
- choice_a
3538
- choice_b
3639
- choice_c

roles/resource_module/templates/module_directory/network_os/network_os_facts.py.j2

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,8 @@ def main():
9090
"""
9191
module = AnsibleModule(argument_spec=Facts.argument_spec,
9292
supports_check_mode=True)
93-
warnings = ['default value for `gather_subset` will be changed to `min` from `!config` v2.11 onwards']
93+
warnings = ['default value for `gather_subset` \
94+
will be changed to `min` from `!config` v2.11 onwards']
9495

9596
connection = Connection(module._socket_path) #pylint: disable=W0212
9697
gather_subset = module.params['gather_subset']

roles/resource_module/templates/module_utils/network_os/facts/base.py.j2

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ from copy import deepcopy
1212
from ansible.module_utils.six import iteritems
1313

1414

15-
class FactsBase(object): #pylint: disable=R0205
15+
class FactsBase(object):
1616
"""
1717
The {{ network_os }} facts base class
1818
"""
@@ -31,8 +31,7 @@ class FactsBase(object): #pylint: disable=R0205
3131

3232
self.generated_spec = self.generate_dict(facts_argument_spec)
3333

34-
@staticmethod
35-
def generate_dict(spec):
34+
def generate_dict(self, spec):
3635
"""
3736
Generate dictionary which is in sync with argspec
3837
@@ -47,10 +46,11 @@ class FactsBase(object): #pylint: disable=R0205
4746
for key, val in iteritems(spec):
4847
if 'default' in val:
4948
dct = {key: val['default']}
49+
elif 'type' in val and val['type'] == 'dict':
50+
dct = {key: self.generate_dict(val['options'])}
5051
else:
5152
dct = {key: None}
5253
obj.update(dct)
53-
5454
return obj
5555

5656
@staticmethod
@@ -91,8 +91,7 @@ class FactsBase(object): #pylint: disable=R0205
9191
return res2
9292
return None
9393

94-
@staticmethod
95-
def generate_final_config(cfg_dict):
94+
def generate_final_config(self, cfg_dict):
9695
"""
9796
Generate final config dictionary
9897
@@ -105,6 +104,13 @@ class FactsBase(object): #pylint: disable=R0205
105104
return final_cfg
106105

107106
for key, val in iteritems(cfg_dict):
108-
if val:
109-
final_cfg.update({key:val})
107+
dct = None
108+
if isinstance(val, dict):
109+
child_val = self.generate_final_config(val)
110+
if child_val:
111+
dct = {key: child_val}
112+
elif val:
113+
dct = {key: val}
114+
if dct:
115+
final_cfg.update(dct)
110116
return final_cfg

roles/resource_module/templates/module_utils/network_os/facts/resource/resource.py.j2

Lines changed: 37 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ It is in this file the configuration is collected from the device
88
for a given resource, parsed, and the facts tree is populated
99
based on the configuration.
1010
"""
11+
import re
1112
from copy import deepcopy
1213
from {{ import_path }}. \
1314
{{ network_os }}.facts.base import FactsBase
@@ -18,7 +19,6 @@ class {{ resource|capitalize }}Facts(FactsBase):
1819

1920
def populate_facts(self, module, connection, data=None):
2021
""" Populate the facts for {{ resource }}
21-
2222
:param module: the module instance
2323
:param connection: the device connection
2424
:param data: previously collected conf
@@ -31,14 +31,26 @@ class {{ resource|capitalize }}Facts(FactsBase):
3131
pass
3232

3333
if not data:
34-
data = "foo" # connection.get('show running-config | section ^interface')
34+
# typically data is populated from the current device configuration
35+
# data = connection.get('show running-config | section ^interface')
36+
# using mock data instead
37+
data = ("resource rsrc_a\n"
38+
" a_bool true\n"
39+
" a_string choice_a\n"
40+
" resource here\n"
41+
"resource rscrc_b\n"
42+
" key is property01 value is value end\n"
43+
" an_int 10\n")
44+
45+
# split the config into instances of the resource
46+
resource_delim = 'resource'
47+
find_pattern = r'(?:^|\n)%s.*?(?=(?:^|\n)%s|$)' % (resource_delim, resource_delim)
48+
resources = [p.strip() for p in re.findall(find_pattern, data, re.DOTALL)]
3549

36-
# operate on a collection of resource x
37-
config = [data] # data.split('interface ')
3850
objs = []
39-
for conf in config:
40-
if conf:
41-
obj = self.render_config(self.generated_spec, conf)
51+
for resource in resources:
52+
if resource:
53+
obj = self.render_config(self.generated_spec, resource)
4254
if obj:
4355
objs.append(obj)
4456
facts = {}
@@ -56,9 +68,23 @@ class {{ resource|capitalize }}Facts(FactsBase):
5668
:rtype: dictionary
5769
:returns: The generated config
5870
"""
59-
if conf:
60-
pass
6171
config = deepcopy(spec)
62-
# populate the facts from the configuration
63-
config = {"some": "value"}
72+
73+
config['name'] = self.parse_conf_arg(conf, 'resource')
74+
config['some_string'] = self.parse_conf_arg(conf, 'a_string')
75+
76+
match = re.match(r'.*key is property01 (\S+)', conf, re.MULTILINE|re.DOTALL)
77+
if match:
78+
config['some_dict']['property_01'] = match.groups()[0]
79+
80+
try:
81+
config['some_bool'] = bool(self.parse_conf_arg(conf, 'a_bool'))
82+
except TypeError:
83+
config['some_bool'] = None
84+
85+
try:
86+
config['some_int'] = int(self.parse_conf_arg(conf, 'an_int'))
87+
except TypeError:
88+
config['some_int'] = None
89+
6490
return self.generate_final_config(config)

tests/ansible.cfg

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[defaults]
2+
host_key_checking = False
3+
stdout_callback = yaml

tests/inventory.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
all:
2+
children:
3+
eos:
4+
hosts:
5+
myos101:
6+
ansible_host: vyos101
7+
vars:
8+
ansible_network_os: vyos
9+
ansible_user: admin
10+
ansible_connection: network_cli
11+
ansible_password: password
12+
ansible_become: True
13+
ansible_become_method: enable
14+
ansible_become_pass: password
15+
ansible_facts_modules: myos_facts

0 commit comments

Comments
 (0)