diff --git a/.travis.yml b/.travis.yml index 3af0261..a3bc78a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,14 +6,14 @@ python: - 3.6 env: - - ANSIBLE_VERSION=2.3 - - ANSIBLE_VERSION=2.4 - ANSIBLE_VERSION=2.5 - ANSIBLE_VERSION=2.6 + - ANSIBLE_VERSION=2.7 + - ANSIBLE_VERSION=2.8 install: - pip install pylama - - pip install napalm + - pip install -r requirements.txt - pip install "ansible>=$ANSIBLE_VERSION.0,<$ANSIBLE_VERSION.99" - pip install -r requirements-dev.txt - pip install -e . diff --git a/CHANGELOG.rst b/CHANGELOG.rst index ed2a6b6..49103a9 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,14 @@ -develop +1.0.0 ===== + - Add support for ansible_network_os + - Fix minor documentation errors + - Expand filenames for `*_file` parameters + - Fix Ansible 2.8 backwards incompatible changes + - Removing support of legacy napalm_base + - Changing napalm_cli to cli_results; napalm_ping to ping_results + - Use yaml safe_load for tests + 0.10.0 ===== diff --git a/README.md b/README.md index 8a1d43d..ab5a211 100644 --- a/README.md +++ b/README.md @@ -105,7 +105,7 @@ Example to get compliance report validation_file: validate.yml ``` -Example to use default connection paramters: +Example to use default connection parameters: ``` - name: get facts from device napalm_get_facts: diff --git a/napalm_ansible/modules/napalm_cli.py b/napalm_ansible/modules/napalm_cli.py index 7827c81..6097bd7 100644 --- a/napalm_ansible/modules/napalm_cli.py +++ b/napalm_ansible/modules/napalm_cli.py @@ -1,5 +1,14 @@ from __future__ import unicode_literals, print_function -from ansible.module_utils.basic import AnsibleModule, return_values +from ansible.module_utils.basic import AnsibleModule + + +# FIX for Ansible 2.8 moving this function and making it private +# greatly simplified for napalm-ansible's use +def return_values(obj): + """ Return native stringified values from datastructures. + + For use with removing sensitive values pre-jsonification.""" + yield str(obj) DOCUMENTATION = ''' @@ -87,15 +96,6 @@ except ImportError: pass -# Legacy for pre-reunification napalm (remove in future) -if not napalm_found: - try: - from napalm_base import get_network_driver # noqa - from napalm_base import ModuleImportError # noqa - napalm_found = True - except ImportError: - pass - def main(): module = AnsibleModule( @@ -175,7 +175,7 @@ def main(): except Exception as e: module.fail_json(msg="cannot close device connection: " + str(e)) - module.exit_json(changed=False, results=cli_response) + module.exit_json(changed=False, cli_results=cli_response) if __name__ == '__main__': diff --git a/napalm_ansible/modules/napalm_get_facts.py b/napalm_ansible/modules/napalm_get_facts.py index 3fae938..d58ddc2 100644 --- a/napalm_ansible/modules/napalm_get_facts.py +++ b/napalm_ansible/modules/napalm_get_facts.py @@ -3,8 +3,8 @@ This file is part of Ansible -Ansible is free software: you can redistribute it and/or modify -it under the terms of the GNU General Public License as published by +Ansible is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. @@ -17,7 +17,16 @@ along with Ansible. If not, see . """ from __future__ import unicode_literals, print_function -from ansible.module_utils.basic import AnsibleModule, return_values +from ansible.module_utils.basic import AnsibleModule + + +# FIX for Ansible 2.8 moving this function and making it private +# greatly simplified for napalm-ansible's use +def return_values(obj): + """ Return native stringified values from datastructures. + + For use with removing sensitive values pre-jsonification.""" + yield str(obj) DOCUMENTATION = ''' @@ -145,15 +154,6 @@ except ImportError: pass -# Legacy for pre-reunification napalm (remove in future) -if not napalm_found: - try: - from napalm_base import get_network_driver # noqa - from napalm_base import ModuleImportError # noqa - napalm_found = True - except ImportError: - pass - def main(): module = AnsibleModule( diff --git a/napalm_ansible/modules/napalm_install_config.py b/napalm_ansible/modules/napalm_install_config.py index 38c4b37..bfa9cef 100644 --- a/napalm_ansible/modules/napalm_install_config.py +++ b/napalm_ansible/modules/napalm_install_config.py @@ -18,7 +18,17 @@ along with Ansible. If not, see . """ from __future__ import unicode_literals, print_function -from ansible.module_utils.basic import AnsibleModule, return_values +import os.path +from ansible.module_utils.basic import AnsibleModule + + +# FIX for Ansible 2.8 moving this function and making it private +# greatly simplified for napalm-ansible's use +def return_values(obj): + """ Return native stringified values from datastructures. + + For use with removing sensitive values pre-jsonification.""" + yield str(obj) DOCUMENTATION = ''' @@ -165,15 +175,6 @@ except ImportError: pass -# Legacy for pre-reunification napalm (remove in future) -if not napalm_found: - try: - from napalm_base import get_network_driver # noqa - from napalm_base import ModuleImportError # noqa - napalm_found = True - except ImportError: - pass - def save_to_file(content, filename): with open(filename, 'w') as f: @@ -236,6 +237,14 @@ def main(): get_diffs = module.params['get_diffs'] archive_file = module.params['archive_file'] candidate_file = module.params['candidate_file'] + if config_file: + config_file = os.path.expanduser(os.path.expandvars(config_file)) + if diff_file: + diff_file = os.path.expanduser(os.path.expandvars(diff_file)) + if archive_file: + archive_file = os.path.expanduser(os.path.expandvars(archive_file)) + if candidate_file: + candidate_file = os.path.expanduser(os.path.expandvars(candidate_file)) argument_check = {'hostname': hostname, 'username': username, 'dev_os': dev_os} for key, val in argument_check.items(): diff --git a/napalm_ansible/modules/napalm_parse_yang.py b/napalm_ansible/modules/napalm_parse_yang.py index 6a2b7fc..9ba84c9 100644 --- a/napalm_ansible/modules/napalm_parse_yang.py +++ b/napalm_ansible/modules/napalm_parse_yang.py @@ -17,7 +17,7 @@ along with Ansible. If not, see . """ from __future__ import unicode_literals, print_function -from ansible.module_utils.basic import AnsibleModule, return_values +from ansible.module_utils.basic import AnsibleModule import json napalm_found = False @@ -28,21 +28,21 @@ except ImportError: pass -# Legacy for pre-reunification napalm (remove in future) -if not napalm_found: - try: - from napalm_base import get_network_driver # noqa - from napalm_base import ModuleImportError # noqa - napalm_found = True - except ImportError: - pass - try: import napalm_yang except ImportError: napalm_yang = None +# FIX for Ansible 2.8 moving this function and making it private +# greatly simplified for napalm-ansible's use +def return_values(obj): + """ Return native stringified values from datastructures. + + For use with removing sensitive values pre-jsonification.""" + yield str(obj) + + DOCUMENTATION = ''' --- module: napalm_parse_yang diff --git a/napalm_ansible/modules/napalm_ping.py b/napalm_ansible/modules/napalm_ping.py index d3eeb32..182a32f 100644 --- a/napalm_ansible/modules/napalm_ping.py +++ b/napalm_ansible/modules/napalm_ping.py @@ -14,7 +14,16 @@ along with Ansible. If not, see . """ from __future__ import unicode_literals, print_function -from ansible.module_utils.basic import AnsibleModule, return_values +from ansible.module_utils.basic import AnsibleModule + + +# FIX for Ansible 2.8 moving this function and making it private +# greatly simplified for napalm-ansible's use +def return_values(obj): + """ Return native stringified values from datastructures. + + For use with removing sensitive values pre-jsonification.""" + yield str(obj) DOCUMENTATION = ''' @@ -136,15 +145,6 @@ except ImportError: pass -# Legacy for pre-reunification napalm (remove in future) -if not napalm_found: - try: - from napalm_base import get_network_driver # noqa - from napalm_base import ModuleImportError # noqa - napalm_found = True - except ImportError: - pass - def main(): module = AnsibleModule( @@ -236,7 +236,7 @@ def main(): except Exception as e: module.fail_json(msg="cannot close device connection: " + str(e)) - module.exit_json(changed=False, results=ping_response) + module.exit_json(changed=False, ping_results=ping_response) if __name__ == '__main__': diff --git a/napalm_ansible/modules/napalm_validate.py b/napalm_ansible/modules/napalm_validate.py index 7d48c39..ae138e5 100644 --- a/napalm_ansible/modules/napalm_validate.py +++ b/napalm_ansible/modules/napalm_validate.py @@ -1,5 +1,5 @@ from __future__ import unicode_literals, print_function -from ansible.module_utils.basic import AnsibleModule, return_values +from ansible.module_utils.basic import AnsibleModule napalm_found = False try: @@ -9,21 +9,21 @@ except ImportError: pass -# Legacy for pre-reunification napalm (remove in future) -if not napalm_found: - try: - from napalm_base import get_network_driver # noqa - from napalm_base import ModuleImportError # noqa - napalm_found = True - except ImportError: - pass - try: import napalm_yang except ImportError: napalm_yang = None +# FIX for Ansible 2.8 moving this function and making it private +# greatly simplified for napalm-ansible's use +def return_values(obj): + """ Return native stringified values from datastructures. + + For use with removing sensitive values pre-jsonification.""" + yield str(obj) + + DOCUMENTATION = ''' --- module: napalm_validate diff --git a/napalm_ansible/plugins/action/napalm.py b/napalm_ansible/plugins/action/napalm.py index acd8466..ac37522 100644 --- a/napalm_ansible/plugins/action/napalm.py +++ b/napalm_ansible/plugins/action/napalm.py @@ -18,6 +18,9 @@ def run(self, tmp=None, task_vars=None): # Timeout can't be passed via command-line as Ansible defaults to a 10 second timeout provider['timeout'] = provider.get('timeout', 60) + if hasattr(pc, 'network_os'): + provider['dev_os'] = provider.get('dev_os', pc.network_os) + self._task.args['provider'] = provider result = super(ActionModule, self).run(tmp, task_vars) diff --git a/requirements.txt b/requirements.txt index a98b396..d59b294 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1,2 @@ napalm +six diff --git a/setup.py b/setup.py index 100afde..8c3abce 100644 --- a/setup.py +++ b/setup.py @@ -6,7 +6,7 @@ setup( name="napalm-ansible", - version='0.10.0', + version='1.0.0', packages=find_packages(exclude=("test*", "library")), author="David Barroso, Kirk Byers, Mircea Ulinic", author_email="dbarrosop@dravetech.com, ktbyers@twb-tech.com", diff --git a/tests/napalm_cli/multiple_commands.yaml b/tests/napalm_cli/multiple_commands.yaml index 97ad04e..16e68ee 100644 --- a/tests/napalm_cli/multiple_commands.yaml +++ b/tests/napalm_cli/multiple_commands.yaml @@ -19,5 +19,5 @@ register: result - assert: that: - - "{{ result.results['show version']|length > 10 }}" - - "{{ result.results['show interfaces']|length > 10 }}" + - "{{ result.cli_results['show version']|length > 10 }}" + - "{{ result.cli_results['show interfaces']|length > 10 }}" diff --git a/tests/napalm_connection/connection_ansible_network_os.yaml b/tests/napalm_connection/connection_ansible_network_os.yaml new file mode 100644 index 0000000..2c59824 --- /dev/null +++ b/tests/napalm_connection/connection_ansible_network_os.yaml @@ -0,0 +1,13 @@ +--- +- name: Get facts + hosts: all + connection: local # code is run locally + gather_facts: no # don't gather facts + tasks: + - block: + - name: get facts from device + napalm_get_facts: # NAPALM plugin + optional_args: + path: "{{ playbook_dir }}/mocked" + profile: "{{ profile }}" + filter: ['facts'] diff --git a/tests/napalm_connection/hosts b/tests/napalm_connection/hosts index 44150c8..763864f 100644 --- a/tests/napalm_connection/hosts +++ b/tests/napalm_connection/hosts @@ -1,5 +1,5 @@ [all] -dummy os=mock profile=[eos] password=vagrant +dummy os=mock profile=[eos] password=vagrant ansible_network_os=mock [all:vars] ansible_python_interpreter="/usr/bin/env python" diff --git a/tests/run_tests.sh b/tests/run_tests.sh index d070a33..61e7e7e 100755 --- a/tests/run_tests.sh +++ b/tests/run_tests.sh @@ -4,6 +4,7 @@ set -e ansible-playbook -i napalm_connection/hosts napalm_connection/connection_info_missing.yaml ansible-playbook -i napalm_connection/hosts napalm_connection/connection_info_in_vars.yaml ansible-playbook -i napalm_connection/hosts napalm_connection/connection_info_in_args.yaml -u vagrant +ansible-playbook -i napalm_connection/hosts napalm_connection/connection_ansible_network_os.yaml -u vagrant ANSIBLE_REMOTE_USER=vagrant ansible-playbook -i napalm_connection/hosts napalm_connection/connection_info_in_env.yaml ansible-playbook -i napalm_install_config/hosts -l "*.dry_run.*" napalm_install_config/config.yaml -C diff --git a/tests/test_documentation.py b/tests/test_documentation.py index 6f838ec..30418cd 100644 --- a/tests/test_documentation.py +++ b/tests/test_documentation.py @@ -24,7 +24,7 @@ def test_module_documentation_exists(ansible_module): def test_module_documentation_format(ansible_module): module = import_module(ansible_module) - docs = yaml.load(module.DOCUMENTATION) + docs = yaml.safe_load(module.DOCUMENTATION) assert 'author' in docs.keys() assert 'description' in docs.keys() assert 'short_description' in docs.keys() @@ -37,8 +37,8 @@ def test_module_documentation_format(ansible_module): def test_module_examples_format(ansible_module): module = import_module(ansible_module) module_name = ansible_module.replace('napalm_ansible.', '') - examples = yaml.load(module.EXAMPLES) - params = yaml.load(module.DOCUMENTATION)['options'].keys() + examples = yaml.safe_load(module.EXAMPLES) + params = yaml.safe_load(module.DOCUMENTATION)['options'].keys() for example in examples: if module_name in example.keys(): for param in example[module_name]: @@ -47,7 +47,7 @@ def test_module_examples_format(ansible_module): def test_module_return_format(ansible_module): module = import_module(ansible_module) - yaml.load(module.RETURN) + yaml.safe_load(module.RETURN) def test_build_docs(ansible_module): @@ -58,10 +58,10 @@ def test_build_docs(ansible_module): module = import_module(ansible_module) content = {} - content['doc'] = yaml.load(module.DOCUMENTATION) + content['doc'] = yaml.safe_load(module.DOCUMENTATION) content['examples'] = module.EXAMPLES content['example_lines'] = module.EXAMPLES.split('\n') - content['return_values'] = yaml.load(module.RETURN) + content['return_values'] = yaml.safe_load(module.RETURN) module_name = ansible_module.replace('napalm_ansible.', '').split('.')[-1] with open('module_docs/{0}.json'.format(module_name), 'w') as f: