From 955dc6e250c3412b80211868ccea13eb6214c369 Mon Sep 17 00:00:00 2001 From: Ricardo Carrillo Cruz Date: Fri, 2 Jun 2017 17:01:08 +0200 Subject: [PATCH] Add net_banner platform agnostic module (#25245) * Add net_banner platform agnostic module * Add integration tests for net_banner * Remove default from required param * Remove skip/python3 from net_banner aliases --- lib/ansible/modules/network/net_banner.py | 88 +++++++++++++++++++ lib/ansible/plugins/action/net_banner.py | 27 ++++++ test/integration/platform_agnostic.yaml | 1 + test/integration/targets/net_banner/aliases | 1 + .../targets/net_banner/defaults/main.yaml | 2 + .../targets/net_banner/tasks/cli.yaml | 16 ++++ .../targets/net_banner/tasks/main.yaml | 2 + .../net_banner/tests/cli/basic-login.yaml | 7 ++ .../net_banner/tests/cli/basic-motd.yaml | 7 ++ .../net_banner/tests/cli/basic-no-login.yaml | 7 ++ .../net_banner/tests/eos/basic-login.yaml | 55 ++++++++++++ .../net_banner/tests/eos/basic-motd.yaml | 55 ++++++++++++ .../net_banner/tests/eos/basic-no-login.yaml | 48 ++++++++++ .../net_banner/tests/ios/basic-login.yaml | 50 +++++++++++ .../net_banner/tests/ios/basic-motd.yaml | 49 +++++++++++ .../net_banner/tests/ios/basic-no-login.yaml | 44 ++++++++++ 16 files changed, 459 insertions(+) create mode 100644 lib/ansible/modules/network/net_banner.py create mode 100644 lib/ansible/plugins/action/net_banner.py create mode 100644 test/integration/targets/net_banner/aliases create mode 100644 test/integration/targets/net_banner/defaults/main.yaml create mode 100644 test/integration/targets/net_banner/tasks/cli.yaml create mode 100644 test/integration/targets/net_banner/tasks/main.yaml create mode 100644 test/integration/targets/net_banner/tests/cli/basic-login.yaml create mode 100644 test/integration/targets/net_banner/tests/cli/basic-motd.yaml create mode 100644 test/integration/targets/net_banner/tests/cli/basic-no-login.yaml create mode 100644 test/integration/targets/net_banner/tests/eos/basic-login.yaml create mode 100644 test/integration/targets/net_banner/tests/eos/basic-motd.yaml create mode 100644 test/integration/targets/net_banner/tests/eos/basic-no-login.yaml create mode 100644 test/integration/targets/net_banner/tests/ios/basic-login.yaml create mode 100644 test/integration/targets/net_banner/tests/ios/basic-motd.yaml create mode 100644 test/integration/targets/net_banner/tests/ios/basic-no-login.yaml diff --git a/lib/ansible/modules/network/net_banner.py b/lib/ansible/modules/network/net_banner.py new file mode 100644 index 00000000000..bfe79a83c33 --- /dev/null +++ b/lib/ansible/modules/network/net_banner.py @@ -0,0 +1,88 @@ +#!/usr/bin/python +# +# 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 +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . +# + +ANSIBLE_METADATA = {'metadata_version': '1.0', + 'status': ['preview'], + 'supported_by': 'community'} + + +DOCUMENTATION = """ +--- +module: net_banner +version_added: "2.4" +author: "Ricardo Carrillo Cruz (@rcarrillocruz)" +short_description: Manage multiline banners on network devices +description: + - This will configure both login and motd banners on network devices. + It allows playbooks to add or remote + banner text from the active running configuration. +options: + banner: + description: + - Specifies which banner that should be + configured on the remote device. + required: true + choices: ['login', 'banner'] + text: + description: + - The banner text that should be + present in the remote device running configuration. This argument + accepts a multiline string, with no empty lines. Requires I(state=present). + default: null + state: + description: + - Specifies whether or not the configuration is + present in the current devices active running configuration. + default: present + choices: ['present', 'absent'] +""" + +EXAMPLES = """ +- name: configure the login banner + net_banner: + banner: login + text: | + this is my login banner + that contains a multiline + string + state: present + +- name: remove the motd banner + net_banner: + banner: motd + state: absent + +- name: Configure banner from file + net_banner: + banner: motd + text: "{{ lookup('file', './config_partial/raw_banner.cfg') }}" + state: present + +""" + +RETURN = """ +commands: + description: The list of configuration mode commands to send to the device + returned: always + type: list + sample: + - banner login + - this is my login banner + - that contains a multiline + - string +""" diff --git a/lib/ansible/plugins/action/net_banner.py b/lib/ansible/plugins/action/net_banner.py new file mode 100644 index 00000000000..cad73f8a26a --- /dev/null +++ b/lib/ansible/plugins/action/net_banner.py @@ -0,0 +1,27 @@ +# (c) 2017, Ansible Inc, +# +# 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 +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Ansible is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Ansible. If not, see . +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +from ansible.plugins.action.net_base import ActionModule as _ActionModule + + +class ActionModule(_ActionModule): + def run(self, tmp=None, task_vars=None): + result = super(ActionModule, self).run(tmp, task_vars) + + return result diff --git a/test/integration/platform_agnostic.yaml b/test/integration/platform_agnostic.yaml index ee9c55c2a5e..eda4f5431df 100644 --- a/test/integration/platform_agnostic.yaml +++ b/test/integration/platform_agnostic.yaml @@ -9,3 +9,4 @@ roles: - { role: net_system, when: "limit_to in ['*', 'net_system']" } + - { role: net_banner, when: "limit_to in ['*', 'net_banner']" } diff --git a/test/integration/targets/net_banner/aliases b/test/integration/targets/net_banner/aliases new file mode 100644 index 00000000000..93151a8d9df --- /dev/null +++ b/test/integration/targets/net_banner/aliases @@ -0,0 +1 @@ +network/ci diff --git a/test/integration/targets/net_banner/defaults/main.yaml b/test/integration/targets/net_banner/defaults/main.yaml new file mode 100644 index 00000000000..5f709c5aac1 --- /dev/null +++ b/test/integration/targets/net_banner/defaults/main.yaml @@ -0,0 +1,2 @@ +--- +testcase: "*" diff --git a/test/integration/targets/net_banner/tasks/cli.yaml b/test/integration/targets/net_banner/tasks/cli.yaml new file mode 100644 index 00000000000..46d86dd6988 --- /dev/null +++ b/test/integration/targets/net_banner/tasks/cli.yaml @@ -0,0 +1,16 @@ +--- +- name: collect all cli test cases + find: + paths: "{{ role_path }}/tests/cli" + patterns: "{{ testcase }}.yaml" + register: test_cases + delegate_to: localhost + +- name: set test_items + set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" + +- name: run test case + include: "{{ test_case_to_run }}" + with_items: "{{ test_items }}" + loop_control: + loop_var: test_case_to_run diff --git a/test/integration/targets/net_banner/tasks/main.yaml b/test/integration/targets/net_banner/tasks/main.yaml new file mode 100644 index 00000000000..415c99d8b12 --- /dev/null +++ b/test/integration/targets/net_banner/tasks/main.yaml @@ -0,0 +1,2 @@ +--- +- { include: cli.yaml, tags: ['cli'] } diff --git a/test/integration/targets/net_banner/tests/cli/basic-login.yaml b/test/integration/targets/net_banner/tests/cli/basic-login.yaml new file mode 100644 index 00000000000..ed5cda1bdb1 --- /dev/null +++ b/test/integration/targets/net_banner/tests/cli/basic-login.yaml @@ -0,0 +1,7 @@ +--- + +- include: "{{ role_path }}/tests/ios/basic-login.yaml" + when: hostvars[inventory_hostname]['ansible_network_os'] == 'ios' + +- include: "{{ role_path }}/tests/eos/basic-login.yaml" + when: hostvars[inventory_hostname]['ansible_network_os'] == 'eos' diff --git a/test/integration/targets/net_banner/tests/cli/basic-motd.yaml b/test/integration/targets/net_banner/tests/cli/basic-motd.yaml new file mode 100644 index 00000000000..a195a89a871 --- /dev/null +++ b/test/integration/targets/net_banner/tests/cli/basic-motd.yaml @@ -0,0 +1,7 @@ +--- + +- include: "{{ role_path }}/tests/ios/basic-motd.yaml" + when: hostvars[inventory_hostname]['ansible_network_os'] == 'ios' + +- include: "{{ role_path }}/tests/eos/basic-motd.yaml" + when: hostvars[inventory_hostname]['ansible_network_os'] == 'eos' diff --git a/test/integration/targets/net_banner/tests/cli/basic-no-login.yaml b/test/integration/targets/net_banner/tests/cli/basic-no-login.yaml new file mode 100644 index 00000000000..d0c514418c1 --- /dev/null +++ b/test/integration/targets/net_banner/tests/cli/basic-no-login.yaml @@ -0,0 +1,7 @@ +--- + +- include: "{{ role_path }}/tests/ios/basic-no-login.yaml" + when: hostvars[inventory_hostname]['ansible_network_os'] == 'ios' + +- include: "{{ role_path }}/tests/eos/basic-no-login.yaml" + when: hostvars[inventory_hostname]['ansible_network_os'] == 'eos' diff --git a/test/integration/targets/net_banner/tests/eos/basic-login.yaml b/test/integration/targets/net_banner/tests/eos/basic-login.yaml new file mode 100644 index 00000000000..c743559ce11 --- /dev/null +++ b/test/integration/targets/net_banner/tests/eos/basic-login.yaml @@ -0,0 +1,55 @@ +--- + +- name: setup - remove login + eos_banner: + banner: login + state: absent + authorize: yes + provider: "{{ cli }}" + +- name: Set login + net_banner: + banner: login + text: | + this is my login banner + that has a multiline + string + state: present + authorize: yes + provider: "{{ cli }}" + register: result + +- debug: + msg: "{{ result }}" + +- assert: + that: + - "result.changed == true" + - "'this is my login banner' in result.commands" + - "'that has a multiline' in result.commands" + # Ensure sessions contains epoc. Will fail after 18th May 2033 + - "'ansible_1' in result.session_name" + +- name: Set login again (idempotent) + net_banner: + banner: login + text: | + this is my login banner + that has a multiline + string + state: present + authorize: yes + provider: "{{ cli }}" + register: result + +- assert: + that: + - "result.changed == false" + - "result.commands | length == 0" + # Ensure sessions contains epoc. Will fail after 18th May 2033 + - "result.session_name is not defined" + + +# FIXME add in tests for everything defined in docs +# FIXME Test state:absent + test: +# FIXME Without powers ensure "privileged mode required" diff --git a/test/integration/targets/net_banner/tests/eos/basic-motd.yaml b/test/integration/targets/net_banner/tests/eos/basic-motd.yaml new file mode 100644 index 00000000000..1e90ad497d7 --- /dev/null +++ b/test/integration/targets/net_banner/tests/eos/basic-motd.yaml @@ -0,0 +1,55 @@ +--- + +- name: setup - remove motd + eos_banner: + banner: motd + state: absent + authorize: yes + provider: "{{ cli }}" + +- name: Set motd + net_banner: + banner: motd + text: | + this is my motd banner + that has a multiline + string + state: present + authorize: yes + provider: "{{ cli }}" + register: result + +- debug: + msg: "{{ result }}" + +- assert: + that: + - "result.changed == true" + - "'this is my motd banner' in result.commands" + - "'that has a multiline' in result.commands" + # Ensure sessions contains epoc. Will fail after 18th May 2033 + - "'ansible_1' in result.session_name" + +- name: Set motd again (idempotent) + net_banner: + banner: motd + text: | + this is my motd banner + that has a multiline + string + state: present + authorize: yes + provider: "{{ cli }}" + register: result + +- assert: + that: + - "result.changed == false" + - "result.commands | length == 0" + # Ensure sessions contains epoc. Will fail after 18th May 2033 + - "result.session_name is not defined" + + +# FIXME add in tests for everything defined in docs +# FIXME Test state:absent + test: +# FIXME Without powers ensure "privileged mode required" diff --git a/test/integration/targets/net_banner/tests/eos/basic-no-login.yaml b/test/integration/targets/net_banner/tests/eos/basic-no-login.yaml new file mode 100644 index 00000000000..17404f4ea48 --- /dev/null +++ b/test/integration/targets/net_banner/tests/eos/basic-no-login.yaml @@ -0,0 +1,48 @@ +--- +- name: Setup + eos_banner: + banner: login + text: | + Junk login banner + over multiple lines + state: present + authorize: yes + provider: "{{ cli }}" + +- name: remove login + net_banner: + banner: login + state: absent + authorize: yes + provider: "{{ cli }}" + register: result + +- debug: + msg: "{{ result }}" + +- assert: + that: + - "result.changed == true" + - "'no banner login' in result.commands" # does this break due to "contains?" + # Ensure sessions contains epoc. Will fail after 18th May 2033 + - "'ansible_1' in result.session_name" + +- name: remove login (idempotent) + net_banner: + banner: login + state: absent + authorize: yes + provider: "{{ cli }}" + register: result + +- assert: + that: + - "result.changed == false" + - "result.commands | length == 0" + # Ensure sessions contains epoc. Will fail after 18th May 2033 + - "result.session_name is not defined" + + +# FIXME add in tests for everything defined in docs +# FIXME Test state:absent + test: +# FIXME Without powers ensure "privileged mode required" diff --git a/test/integration/targets/net_banner/tests/ios/basic-login.yaml b/test/integration/targets/net_banner/tests/ios/basic-login.yaml new file mode 100644 index 00000000000..0e67496a06d --- /dev/null +++ b/test/integration/targets/net_banner/tests/ios/basic-login.yaml @@ -0,0 +1,50 @@ +--- + +- name: setup - remove login + ios_banner: + banner: login + state: absent + authorize: yes + provider: "{{ cli }}" + +- name: Set login + net_banner: + banner: login + text: | + this is my login banner + that has a multiline + string + state: present + authorize: yes + provider: "{{ cli }}" + register: result + +- debug: + msg: "{{ result }}" + +- assert: + that: + - "result.changed == true" + - "'banner login @\nthis is my login banner\nthat has a multiline\nstring\n@' in result.commands" + +- name: Set login again (idempotent) + net_banner: + banner: login + text: | + this is my login banner + that has a multiline + string + state: present + authorize: yes + provider: "{{ cli }}" + register: result + +- assert: + that: + - "result.changed == false" + - "result.commands | length == 0" + + +# FIXME add in tests for everything defined in docs +# FIXME Test state:absent + test: +# FIXME Without powers ensure "privileged mode required" diff --git a/test/integration/targets/net_banner/tests/ios/basic-motd.yaml b/test/integration/targets/net_banner/tests/ios/basic-motd.yaml new file mode 100644 index 00000000000..6f60c0375ca --- /dev/null +++ b/test/integration/targets/net_banner/tests/ios/basic-motd.yaml @@ -0,0 +1,49 @@ +--- +- name: setup - remove motd + ios_banner: + banner: motd + state: absent + authorize: yes + provider: "{{ cli }}" + +- name: Set motd + net_banner: + banner: motd + text: | + this is my motd banner + that has a multiline + string + state: present + authorize: yes + provider: "{{ cli }}" + register: result + +- debug: + msg: "{{ result }}" + +- assert: + that: + - "result.changed == true" + - "'banner motd @\nthis is my motd banner\nthat has a multiline\nstring\n@' in result.commands" + +- name: Set motd again (idempotent) + net_banner: + banner: motd + text: | + this is my motd banner + that has a multiline + string + state: present + authorize: yes + provider: "{{ cli }}" + register: result + +- assert: + that: + - "result.changed == false" + - "result.commands | length == 0" + + +# FIXME add in tests for everything defined in docs +# FIXME Test state:absent + test: +# FIXME Without powers ensure "privileged mode required" diff --git a/test/integration/targets/net_banner/tests/ios/basic-no-login.yaml b/test/integration/targets/net_banner/tests/ios/basic-no-login.yaml new file mode 100644 index 00000000000..18047e296db --- /dev/null +++ b/test/integration/targets/net_banner/tests/ios/basic-no-login.yaml @@ -0,0 +1,44 @@ +--- +- name: Setup + ios_banner: + banner: login + text: | + Junk login banner + over multiple lines + state: present + authorize: yes + provider: "{{ cli }}" + +- name: remove login + net_banner: + banner: login + state: absent + authorize: yes + provider: "{{ cli }}" + register: result + +- debug: + msg: "{{ result }}" + +- assert: + that: + - "result.changed == true" + - "'no banner login' in result.commands" # does this break due to "contains?" + +- name: remove login (idempotent) + net_banner: + banner: login + state: absent + authorize: yes + provider: "{{ cli }}" + register: result + +- assert: + that: + - "result.changed == false" + - "result.commands | length == 0" + + +# FIXME add in tests for everything defined in docs +# FIXME Test state:absent + test: +# FIXME Without powers ensure "privileged mode required"