1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

HTTP(S) API connection plugin (#39224)

* HTTPAPI connection

* Punt run_commands to cliconf or httpapi

* Fake enable_mode on eapi

* Pull changes to nxos

* Move load_config to edit_config for future-preparedness

* Don't fail on lldp disabled

* Re-enable check_rc on nxos' run_commands

* Reorganize nxos httpapi plugin for compatibility

* draft docs for connection: httpapi

* restores docs for connection:local for eapi

* Add _remote_is_local to httpapi
This commit is contained in:
Nathaniel Case 2018-05-17 18:47:15 -04:00 committed by GitHub
parent cc61c86049
commit e9d7fa0418
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
277 changed files with 1325 additions and 1676 deletions

View file

@ -11,11 +11,7 @@ Execution on the Control Node
Unlike most Ansible modules, network modules do not run on the managed nodes. From a user's point of view, network modules work like any other modules. They work with ad-hoc commands, playbooks, and roles. Behind the scenes, however, network modules use a different methodology than the other (Linux/Unix and Windows) modules use. Ansible is written and executed in Python. Because the majority of network devices can not run Python, the Ansible network modules are executed on the Ansible control node, where ``ansible`` or ``ansible-playbook`` runs. Unlike most Ansible modules, network modules do not run on the managed nodes. From a user's point of view, network modules work like any other modules. They work with ad-hoc commands, playbooks, and roles. Behind the scenes, however, network modules use a different methodology than the other (Linux/Unix and Windows) modules use. Ansible is written and executed in Python. Because the majority of network devices can not run Python, the Ansible network modules are executed on the Ansible control node, where ``ansible`` or ``ansible-playbook`` runs.
Execution on the control node shapes two other differences in how network modules function: Network modules also use the control node as a destination for backup files, for those modules that offer a ``backup`` option. With Linux/Unix modules, where a configuration file already exists on the managed node(s), the backup file gets written by default in the same directory as the new, changed file. Network modules do not update configuration files on the managed nodes, because network configuration is not written in files. Network modules write backup files on the control node, usually in the `backup` directory under the playbook root directory.
- Network modules do not run every task in a playbook. They request current config first, compare current config to the state described by the task or playbook, and execute a task only if it changes the state of the managed node.
- Network modules that offer a backup option write the backup files onto the control node. With Linux/Unix modules, where a configuration file already exists on the managed node(s), the backup file gets written by default in the same directory as the new, changed file. Network modules do not update configuration files on the managed nodes, because network configuration is not written in files. Network modules write backup files on the control node, in the `backup` directory under the playbook root directory.
Multiple Communication Protocols Multiple Communication Protocols
================================================================================ ================================================================================
@ -23,14 +19,15 @@ Multiple Communication Protocols
Because network modules execute on the control node instead of on the managed nodes, they can support multiple communication protocols. The communication protocol (XML over SSH, CLI over SSH, API over HTTPS) selected for each network module depends on the platform and the purpose of the module. Some network modules support only one protocol; some offer a choice. The most common protocol is CLI over SSH. You set the communication protocol with the ``ansible_connection`` variable: Because network modules execute on the control node instead of on the managed nodes, they can support multiple communication protocols. The communication protocol (XML over SSH, CLI over SSH, API over HTTPS) selected for each network module depends on the platform and the purpose of the module. Some network modules support only one protocol; some offer a choice. The most common protocol is CLI over SSH. You set the communication protocol with the ``ansible_connection`` variable:
.. csv-table:: .. csv-table::
:header: "Value of ansible_connection", "Protocol", "Requires" :header: "Value of ansible_connection", "Protocol", "Requires", "Persistent?"
:widths: 30, 10, 10 :widths: 30, 10, 10, 10
"network_cli", "CLI over SSH", "network_os setting" "network_cli", "CLI over SSH", "network_os setting", "yes"
"netconf", "XML over SSH", "network_os setting" "netconf", "XML over SSH", "network_os setting", "yes"
"local", "depends on provider", "provider setting" "httpapi", "API over HTTP/HTTPS", "network_os setting", "yes"
"local", "depends on provider", "provider setting", "no"
Beginning with Ansible 2.5, we recommend using ``network_cli`` or ``netconf`` for ``ansible_connection`` whenever possible. For details on using API over HTTPS connections, see the :ref:`platform-specific <platform_options>` pages. Beginning with Ansible 2.6, we recommend using one of the persistent connection types listed above instead of ``local``. With persistent connections, you can define the hosts and credentials only once, rather than in every task. For more details on using each connection type on various platforms, see the :ref:`platform-specific <platform_options>` pages.
Modules Organized by Network Platform Modules Organized by Network Platform
@ -46,12 +43,15 @@ A network platform is a set of network devices with a common operating system th
All modules within a network platform share certain requirements. Some network platforms have specific differences - see the :ref:`platform-specific <platform_options>` documentation for details. All modules within a network platform share certain requirements. Some network platforms have specific differences - see the :ref:`platform-specific <platform_options>` documentation for details.
Privilege Escalation: `authorize` and `become` Privilege Escalation: ``enable`` mode, ``become``, and ``authorize``
================================================================================ ================================================================================
Several network platforms support privilege escalation, where certain tasks must be done by a privileged user. This is generally known as ``enable`` mode (the equivalent of ``sudo`` in \*nix administration). Ansible network modules offer privilege escalation for those network devices that support it. However, different platforms use privilege escalation in different ways. Several network platforms support privilege escalation, where certain tasks must be done by a privileged user. On network devices this is called ``enable`` mode (the equivalent of ``sudo`` in \*nix administration). Ansible network modules offer privilege escalation for those network devices that support it. For details of which platforms support ``enable`` mode, with examples of how to use it, see the :ref:`platform-specific <platform_options>` documentation.
Network platforms that support ``connection: network_cli`` and privilege escalation use the top-level Ansible parameter ``become: yes`` with ``become_method: enable``. For modules in these platforms, a ``group_vars`` file would look like: Using ``become`` for privilege escalation
-----------------------------------------
As of Ansible 2.6, you can use the top-level Ansible parameter ``become: yes`` with ``become_method: enable`` to run a task, play, or playbook with escalated privileges on any network platform that supports privilege escalation. You must use either ``connection: network_cli`` or ``connection: httpapi`` with ``become: yes`` with ``become_method: enable``. If you are using ``network_cli`` to connect Ansible to your network devices, a ``group_vars`` file would look like:
.. code-block:: yaml .. code-block:: yaml
@ -60,9 +60,10 @@ Network platforms that support ``connection: network_cli`` and privilege escalat
ansible_become: yes ansible_become: yes
ansible_become_method: enable ansible_become_method: enable
We recommend using ``network_cli`` connections whenever possible. Legacy playbooks: ``authorize`` for privilege escalation
-----------------------------------------------------------------
Some network platforms support privilege escalation but cannot use ``network_cli`` connections yet. This includes all platforms in older versions of Ansible (< 2.5) and HTTPS connections using ``eapi`` in version 2.5. With these connections, you must use a ``provider`` dictionary and include ``authorize: yes`` and ``auth_pass: my_enable_password``. For that use case, a ``group_vars`` file looks like: If you are running Ansible 2.5 or older, some network platforms support privilege escalation but not ``network_cli`` or ``httpapi`` connections. This includes all platforms in versions 2.4 and older, and HTTPS connections using ``eapi`` in version 2.5. With a ``local`` connection, you must use a ``provider`` dictionary and include ``authorize: yes`` and ``auth_pass: my_enable_password``. For that use case, a ``group_vars`` file looks like:
.. code-block:: yaml .. code-block:: yaml
@ -76,7 +77,7 @@ Some network platforms support privilege escalation but cannot use ``network_cli
transport: eapi transport: eapi
use_ssl: no use_ssl: no
And you use the ``eapi`` variable in your play(s) or task(s): And you use the ``eapi`` variable in your task(s):
.. code-block:: yaml .. code-block:: yaml
@ -91,4 +92,6 @@ And you use the ``eapi`` variable in your play(s) or task(s):
state: present state: present
provider: "{{ eapi }}" provider: "{{ eapi }}"
Note that while Ansible 2.6 supports the use of ``connection: local`` with ``provider`` dictionaries, this usage will be deprecated in future and eventually removed.
For more information, see :ref:`Become and Networks<become-network>` For more information, see :ref:`Become and Networks<become-network>`

View file

@ -11,27 +11,35 @@ Arista EOS supports multiple connections. This page offers details on how each c
Connections Available Connections Available
================================================================================ ================================================================================
+---------------------------+-----------------------------------------------+-----------------------------------------+ +---------------------------+-----------------------------------------------+---------------------------------------------+
|.. | CLI | eAPI | |.. | CLI | eAPI |
+===========================+===============================================+=========================================+ +===========================+===============================================+=============================================+
| **Protocol** | SSH | HTTP(S) | | **Protocol** | SSH | HTTP(S) |
+---------------------------+-----------------------------------------------+-----------------------------------------+ +---------------------------+-----------------------------------------------+---------------------------------------------+
| | **Credentials** | | uses SSH keys / SSH-agent if present | | uses HTTPS certificates if present | | | **Credentials** | | uses SSH keys / SSH-agent if present | | uses HTTPS certificates if present |
| | | | accepts ``-u myuser -k`` if using password | | | | | | | accepts ``-u myuser -k`` if using password | | |
+---------------------------+-----------------------------------------------+-----------------------------------------+ +---------------------------+-----------------------------------------------+---------------------------------------------+
| **Indirect Access** | via a bastion (jump host) | via a web proxy | | **Indirect Access** | via a bastion (jump host) | via a web proxy |
+---------------------------+-----------------------------------------------+-----------------------------------------+ +---------------------------+-----------------------------------------------+---------------------------------------------+
| | **Connection Settings** | | ``ansible_connection: network_cli`` | | ``ansible_connection: local`` | | | **Connection Settings** | | ``ansible_connection: network_cli`` | | ``ansible_connection: httpapi`` |
| | | | | | Requires ``transport: eapi`` | | | | | | | OR |
| | | | | | in the ``provider`` dictionary | | | | | | | ``ansible_connection: local`` |
+---------------------------+-----------------------------------------------+-----------------------------------------+ | | | | | | with ``transport: eapi`` |
| | **Enable Mode** | | supported - use ``ansible_become: yes`` | | supported - use ``authorize: yes`` | | | | | | | in the ``provider`` dictionary |
| | (Privilege Escalation) | | with ``ansible_become_method: enable`` | | and ``auth_pass:`` in the | +---------------------------+-----------------------------------------------+---------------------------------------------+
| | | | and ``ansible_become_pass:`` | | ``provider`` dictionary | | | **Enable Mode** | | supported - use ``ansible_become: yes`` | | supported: |
+---------------------------+-----------------------------------------------+-----------------------------------------+ | | (Privilege Escalation) | | with ``ansible_become_method: enable`` | | ``httpapi`` |
| **Returned Data Format** | ``stdout[0].`` | ``stdout[0].messages[0].`` | | | | | | | uses ``ansible_become: yes`` |
+---------------------------+-----------------------------------------------+-----------------------------------------+ | | | | | | with ``ansible_become_method: enable`` |
| | | | | | ``local`` |
| | | | | | uses ``authorize: yes`` |
| | | | | | and ``auth_pass:`` |
| | | | | | in the ``provider`` dictionary |
+---------------------------+-----------------------------------------------+---------------------------------------------+
| **Returned Data Format** | ``stdout[0].`` | ``stdout[0].messages[0].`` |
+---------------------------+-----------------------------------------------+---------------------------------------------+
For legacy playbooks, EOS still supports ``ansible_connection: local``. We recommend modernizing to use ``ansible_connection: network_cli`` or ``ansible_connection: httpapi`` as soon as possible.
Using CLI in Ansible 2.5 Using CLI in Ansible 2.5
================================================================================ ================================================================================
@ -86,13 +94,47 @@ Before you can use eAPI to connect to a switch, you must enable eAPI. To enable
become_method: enable become_method: enable
when: ansible_network_os == 'eos' when: ansible_network_os == 'eos'
You can find more options for enabling HTTP/HTTPS and local http in the :ref:`eos_eapi <eos_eapi_module>` module documentation. You can find more options for enabling HTTP/HTTPS connections in the :ref:`eos_eapi <eos_eapi_module>` module documentation.
Once eAPI is enabled, change your ``group_vars/eos.yml`` to use the eAPI connection. Once eAPI is enabled, change your ``group_vars/eos.yml`` to use the eAPI connection.
Example eAPI ``group_vars/eos.yml`` Example eAPI ``group_vars/eos.yml``
----------------------------------- -----------------------------------
.. code-block:: yaml
ansible_connection: httpapi
ansible_network_os: eos
ansible_user: myuser
ansible_ssh_pass: !vault...
become: yes
become_method: enable
proxy_env:
http_proxy: http://proxy.example.com:8080
- If you are accessing your host directly (not through a web proxy) you can remove the ``proxy_env`` configuration.
- If you are accessing your host through a web proxy using ``https``, change ``http_proxy`` to ``https_proxy``.
Example eAPI Task
-----------------
.. code-block:: yaml
- name: Backup current switch config (eos)
eos_config:
backup: yes
register: backup_eos_location
environment: "{{ proxy_env }}"
when: ansible_network_os == 'eos'
In this example the ``proxy_env`` variable defined in ``group_vars`` gets passed to the ``environment`` option of the module in the task.
eAPI examples with ``connection: local``
-----------------------------------------
``group_vars/eos.yml``:
.. code-block:: yaml .. code-block:: yaml
ansible_connection: local ansible_connection: local
@ -107,12 +149,7 @@ Example eAPI ``group_vars/eos.yml``
proxy_env: proxy_env:
http_proxy: http://proxy.example.com:8080 http_proxy: http://proxy.example.com:8080
- If you are accessing your host directly (not through a web proxy) you can remove the ``proxy_env`` configuration. eAPI task:
- If you are accessing your host through a web proxy using ``https``, change ``http_proxy`` to ``https_proxy``.
Example eAPI Task
-----------------
.. code-block:: yaml .. code-block:: yaml
@ -129,5 +166,4 @@ In this example two variables defined in ``group_vars`` get passed to the module
- the ``eapi`` variable gets passed to the ``provider`` option of the module - the ``eapi`` variable gets passed to the ``provider`` option of the module
- the ``proxy_env`` variable gets passed to the ``environment`` option of the module - the ``proxy_env`` variable gets passed to the ``environment`` option of the module
.. include:: shared_snippets/SSH_warning.rst .. include:: shared_snippets/SSH_warning.rst

View file

@ -4,7 +4,7 @@
Platform Options Platform Options
**************** ****************
Some Ansible Network platforms support multiple connection types, privilege escalation, or other options. The pages in this section offer standardized guides to understanding available options on each network platform. We welcome contributions from community-maintained platforms to this section. Some Ansible Network platforms support multiple connection types, privilege escalation (``enable`` mode), or other options. The pages in this section offer standardized guides to understanding available options on each network platform. We welcome contributions from community-maintained platforms to this section.
.. toctree:: .. toctree::
:maxdepth: 2 :maxdepth: 2

View file

@ -21,9 +21,7 @@ Connections Available
+---------------------------+-----------------------------------------------+-----------------------------------------+ +---------------------------+-----------------------------------------------+-----------------------------------------+
| **Indirect Access** | via a bastion (jump host) | via a web proxy | | **Indirect Access** | via a bastion (jump host) | via a web proxy |
+---------------------------+-----------------------------------------------+-----------------------------------------+ +---------------------------+-----------------------------------------------+-----------------------------------------+
| | **Connection Settings** | | ``ansible_connection: network_cli`` | | ``ansible_connection: local`` | | | **Connection Settings** | | ``ansible_connection: network_cli`` | | ``ansible_connection: httpapi`` |
| | | | | | Requires ``transport: nxapi`` |
| | | | | | in the ``provider`` dictionary |
+---------------------------+-----------------------------------------------+-----------------------------------------+ +---------------------------+-----------------------------------------------+-----------------------------------------+
| | **Enable Mode** | | supported - use ``ansible_become: yes`` | | not supported by NX-API | | | **Enable Mode** | | supported - use ``ansible_become: yes`` | | not supported by NX-API |
| | (Privilege Escalation) | | with ``ansible_become_method: enable`` | | | | | (Privilege Escalation) | | with ``ansible_become_method: enable`` | | |
@ -32,6 +30,7 @@ Connections Available
| **Returned Data Format** | ``stdout[0].`` | ``stdout[0].messages[0].`` | | **Returned Data Format** | ``stdout[0].`` | ``stdout[0].messages[0].`` |
+---------------------------+-----------------------------------------------+-----------------------------------------+ +---------------------------+-----------------------------------------------+-----------------------------------------+
For legacy playbooks, NXOS still supports ``ansible_connection: local``. We recommend modernizing to use ``ansible_connection: network_cli`` or ``ansible_connection: httpapi`` as soon as possible.
Using CLI in Ansible 2.5 Using CLI in Ansible 2.5
================================================================================ ================================================================================
@ -93,13 +92,10 @@ Example NX-API ``group_vars/nxos.yml``
.. code-block:: yaml .. code-block:: yaml
ansible_connection: local ansible_connection: httpapi
ansible_network_os: nxos ansible_network_os: nxos
ansible_user: myuser ansible_user: myuser
ansible_ssh_pass: !vault... ansible_ssh_pass: !vault...
nxapi:
host: "{{ inventory_hostname }}"
transport: nxapi
proxy_env: proxy_env:
http_proxy: http://proxy.example.com:8080 http_proxy: http://proxy.example.com:8080
@ -115,15 +111,10 @@ Example NX-API Task
- name: Backup current switch config (nxos) - name: Backup current switch config (nxos)
nxos_config: nxos_config:
backup: yes backup: yes
provider: "{{ nxapi }}"
register: backup_nxos_location register: backup_nxos_location
environment: "{{ proxy_env }}" environment: "{{ proxy_env }}"
when: ansible_network_os == 'nxos' when: ansible_network_os == 'nxos'
In this example two variables defined in ``group_vars`` get passed to the module of the task: In this example the ``proxy_env`` variable defined in ``group_vars`` gets passed to the ``environment`` option of the module used in the task.
- the ``nxapi`` variable gets passed to the ``provider`` option of the module
- the ``proxy_env`` variable gets passed to the ``environment`` option of the module
.. include:: shared_snippets/SSH_warning.rst .. include:: shared_snippets/SSH_warning.rst

View file

@ -213,15 +213,11 @@ module.
Become and Networks Become and Networks
=================== ===================
As of version 2.6, Ansible supports ``become`` for privilege escalation (entering ``enable`` mode or privileged EXEC mode) on all :ref:`Ansible-maintained platforms<network_supported>` that support ``enable`` mode: `eos``, ``ios``, and ``nxos``. Using ``become`` replaces the ``authorize`` and ``auth_pass`` options in a ``provider`` dictionary.
network_cli and become You must set the connection type to either ``connection: network_cli`` or ``connection: httpapi`` to use ``become`` for privilege escalation on network devices. Check the :ref:`platform_options` and :ref:`network_modules` documentation for details.
----------------------
Ansible 2.5 added support for ``become`` to be used to enter ``enable`` mode (Privileged EXEC mode) on network devices that support it. This replaces the previous ``authorize`` and ``auth_pass`` options in ``provider``. You can use escalated privileges on only the specific tasks that need them, on an entire play, or on all plays. Adding ``become: yes`` and ``become_method: enable`` instructs Ansible to enter ``enable`` mode before executing the task, play, or playbook where those parameters are set.
You must set the host connection type to ``connection: network_cli`` to use ``become`` for privilege escalation on network devices. Ansible 2.5.3 supports ``become`` for privilege escalation on ``eos``, ``ios``, and ``nxos``.
You can use escalated privileges on only the specific tasks that need them, on an entire play, or on all plays. Adding ``become: yes`` and ``become_method: enable`` instructs Ansible to enter ``enable`` mode before executing the task, play, or playbook.
If you see this error message, the task that generated it requires ``enable`` mode to succeed: If you see this error message, the task that generated it requires ``enable`` mode to succeed:
@ -281,13 +277,10 @@ If you need a password to enter ``enable`` mode, you can specify it in one of tw
As a reminder passwords should never be stored in plain text. For information on encrypting your passwords and other secrets with Ansible Vault, see :doc:`playbooks_vault`. As a reminder passwords should never be stored in plain text. For information on encrypting your passwords and other secrets with Ansible Vault, see :doc:`playbooks_vault`.
.. _become-network-auth-and-auth-password:
authorize and auth_pass authorize and auth_pass
----------------------- -----------------------
For HTTPS connections that cannot use ``connection: network_cli``, you can enter ``enable`` mode using the module options ``authorize`` and ``auth_pass``: Ansible still supports ``enable`` mode with ``connection: local`` for legacy playbooks. To enter ``enable`` mode with ``connection: local``, use the module options ``authorize`` and ``auth_pass``:
.. code-block:: yaml .. code-block:: yaml
@ -302,7 +295,7 @@ For HTTPS connections that cannot use ``connection: network_cli``, you can enter
authorize: yes authorize: yes
auth_pass: " {{ secret_auth_pass }}" auth_pass: " {{ secret_auth_pass }}"
Note that over time more platforms and connections will support ``become``. As this happens, the use of ``authorize`` and of ``provider`` dictionaries will be deprecated. Check the :ref:`platform_options` and :ref:`network_modules` documentation for details. We recommend updating your playbooks to use ``become`` for network-device ``enable`` mode consistently. The use of ``authorize`` and of ``provider`` dictionaries will be deprecated in future. Check the :ref:`platform_options` and :ref:`network_modules` documentation for details.
.. _become-windows: .. _become-windows:

View file

@ -655,6 +655,14 @@ DEFAULT_HOST_LIST:
section: defaults section: defaults
type: pathlist type: pathlist
yaml: {key: defaults.inventory} yaml: {key: defaults.inventory}
DEFAULT_HTTPAPI_PLUGIN_PATH:
name: HttpApi Plugins Path
default: ~/.ansible/plugins/httpapi:/usr/share/ansible/plugins/httpapi
description: Colon separated paths in which Ansible will search for HttpApi Plugins.
env: [{name: ANSIBLE_HTTPAPI_PLUGINS}]
ini:
- {key: httpapi_plugins, section: defaults}
type: pathspec
DEFAULT_INTERNAL_POLL_INTERVAL: DEFAULT_INTERNAL_POLL_INTERVAL:
name: Internal poll interval name: Internal poll interval
default: 0.001 default: 0.001

View file

@ -163,46 +163,8 @@ class Cli:
def run_commands(self, commands, check_rc=True): def run_commands(self, commands, check_rc=True):
"""Run list of commands on remote device and return results """Run list of commands on remote device and return results
""" """
responses = list()
connection = self._get_connection() connection = self._get_connection()
return connection.run_commands(commands, check_rc)
for cmd in to_list(commands):
if isinstance(cmd, dict):
command = cmd['command']
prompt = cmd['prompt']
answer = cmd['answer']
else:
command = cmd
prompt = None
answer = None
out = connection.get(command, prompt, answer)
out = to_text(out, errors='surrogate_or_strict')
try:
out = self._module.from_json(out)
except ValueError:
out = str(out).strip()
responses.append(out)
return responses
def send_config(self, commands):
conn = self._get_connection()
multiline = False
rc = 0
for command in to_list(commands):
if command == 'end':
continue
if command.startswith('banner') or multiline:
multiline = True
elif command == 'EOF' and multiline:
multiline = False
conn.get(command, None, None, multiline)
def configure(self, commands): def configure(self, commands):
"""Sends configuration commands to the remote device """Sends configuration commands to the remote device
@ -239,32 +201,12 @@ class Cli:
return result return result
conn = self._get_connection() conn = self._get_connection()
session = 'ansible_%s' % int(time.time())
result = {'session': session}
out = conn.get('configure session %s' % session)
if replace:
out = conn.get('rollback clean-config')
try: try:
self.send_config(commands) return conn.load_config(commands, commit, replace)
except ConnectionError as exc: except ConnectionError as exc:
self.close_session(session)
message = getattr(exc, 'err', exc) message = getattr(exc, 'err', exc)
self._module.fail_json(msg="Error on executing commands %s" % commands, data=to_text(message, errors='surrogate_then_replace')) self._module.fail_json(msg="Error on executing commands %s" % commands, data=to_text(message, errors='surrogate_then_replace'))
out = conn.get('show session-config diffs')
if out:
result['diff'] = to_text(out, errors='surrogate_then_replace').strip()
if commit:
conn.get('commit')
else:
self.close_session(session)
return result
class Eapi: class Eapi:

View file

@ -146,47 +146,8 @@ class Cli:
def run_commands(self, commands, check_rc=True): def run_commands(self, commands, check_rc=True):
"""Run list of commands on remote device and return results """Run list of commands on remote device and return results
""" """
responses = list()
connection = self._get_connection() connection = self._get_connection()
return connection.run_commands(commands, check_rc)
for item in to_list(commands):
if item['output'] == 'json' and not is_json(item['command']):
cmd = '%s | json' % item['command']
elif item['output'] == 'text' and is_json(item['command']):
cmd = item['command'].rsplit('|', 1)[0]
else:
cmd = item['command']
out = ''
try:
out = connection.get(cmd)
code = 0
except ConnectionError as e:
code = getattr(e, 'code', 1)
message = getattr(e, 'err', e)
err = to_text(message, errors='surrogate_then_replace')
try:
out = to_text(out, errors='surrogate_or_strict')
except UnicodeError:
self._module.fail_json(msg=u'Failed to decode output from %s: %s' % (cmd, to_text(out)))
if check_rc and code != 0:
self._module.fail_json(msg=err)
if not check_rc and code != 0:
try:
out = self._module.from_json(err)
except ValueError:
out = to_text(message).strip()
else:
try:
out = self._module.from_json(out)
except ValueError:
out = to_text(out).strip()
responses.append(out)
return responses
def load_config(self, config, return_error=False, opts=None): def load_config(self, config, return_error=False, opts=None):
"""Sends configuration commands to the remote device """Sends configuration commands to the remote device

View file

@ -258,7 +258,8 @@ class Interfaces(FactsBase):
self.facts['interfaces'] = self.populate_interfaces(data) self.facts['interfaces'] = self.populate_interfaces(data)
data = self.responses[1] data = self.responses[1]
self.facts['neighbors'] = self.populate_neighbors(data['lldpNeighbors']) if data:
self.facts['neighbors'] = self.populate_neighbors(data['lldpNeighbors'])
def populate_interfaces(self, data): def populate_interfaces(self, data):
facts = dict() facts = dict()

View file

@ -43,13 +43,13 @@ class ActionModule(_ActionModule):
socket_path = None socket_path = None
if self._play_context.connection == 'network_cli': if self._play_context.connection in ('network_cli', 'httpapi'):
provider = self._task.args.get('provider', {}) provider = self._task.args.get('provider', {})
if any(provider.values()): if any(provider.values()):
display.warning('provider is unnecessary when using network_cli and will be ignored') display.warning('provider is unnecessary when using %s and will be ignored' % self._play_context.connection)
del self._task.args['provider'] del self._task.args['provider']
if self._task.args.get('transport'): if self._task.args.get('transport'):
display.warning('transport is unnecessary when using network_cli and will be ignored') display.warning('transport is unnecessary when using %s and will be ignored' % self._play_context.connection)
del self._task.args['transport'] del self._task.args['transport']
elif self._play_context.connection == 'local': elif self._play_context.connection == 'local':
provider = load_provider(eos_provider_spec, self._task.args) provider = load_provider(eos_provider_spec, self._task.args)

View file

@ -43,16 +43,17 @@ class ActionModule(_ActionModule):
socket_path = None socket_path = None
if self._task.args.get('provider', {}).get('transport') == 'nxapi' and self._task.action == 'nxos_nxapi': if (self._play_context.connection == 'httpapi' or self._task.args.get('provider', {}).get('transport') == 'nxapi') \
and self._task.action == 'nxos_nxapi':
return {'failed': True, 'msg': "Transport type 'nxapi' is not valid for '%s' module." % (self._task.action)} return {'failed': True, 'msg': "Transport type 'nxapi' is not valid for '%s' module." % (self._task.action)}
if self._play_context.connection == 'network_cli': if self._play_context.connection in ('network_cli', 'httpapi'):
provider = self._task.args.get('provider', {}) provider = self._task.args.get('provider', {})
if any(provider.values()): if any(provider.values()):
display.warning('provider is unnecessary when using network_cli and will be ignored') display.warning('provider is unnecessary when using %s and will be ignored' % self._play_context.connection)
del self._task.args['provider'] del self._task.args['provider']
if self._task.args.get('transport'): if self._task.args.get('transport'):
display.warning('transport is unnecessary when using network_cli and will be ignored') display.warning('transport is unnecessary when using %s and will be ignored' % self._play_context.connection)
del self._task.args['transport'] del self._task.args['transport']
elif self._play_context.connection == 'local': elif self._play_context.connection == 'local':
provider = load_provider(nxos_provider_spec, self._task.args) provider = load_provider(nxos_provider_spec, self._task.args)

View file

@ -20,15 +20,37 @@ from __future__ import (absolute_import, division, print_function)
__metaclass__ = type __metaclass__ = type
import json import json
import time
from itertools import chain from itertools import chain
from ansible.module_utils._text import to_bytes
from ansible.module_utils.network.common.utils import to_list from ansible.module_utils.network.common.utils import to_list
from ansible.plugins.cliconf import CliconfBase, enable_mode from ansible.plugins.cliconf import CliconfBase, enable_mode
from ansible.plugins.connection.network_cli import Connection as NetworkCli
class Cliconf(CliconfBase): class Cliconf(CliconfBase):
def send_command(self, command, prompt=None, answer=None, sendonly=False, newline=True, prompt_retry_check=False):
"""Executes a cli command and returns the results
This method will execute the CLI command on the connection and return
the results to the caller. The command output will be returned as a
string
"""
kwargs = {'command': to_bytes(command), 'sendonly': sendonly,
'newline': newline, 'prompt_retry_check': prompt_retry_check}
if prompt is not None:
kwargs['prompt'] = to_bytes(prompt)
if answer is not None:
kwargs['answer'] = to_bytes(answer)
if isinstance(self._connection, NetworkCli):
resp = self._connection.send(**kwargs)
else:
resp = self._connection.send_request(command, **kwargs)
return resp
def get_device_info(self): def get_device_info(self):
device_info = {} device_info = {}
@ -74,3 +96,72 @@ class Cliconf(CliconfBase):
result['network_api'] = 'cliconf' result['network_api'] = 'cliconf'
result['device_info'] = self.get_device_info() result['device_info'] = self.get_device_info()
return json.dumps(result) return json.dumps(result)
# Imported from module_utils
def close_session(self, session):
# to close session gracefully execute abort in top level session prompt.
self.get('end')
self.get('configure session %s' % session)
self.get('abort')
def run_commands(self, commands, check_rc=True):
"""Run list of commands on remote device and return results
"""
responses = list()
multiline = False
for cmd in to_list(commands):
if isinstance(cmd, dict):
command = cmd['command']
prompt = cmd['prompt']
answer = cmd['answer']
else:
command = cmd
prompt = None
answer = None
if command == 'end':
continue
elif command.startswith('banner') or multiline:
multiline = True
elif command == 'EOF' and multiline:
multiline = False
out = self.get(command, prompt, answer, multiline)
if out is not None:
try:
out = json.loads(out)
except ValueError:
out = str(out).strip()
responses.append(out)
return responses
def load_config(self, commands, commit=False, replace=False):
"""Loads the config commands onto the remote device
"""
session = 'ansible_%s' % int(time.time())
result = {'session': session}
self.get('configure session %s' % session)
if replace:
self.get('rollback clean-config')
try:
self.run_commands(commands)
except ConnectionError:
self.close_session(session)
raise
out = self.get('show session-config diffs')
if out:
result['diff'] = out.strip()
if commit:
self.get('commit')
else:
self.close_session(session)
return result

View file

@ -23,12 +23,33 @@ import json
from itertools import chain from itertools import chain
from ansible.module_utils._text import to_bytes, to_text
from ansible.module_utils.network.common.utils import to_list from ansible.module_utils.network.common.utils import to_list
from ansible.plugins.cliconf import CliconfBase from ansible.plugins.cliconf import CliconfBase
from ansible.plugins.connection.network_cli import Connection as NetworkCli
class Cliconf(CliconfBase): class Cliconf(CliconfBase):
def send_command(self, command, prompt=None, answer=None, sendonly=False, newline=True, prompt_retry_check=False):
"""Executes a cli command and returns the results
This method will execute the CLI command on the connection and return
the results to the caller. The command output will be returned as a
string
"""
kwargs = {'command': to_bytes(command), 'sendonly': sendonly,
'newline': newline, 'prompt_retry_check': prompt_retry_check}
if prompt is not None:
kwargs['prompt'] = to_bytes(prompt)
if answer is not None:
kwargs['answer'] = to_bytes(answer)
if isinstance(self._connection, NetworkCli):
resp = self._connection.send(**kwargs)
else:
resp = self._connection.send_request(command, **kwargs)
return resp
def get_device_info(self): def get_device_info(self):
device_info = {} device_info = {}
@ -76,3 +97,37 @@ class Cliconf(CliconfBase):
result['network_api'] = 'cliconf' result['network_api'] = 'cliconf'
result['device_info'] = self.get_device_info() result['device_info'] = self.get_device_info()
return json.dumps(result) return json.dumps(result)
# Migrated from module_utils
def run_commands(self, commands, check_rc=True):
"""Run list of commands on remote device and return results
"""
responses = list()
for item in to_list(commands):
if item['output'] == 'json' and not item['command'].endswith('| json'):
cmd = '%s | json' % item['command']
elif item['output'] == 'text' and item['command'].endswith('| json'):
cmd = item['command'].rsplit('|', 1)[0]
else:
cmd = item['command']
try:
out = self.get(cmd)
except ConnectionError as e:
if check_rc:
raise
out = e
try:
out = to_text(out, errors='surrogate_or_strict').strip()
except UnicodeError:
raise ConnectionError(msg=u'Failed to decode output from %s: %s' % (cmd, to_text(out)))
try:
out = json.loads(out)
except ValueError:
pass
responses.append(out)
return responses

View file

@ -0,0 +1,303 @@
# (c) 2018 Red Hat Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
DOCUMENTATION = """
---
author: Ansible Networking Team
connection: httpapi
short_description: Use httpapi to run command on network appliances
description:
- This connection plugin provides a connection to remote devices over a
HTTP(S)-based api.
version_added: "2.6"
options:
host:
description:
- Specifies the remote device FQDN or IP address to establish the SSH
connection to.
default: inventory_hostname
vars:
- name: ansible_host
port:
type: int
description:
- Specifies the port on the remote device to listening for connections
when establishing the SSH connection.
ini:
- section: defaults
key: remote_port
env:
- name: ANSIBLE_REMOTE_PORT
vars:
- name: ansible_port
network_os:
description:
- Configures the device platform network operating system. This value is
used to load the correct httpapi and cliconf plugins to communicate
with the remote device
vars:
- name: ansible_network_os
remote_user:
description:
- The username used to authenticate to the remote device when the API
connection is first established. If the remote_user is not specified,
the connection will use the username of the logged in user.
- Can be configured form the CLI via the C(--user) or C(-u) options
ini:
- section: defaults
key: remote_user
env:
- name: ANSIBLE_REMOTE_USER
vars:
- name: ansible_user
password:
description:
- Secret used to authenticate
vars:
- name: ansible_password
- name: ansible_httpapi_pass
use_ssl:
description:
- Whether to connect using SSL (HTTPS) or not (HTTP)
default: False
vars:
- name: ansible_httpapi_use_ssl
timeout:
type: int
description:
- Sets the connection time, in seconds, for the communicating with the
remote device. This timeout is used as the default timeout value for
commands when issuing a command to the network CLI. If the command
does not return in timeout seconds, the an error is generated.
default: 120
become:
type: boolean
description:
- The become option will instruct the CLI session to attempt privilege
escalation on platforms that support it. Normally this means
transitioning from user mode to C(enable) mode in the CLI session.
If become is set to True and the remote device does not support
privilege escalation or the privilege has already been elevated, then
this option is silently ignored
- Can be configured form the CLI via the C(--become) or C(-b) options
default: False
ini:
section: privilege_escalation
key: become
env:
- name: ANSIBLE_BECOME
vars:
- name: ansible_become
become_method:
description:
- This option allows the become method to be specified in for handling
privilege escalation. Typically the become_method value is set to
C(enable) but could be defined as other values.
default: sudo
ini:
section: privilege_escalation
key: become_method
env:
- name: ANSIBLE_BECOME_METHOD
vars:
- name: ansible_become_method
persistent_connect_timeout:
type: int
description:
- Configures, in seconds, the amount of time to wait when trying to
initially establish a persistent connection. If this value expires
before the connection to the remote device is completed, the connection
will fail
default: 30
ini:
section: persistent_connection
key: persistent_connect_timeout
env:
- name: ANSIBLE_PERSISTENT_CONNECT_TIMEOUT
persistent_command_timeout:
type: int
description:
- Configures, in seconds, the amount of time to wait for a command to
return from the remote device. If this timer is exceeded before the
command returns, the connection plugin will raise an exception and
close
default: 10
ini:
section: persistent_connection
key: persistent_command_timeout
env:
- name: ANSIBLE_PERSISTENT_COMMAND_TIMEOUT
"""
import os
from ansible import constants as C
from ansible.errors import AnsibleConnectionFailure
from ansible.module_utils._text import to_bytes
from ansible.module_utils.six import PY3
from ansible.module_utils.six.moves import cPickle
from ansible.module_utils.urls import open_url
from ansible.playbook.play_context import PlayContext
from ansible.plugins.loader import cliconf_loader, connection_loader, httpapi_loader
from ansible.plugins.connection import ConnectionBase
from ansible.utils.path import unfrackpath
try:
from __main__ import display
except ImportError:
from ansible.utils.display import Display
display = Display()
class Connection(ConnectionBase):
'''Network API connection'''
transport = 'httpapi'
has_pipelining = True
force_persistence = True
# Do not use _remote_is_local in other connections
_remote_is_local = True
def __init__(self, play_context, new_stdin, *args, **kwargs):
super(Connection, self).__init__(play_context, new_stdin, *args, **kwargs)
self._matched_prompt = None
self._matched_pattern = None
self._last_response = None
self._history = list()
self._local = connection_loader.get('local', play_context, '/dev/null')
self._local.set_options()
self._cliconf = None
self._ansible_playbook_pid = kwargs.get('ansible_playbook_pid')
network_os = self._play_context.network_os
if not network_os:
raise AnsibleConnectionFailure(
'Unable to automatically determine host network os. Please '
'manually configure ansible_network_os value for this host'
)
self._httpapi = httpapi_loader.get(network_os, self)
if self._httpapi:
display.vvvv('loaded API plugin for network_os %s' % network_os, host=self._play_context.remote_addr)
else:
raise AnsibleConnectionFailure('unable to load API plugin for network_os %s' % network_os)
self._url = None
self._auth = None
# reconstruct the socket_path and set instance values accordingly
self._update_connection_state()
def __getattr__(self, name):
try:
return self.__dict__[name]
except KeyError:
if not name.startswith('_'):
for plugin in (self._httpapi, self._cliconf):
method = getattr(plugin, name, None)
if method:
return method
raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, name))
def exec_command(self, cmd, in_data=None, sudoable=True):
return self._local.exec_command(cmd, in_data, sudoable)
def put_file(self, in_path, out_path):
return self._local.put_file(in_path, out_path)
def fetch_file(self, in_path, out_path):
return self._local.fetch_file(in_path, out_path)
def update_play_context(self, pc_data):
"""Updates the play context information for the connection"""
pc_data = to_bytes(pc_data)
if PY3:
pc_data = cPickle.loads(pc_data, encoding='bytes')
else:
pc_data = cPickle.loads(pc_data)
play_context = PlayContext()
play_context.deserialize(pc_data)
messages = ['updating play_context for connection']
if self._play_context.become is False and play_context.become is True:
self._enable = True
messages.append('authorizing connection')
elif self._play_context.become is True and not play_context.become:
self._enable = False
messages.append('deauthorizing connection')
self._play_context = play_context
return messages
def _connect(self):
if self.connected:
return
network_os = self._play_context.network_os
protocol = 'https' if self.get_option('use_ssl') else 'http'
host = self._play_context.remote_addr
port = self._play_context.port or 443 if protocol == 'https' else 80
self._url = '%s://%s:%s' % (protocol, host, port)
self._cliconf = cliconf_loader.get(network_os, self)
if self._cliconf:
display.vvvv('loaded cliconf plugin for network_os %s' % network_os, host=self._play_context.remote_addr)
else:
display.vvvv('unable to load cliconf for network_os %s' % network_os)
self._connected = True
def _update_connection_state(self):
'''
Reconstruct the connection socket_path and check if it exists
If the socket path exists then the connection is active and set
both the _socket_path value to the path and the _connected value
to True. If the socket path doesn't exist, leave the socket path
value to None and the _connected value to False
'''
ssh = connection_loader.get('ssh', class_only=True)
cp = ssh._create_control_path(
self._play_context.remote_addr, self._play_context.port,
self._play_context.remote_user, self._play_context.connection,
self._ansible_playbook_pid
)
tmp_path = unfrackpath(C.PERSISTENT_CONTROL_PATH_DIR)
socket_path = unfrackpath(cp % dict(directory=tmp_path))
if os.path.exists(socket_path):
self._connected = True
self._socket_path = socket_path
def reset(self):
'''
Reset the connection
'''
if self._socket_path:
display.vvvv('resetting persistent connection for socket_path %s' % self._socket_path, host=self._play_context.remote_addr)
self.close()
display.vvvv('reset call on connection instance', host=self._play_context.remote_addr)
def close(self):
if self._connected:
self._connected = False
def send(self, path, data, **kwargs):
'''
Sends the command to the device over api
'''
url_kwargs = dict(url_username=self._play_context.remote_user, url_password=self._play_context.password)
url_kwargs.update(kwargs)
response = open_url(self._url + path, data=data, **url_kwargs)
self._auth = response.info().get('Set-Cookie')
return response

View file

View file

@ -0,0 +1,158 @@
# (c) 2018 Red Hat Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import json
import time
from ansible.module_utils._text import to_text
from ansible.module_utils.network.common.utils import to_list
from ansible.module_utils.connection import ConnectionError
try:
from __main__ import display
except ImportError:
from ansible.utils.display import Display
display = Display()
class HttpApi:
def __init__(self, connection):
self.connection = connection
def send_request(self, data, **message_kwargs):
if 'become' in message_kwargs:
display.vvvv('firing event: on_become')
# TODO ??? self._terminal.on_become(passwd=auth_pass)
output = message_kwargs.get('output', 'text')
request = request_builder(data, output)
headers = {'Content-Type': 'application/json-rpc'}
response = self.connection.send('/command-api', request, headers=headers, method='POST')
response = json.loads(to_text(response.read()))
return handle_response(response)
def get_prompt(self):
# Hack to keep @enable_mode working
return '#'
# Imported from module_utils
def edit_config(self, config, commit=False, replace=False):
"""Loads the configuration onto the remote devices
If the device doesn't support configuration sessions, this will
fallback to using configure() to load the commands. If that happens,
there will be no returned diff or session values
"""
session = 'ansible_%s' % int(time.time())
result = {'session': session}
banner_cmd = None
banner_input = []
commands = ['configure session %s' % session]
if replace:
commands.append('rollback clean-config')
for command in config:
if command.startswith('banner'):
banner_cmd = command
banner_input = []
elif banner_cmd:
if command == 'EOF':
command = {'cmd': banner_cmd, 'input': '\n'.join(banner_input)}
banner_cmd = None
commands.append(command)
else:
banner_input.append(command)
continue
else:
commands.append(command)
response = self.send_request(commands)
commands = ['configure session %s' % session, 'show session-config diffs']
if commit:
commands.append('commit')
else:
commands.append('abort')
response = self.send_request(commands, output='text')
diff = response[1].strip()
if diff:
result['diff'] = diff
return result
def run_commands(self, commands, check_rc=True):
"""Runs list of commands on remote device and returns results
"""
output = None
queue = list()
responses = list()
def run_queue(queue, output):
response = to_list(self.send_request(queue, output=output))
if output == 'json':
response = [json.loads(item) for item in response]
return response
for item in to_list(commands):
cmd_output = None
if isinstance(item, dict):
command = item['command']
if command.endswith('| json'):
command = command.replace('| json', '')
cmd_output = 'json'
elif 'output' in item:
cmd_output = item['output']
else:
command = item
cmd_output = 'json'
if output and output != cmd_output:
responses.extend(run_queue(queue, output))
queue = list()
output = cmd_output or 'json'
queue.append(command)
if queue:
responses.extend(run_queue(queue, output))
return responses
def load_config(self, config, commit=False, replace=False):
"""Loads the configuration onto the remote devices
If the device doesn't support configuration sessions, this will
fallback to using configure() to load the commands. If that happens,
there will be no returned diff or session values
"""
return self.edit_config(config, commit, replace)
def handle_response(response):
if 'error' in response:
error = response['error']
raise ConnectionError(error['message'], code=error['code'])
results = []
for result in response['result']:
if 'messages' in result:
results.append(result['messages'][0])
elif 'output' in result:
results.append(result['output'].strip())
else:
results.append(json.dumps(result))
if len(results) == 1:
return results[0]
return results
def request_builder(commands, output, reqid=None):
params = dict(version=1, cmds=to_list(commands), format=output)
return json.dumps(dict(jsonrpc='2.0', id=reqid, method='runCmds', params=params))

View file

@ -0,0 +1,135 @@
# (c) 2018 Red Hat Inc.
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type
import json
from ansible.module_utils._text import to_text
from ansible.module_utils.connection import ConnectionError
from ansible.module_utils.network.common.utils import to_list
try:
from __main__ import display
except ImportError:
from ansible.utils.display import Display
display = Display()
class HttpApi:
def __init__(self, connection):
self.connection = connection
def _run_queue(self, queue, output):
request = request_builder(queue, output)
headers = {'Content-Type': 'application/json'}
response = self.connection.send('/ins', request, headers=headers, method='POST')
response = json.loads(to_text(response.read()))
return handle_response(response)
def send_request(self, data, **message_kwargs):
output = None
queue = list()
responses = list()
for item in to_list(data):
cmd_output = message_kwargs.get('output', 'json')
if isinstance(item, dict):
command = item['command']
if command.endswith('| json'):
command = command.rsplit('|', 1)[0]
cmd_output = 'json'
elif 'output' in item:
cmd_output = item['output']
else:
command = item
if output and output != cmd_output:
responses.extend(self._run_queue(queue, output))
queue = list()
output = cmd_output or 'json'
queue.append(command)
if queue:
responses.extend(self._run_queue(queue, output))
if len(responses) == 1:
return responses[0]
return responses
# Migrated from module_utils
def edit_config(self, command):
responses = self.send_request(command, output='config')
return json.dumps(responses)
def run_commands(self, commands, check_rc=True):
"""Runs list of commands on remote device and returns results
"""
try:
out = self.send_request(commands)
except ConnectionError as exc:
if check_rc:
raise
out = to_text(exc)
out = to_list(out)
for index, response in enumerate(out):
if response[0] == '{':
out[index] = json.loads(response)
return out
def handle_response(response):
results = []
if response['ins_api'].get('outputs'):
for output in to_list(response['ins_api']['outputs']['output']):
if output['code'] != '200':
raise ConnectionError('%s: %s' % (output['input'], output['msg']))
elif 'body' in output:
result = output['body']
if isinstance(result, dict):
result = json.dumps(result)
results.append(result.strip())
return results
def request_builder(commands, output, version='1.0', chunk='0', sid=None):
"""Encodes a NXAPI JSON request message
"""
output_to_command_type = {
'text': 'cli_show_ascii',
'json': 'cli_show',
'bash': 'bash',
'config': 'cli_conf'
}
maybe_output = commands[0].split('|')[-1].strip()
if maybe_output in output_to_command_type:
command_type = output_to_command_type[maybe_output]
commands = [command.split('|')[0].strip() for command in commands]
else:
try:
command_type = output_to_command_type[output]
except KeyError:
msg = 'invalid format, received %s, expected one of %s' % \
(output, ','.join(output_to_command_type.keys()))
raise ConnectionError(msg)
if isinstance(commands, (list, set, tuple)):
commands = ' ;'.join(commands)
msg = {
'version': version,
'type': command_type,
'chunk': chunk,
'sid': sid,
'input': commands,
'output_format': 'json'
}
return json.dumps(dict(ins_api=msg))

View file

@ -762,3 +762,10 @@ inventory_loader = PluginLoader(
C.DEFAULT_INVENTORY_PLUGIN_PATH, C.DEFAULT_INVENTORY_PLUGIN_PATH,
'inventory_plugins' 'inventory_plugins'
) )
httpapi_loader = PluginLoader(
'HttpApi',
'ansible.plugins.httpapi',
C.DEFAULT_HTTPAPI_PLUGIN_PATH,
'httpapi_plugins',
)

View file

@ -14,9 +14,3 @@
with_items: "{{ test_items }}" with_items: "{{ test_items }}"
loop_control: loop_control:
loop_var: test_case_to_run loop_var: test_case_to_run
- name: run test case (connection=local)
include: "{{ test_case_to_run }} ansible_connection=local ansible_become=no"
with_first_found: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run

View file

@ -9,8 +9,8 @@
- name: set test_items - name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test case (connection=local) - name: run test cases (connection=httpapi)
include: "{{ test_case_to_run }} ansible_connection=local" include: "{{ test_case_to_run }} ansible_connection=httpapi"
with_items: "{{ test_items }}" with_items: "{{ test_items }}"
loop_control: loop_control:
loop_var: test_case_to_run loop_var: test_case_to_run

View file

@ -46,7 +46,7 @@
# Ensure sessions contains epoc. Will fail after 18th May 2033 # Ensure sessions contains epoc. Will fail after 18th May 2033
- "result.session_name is not defined" - "result.session_name is not defined"
- name: remove login - name: Remove login
eos_banner: eos_banner:
banner: login banner: login
state: absent state: absent
@ -62,7 +62,7 @@
# Ensure sessions contains epoc. Will fail after 18th May 2033 # Ensure sessions contains epoc. Will fail after 18th May 2033
- "'ansible_1' in result.session_name" - "'ansible_1' in result.session_name"
- name: remove login (idempotent) - name: Remove login again (idempotent)
eos_banner: eos_banner:
banner: login banner: login
state: absent state: absent
@ -78,7 +78,6 @@
# Ensure sessions contains epoc. Will fail after 18th May 2033 # Ensure sessions contains epoc. Will fail after 18th May 2033
- "result.session_name is not defined" - "result.session_name is not defined"
# FIXME add in tests for everything defined in docs # FIXME add in tests for everything defined in docs
# FIXME Test state:absent + test: # FIXME Test state:absent + test:
# FIXME Without powers ensure "privileged mode required" # FIXME Without powers ensure "privileged mode required"

View file

@ -1,4 +1,5 @@
--- ---
- debug: msg="START eapi/basic-login.yaml on connection={{ ansible_connection }}"
- name: Remove previous login banner - name: Remove previous login banner
eos_config: eos_config:
@ -6,7 +7,7 @@
authorize: yes authorize: yes
provider: "{{ eapi }}" provider: "{{ eapi }}"
- name: Set login - name: Create login banner
eos_banner: eos_banner:
banner: login banner: login
text: | text: |
@ -21,12 +22,11 @@
- assert: - assert:
that: that:
- "result.changed == true" - "result.changed == true"
- "result.commands.0.cmd == 'banner login'" - "'banner login' in result.commands[0]" # does this break due to "contains?"
- "result.commands.0.input == 'this is my login banner\nthat has a multiline\nstring'"
# Ensure sessions contains epoc. Will fail after 18th May 2033 # Ensure sessions contains epoc. Will fail after 18th May 2033
- "'ansible_1' in result.session_name" - "'ansible_1' in result.session_name"
- name: Set login again (idempotent) - name: Create login banner again (idempotent)
eos_banner: eos_banner:
banner: login banner: login
text: | text: |
@ -60,7 +60,7 @@
- assert: - assert:
that: that:
- "result.changed == true" - "result.changed == true"
- "result.commands.0.cmd == 'no banner login'" - "'no banner login' in result.commands" # does this break due to "contains?"
# Ensure sessions contains epoc. Will fail after 18th May 2033 # Ensure sessions contains epoc. Will fail after 18th May 2033
- "'ansible_1' in result.session_name" - "'ansible_1' in result.session_name"

View file

@ -21,8 +21,8 @@
- assert: - assert:
that: that:
- "result.changed == true" - "result.changed == true"
- "result.commands.0.cmd == 'banner motd'" - "'this is my motd banner' in result.commands"
- "result.commands.0.input == 'this is my motd banner\nthat has a multiline\nstring'" - "'that has a multiline' in result.commands"
# Ensure sessions contains epoc. Will fail after 18th May 2033 # Ensure sessions contains epoc. Will fail after 18th May 2033
- "'ansible_1' in result.session_name" - "'ansible_1' in result.session_name"
@ -60,7 +60,7 @@
- assert: - assert:
that: that:
- "result.changed == true" - "result.changed == true"
- "result.commands.0.cmd == 'no banner motd'" - "'no banner motd' in result.commands"
# Ensure sessions contains epoc. Will fail after 18th May 2033 # Ensure sessions contains epoc. Will fail after 18th May 2033
- "'ansible_1' in result.session_name" - "'ansible_1' in result.session_name"

View file

@ -22,8 +22,7 @@
- assert: - assert:
that: that:
- "result.changed == true" - "result.changed == true"
- "result.commands.0.cmd == 'banner motd'" - "'this is my motd banner configure by net_banner' in result.commands"
- "result.commands.0.input == 'this is my motd banner configure by net_banner'"
# Ensure sessions contains epoc. Will fail after 18th May 2033 # Ensure sessions contains epoc. Will fail after 18th May 2033
- "'ansible_1' in result.session_name" - "'ansible_1' in result.session_name"

View file

@ -14,9 +14,3 @@
with_items: "{{ test_items }}" with_items: "{{ test_items }}"
loop_control: loop_control:
loop_var: test_case_to_run loop_var: test_case_to_run
- name: run test case (connection=local)
include: "{{ test_case_to_run }} ansible_connection=local ansible_become=no"
with_first_found: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run

View file

@ -9,8 +9,8 @@
- name: set test_items - name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test case (connection=local) - name: run test cases (connection=httpapi)
include: "{{ test_case_to_run }} ansible_connection=local" include: "{{ test_case_to_run }} ansible_connection=httpapi"
with_items: "{{ test_items }}" with_items: "{{ test_items }}"
loop_control: loop_control:
loop_var: test_case_to_run loop_var: test_case_to_run

View file

@ -8,7 +8,6 @@
- show interfaces Management1 | json - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.name foo Management" - "result[1].interfaces.Management1.name foo Management"
provider: "{{ cli }}"
register: result register: result
ignore_errors: yes ignore_errors: yes

View file

@ -5,11 +5,10 @@
eos_command: eos_command:
commands: commands:
- show version - show version
- show interface Management1 | json - show interfaces Management1 | json
wait_for: wait_for:
- "result[0] contains EOS" - "result[0] contains EOS"
- "result[1].interfaces.Management1.name contains Manage" - "result[1].interfaces.Management1.name contains Manage"
provider: "{{ cli }}"
register: result register: result
- assert: - assert:

View file

@ -8,7 +8,6 @@
- show interfaces Management1 | json - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.name eq Management1" - "result[1].interfaces.Management1.name eq Management1"
provider: "{{ cli }}"
register: result register: result
- assert: - assert:
@ -23,7 +22,6 @@
- show interfaces Management1 | json - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.name == Management1" - "result[1].interfaces.Management1.name == Management1"
provider: "{{ cli }}"
register: result register: result
- assert: - assert:

View file

@ -8,7 +8,6 @@
- show interfaces Management1 | json - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.mtu gt 0" - "result[1].interfaces.Management1.mtu gt 0"
provider: "{{ cli }}"
register: result register: result
- assert: - assert:
@ -23,7 +22,6 @@
- show interfaces Management1 | json - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.mtu > 0" - "result[1].interfaces.Management1.mtu > 0"
provider: "{{ cli }}"
register: result register: result
- assert: - assert:

View file

@ -8,7 +8,6 @@
- show interfaces Management1 | json - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.mtu ge 0" - "result[1].interfaces.Management1.mtu ge 0"
provider: "{{ cli }}"
register: result register: result
- assert: - assert:
@ -23,7 +22,6 @@
- show interfaces Management1 | json - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.mtu >= 0" - "result[1].interfaces.Management1.mtu >= 0"
provider: "{{ cli }}"
register: result register: result
- assert: - assert:

View file

@ -4,7 +4,6 @@
- name: run invalid command - name: run invalid command
eos_command: eos_command:
commands: ['show foo'] commands: ['show foo']
provider: "{{ cli }}"
register: result register: result
ignore_errors: yes ignore_errors: yes
@ -18,7 +17,6 @@
commands: commands:
- show version - show version
- show foo - show foo
provider: "{{ cli }}"
register: result register: result
ignore_errors: yes ignore_errors: yes

View file

@ -8,7 +8,6 @@
- show interfaces Management1 | json - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.mtu lt 1600" - "result[1].interfaces.Management1.mtu lt 1600"
provider: "{{ cli }}"
register: result register: result
- assert: - assert:
@ -23,7 +22,6 @@
- show interfaces Management1 | json - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.mtu < 1600" - "result[1].interfaces.Management1.mtu < 1600"
provider: "{{ cli }}"
register: result register: result
- assert: - assert:

View file

@ -8,7 +8,6 @@
- show interfaces Management1 | json - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.mtu le 1600" - "result[1].interfaces.Management1.mtu le 1600"
provider: "{{ cli }}"
register: result register: result
- assert: - assert:
@ -23,7 +22,6 @@
- show interfaces Management1 | json - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.mtu <= 1600" - "result[1].interfaces.Management1.mtu <= 1600"
provider: "{{ cli }}"
register: result register: result
- assert: - assert:

View file

@ -8,7 +8,6 @@
- show interfaces Management1 | json - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.name neq Ethernet" - "result[1].interfaces.Management1.name neq Ethernet"
provider: "{{ cli }}"
register: result register: result
- assert: - assert:
@ -23,7 +22,6 @@
- show interfaces Management1 | json - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.name != Ethernet" - "result[1].interfaces.Management1.name != Ethernet"
provider: "{{ cli }}"
register: result register: result
- assert: - assert:

View file

@ -4,7 +4,6 @@
- name: get output for single command - name: get output for single command
eos_command: eos_command:
commands: ['show version'] commands: ['show version']
provider: "{{ cli }}"
register: result register: result
- assert: - assert:
@ -17,7 +16,6 @@
commands: commands:
- show version - show version
- show interfaces - show interfaces
provider: "{{ cli }}"
register: result register: result
- assert: - assert:

View file

@ -7,7 +7,6 @@
- show version - show version
wait_for: wait_for:
- "result[0] contains bad_value_string" - "result[0] contains bad_value_string"
provider: "{{ cli }}"
register: result register: result
ignore_errors: yes ignore_errors: yes

View file

@ -8,7 +8,6 @@
- show interfaces Management1 - show interfaces Management1
wait_for: wait_for:
- "result[1].interfaces.Management1.name foo Management" - "result[1].interfaces.Management1.name foo Management"
provider: "{{ eapi }}"
register: result register: result
ignore_errors: yes ignore_errors: yes

View file

@ -1,15 +1,14 @@
--- ---
- debug: msg="START eapi/contains.yaml" - debug: msg="START eapi/contains.yaml on connection={{ ansible_connection }}"
- name: test contains operator - name: test contains operator
eos_command: eos_command:
commands: commands:
- show version - show version
- show interfaces Management1 - show interfaces Management1 | json
wait_for: wait_for:
- "result[0].modelName contains EOS" - "result[0] contains EOS"
- "result[1].interfaces.Management1.name contains Management" - "result[1].interfaces.Management1.name contains Manage"
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -17,4 +16,4 @@
- "result.changed == false" - "result.changed == false"
- "result.stdout is defined" - "result.stdout is defined"
- debug: msg="END eapi/contains.yaml" - debug: msg="END eapi/contains.yaml on connection={{ ansible_connection }}"

View file

@ -1,14 +1,13 @@
--- ---
- debug: msg="START eapi/equal.yaml" - debug: msg="START eapi/equal.yaml on connection={{ ansible_connection }}"
- name: test eq operator - name: test eq operator
eos_command: eos_command:
commands: commands:
- show version - show version
- show interfaces Management1 - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.name eq Management1" - "result[1].interfaces.Management1.name eq Management1"
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -20,10 +19,9 @@
eos_command: eos_command:
commands: commands:
- show version - show version
- show interfaces Management1 - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.name == Management1" - "result[1].interfaces.Management1.name == Management1"
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -31,4 +29,4 @@
- "result.changed == false" - "result.changed == false"
- "result.stdout is defined" - "result.stdout is defined"
- debug: msg="END eapi/equal.yaml" - debug: msg="END eapi/equal.yaml on connection={{ ansible_connection }}"

View file

@ -1,14 +1,13 @@
--- ---
- debug: msg="START eapi/greaterthan.yaml" - debug: msg="START eapi/greaterthan.yaml on connection={{ ansible_connection }}"
- name: test gt operator - name: test gt operator
eos_command: eos_command:
commands: commands:
- show version - show version
- show interfaces Management1 - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.mtu gt 0" - "result[1].interfaces.Management1.mtu gt 0"
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -20,10 +19,9 @@
eos_command: eos_command:
commands: commands:
- show version - show version
- show interfaces Management1 - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.mtu >= 0" - "result[1].interfaces.Management1.mtu > 0"
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -31,4 +29,4 @@
- "result.changed == false" - "result.changed == false"
- "result.stdout is defined" - "result.stdout is defined"
- debug: msg="END eapi/greaterthan.yaml" - debug: msg="END eapi/greaterthan.yaml on connection={{ ansible_connection }}"

View file

@ -1,14 +1,13 @@
--- ---
- debug: msg="START eapi/greaterthanorequal.yaml" - debug: msg="START eapi/greaterthanorequal.yaml on connection={{ ansible_connection }}"
- name: test ge operator - name: test ge operator
eos_command: eos_command:
commands: commands:
- show version - show version
- show interfaces Management1 - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.mtu ge 0" - "result[1].interfaces.Management1.mtu ge 0"
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -20,10 +19,9 @@
eos_command: eos_command:
commands: commands:
- show version - show version
- show interfaces Management1 - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.mtu >= 0" - "result[1].interfaces.Management1.mtu >= 0"
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -31,4 +29,4 @@
- "result.changed == false" - "result.changed == false"
- "result.stdout is defined" - "result.stdout is defined"
- debug: msg="END eapi/greaterthanorequal.yaml" - debug: msg="END eapi/greaterthanorequal.yaml on connection={{ ansible_connection }}"

View file

@ -4,7 +4,6 @@
- name: run invalid command - name: run invalid command
eos_command: eos_command:
commands: ['show foo'] commands: ['show foo']
provider: "{{ eapi }}"
register: result register: result
ignore_errors: yes ignore_errors: yes
@ -18,7 +17,6 @@
commands: commands:
- show version - show version
- show foo - show foo
provider: "{{ eapi }}"
register: result register: result
ignore_errors: yes ignore_errors: yes

View file

@ -1,14 +1,13 @@
--- ---
- debug: msg="START eapi/lessthan.yaml" - debug: msg="START eapi/lessthan.yaml on connection={{ ansible_connection }}"
- name: test lt operator - name: test lt operator
eos_command: eos_command:
commands: commands:
- show version - show version
- show interfaces Management1 - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.mtu lt 9100" - "result[1].interfaces.Management1.mtu lt 1600"
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -20,10 +19,9 @@
eos_command: eos_command:
commands: commands:
- show version - show version
- show interfaces Management1 - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.mtu < 9100" - "result[1].interfaces.Management1.mtu < 1600"
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -31,4 +29,4 @@
- "result.changed == false" - "result.changed == false"
- "result.stdout is defined" - "result.stdout is defined"
- debug: msg="END eapi/lessthan.yaml" - debug: msg="END eapi/lessthan.yaml on connection={{ ansible_connection }}"

View file

@ -1,14 +1,13 @@
--- ---
- debug: msg="START eapi/lessthanorequal.yaml" - debug: msg="START eapi/lessthanorequal.yaml on connection={{ ansible_connection }}"
- name: test le operator - name: test le operator
eos_command: eos_command:
commands: commands:
- show version - show version
- show interfaces Management1 - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.mtu le 9100" - "result[1].interfaces.Management1.mtu le 1600"
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -20,10 +19,9 @@
eos_command: eos_command:
commands: commands:
- show version - show version
- show interfaces Management1 - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.mtu <= 9100" - "result[1].interfaces.Management1.mtu <= 1600"
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -31,4 +29,4 @@
- "result.changed == false" - "result.changed == false"
- "result.stdout is defined" - "result.stdout is defined"
- debug: msg="END eapi/lessthanorequal.yaml" - debug: msg="END eapi/lessthanorequal.yaml on connection={{ ansible_connection }}"

View file

@ -1,14 +1,13 @@
--- ---
- debug: msg="START eapi/notequal.yaml" - debug: msg="START eapi/notequal.yaml on connection={{ ansible_connection }}"
- name: test neq operator - name: test neq operator
eos_command: eos_command:
commands: commands:
- show version - show version
- show interfaces Management1 - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.name neq Ethernet" - "result[1].interfaces.Management1.name neq Ethernet"
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -20,10 +19,9 @@
eos_command: eos_command:
commands: commands:
- show version - show version
- show interfaces Management1 - show interfaces Management1 | json
wait_for: wait_for:
- "result[1].interfaces.Management1.name != Ethernet" - "result[1].interfaces.Management1.name != Ethernet"
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -31,4 +29,4 @@
- "result.changed == false" - "result.changed == false"
- "result.stdout is defined" - "result.stdout is defined"
- debug: msg="END eapi/notequal.yaml" - debug: msg="END eapi/notequal.yaml on connection={{ ansible_connection }}"

View file

@ -4,7 +4,6 @@
- name: get output for single command - name: get output for single command
eos_command: eos_command:
commands: ['show version'] commands: ['show version']
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -17,7 +16,6 @@
commands: commands:
- show version - show version
- show interfaces - show interfaces
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:

View file

@ -8,7 +8,6 @@
wait_for: wait_for:
- "result[0].version foo 4.15" - "result[0].version foo 4.15"
retries: 1 retries: 1
provider: "{{ eapi }}"
register: result register: result
ignore_errors: yes ignore_errors: yes

View file

@ -14,9 +14,3 @@
with_items: "{{ test_items }}" with_items: "{{ test_items }}"
loop_control: loop_control:
loop_var: test_case_to_run loop_var: test_case_to_run
- name: run test case (connection=local)
include: "{{ test_case_to_run }} ansible_connection=local ansible_become=no"
with_first_found: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run

View file

@ -9,8 +9,8 @@
- name: set test_items - name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test case (connection=local) - name: run test cases (connection=httpapi)
include: "{{ test_case_to_run }} ansible_connection=local" include: "{{ test_case_to_run }} ansible_connection=httpapi"
with_items: "{{ test_items }}" with_items: "{{ test_items }}"
loop_control: loop_control:
loop_var: test_case_to_run loop_var: test_case_to_run

View file

@ -9,7 +9,6 @@
parents: parents:
- interface Ethernet2 - interface Ethernet2
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- name: collect any backup files - name: collect any backup files
@ -29,7 +28,6 @@
eos_config: eos_config:
src: basic/config.j2 src: basic/config.j2
backup: yes backup: yes
provider: "{{ cli }}"
become: yes become: yes
register: result register: result

View file

@ -6,7 +6,6 @@
lines: lines:
- ip address 119.31.1.1 255.255.255.256 - ip address 119.31.1.1 255.255.255.256
parents: interface Loopback911 parents: interface Loopback911
provider: "{{ cli }}"
become: yes become: yes
check_mode: 1 check_mode: 1
environment: environment:
@ -25,7 +24,6 @@
before: before:
- "no ip access-list test" - "no ip access-list test"
src: basic/cmds.j2 src: basic/cmds.j2
provider: "{{ cli }}"
become: yes become: yes
check_mode: yes check_mode: yes
register: config register: config
@ -34,7 +32,6 @@
eos_command: eos_command:
commands: commands:
- show configuration sessions | json - show configuration sessions | json
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -47,7 +44,6 @@
lines: lines:
- ip address 119.31.1.1 255.255.255.256 - ip address 119.31.1.1 255.255.255.256
parents: interface Loopback911 parents: interface Loopback911
provider: "{{ cli }}"
become: yes become: yes
check_mode: 1 check_mode: 1
environment: environment:
@ -64,7 +60,6 @@
lines: lines:
- ip address 119.31.1.1 255.255.255.255 - ip address 119.31.1.1 255.255.255.255
parents: interface Loopback911 parents: interface Loopback911
provider: "{{ cli }}"
become: yes become: yes
check_mode: yes check_mode: yes
register: result register: result

View file

@ -5,13 +5,11 @@
eos_config: eos_config:
lines: hostname {{ inventory_hostname_short }} lines: hostname {{ inventory_hostname_short }}
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- name: get current running-config - name: get current running-config
eos_command: eos_command:
commands: show running-config commands: show running-config
provider: "{{ cli }}"
become: yes become: yes
register: config register: config
@ -19,7 +17,6 @@
eos_config: eos_config:
lines: hostname foo lines: hostname foo
config: "{{ config.stdout[0] }}" config: "{{ config.stdout[0] }}"
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -31,7 +28,6 @@
- name: get current running-config - name: get current running-config
eos_command: eos_command:
commands: show running-config commands: show running-config
provider: "{{ cli }}"
become: yes become: yes
register: config register: config
@ -39,7 +35,6 @@
eos_config: eos_config:
lines: hostname foo lines: hostname foo
config: "{{ config.stdout[0] }}" config: "{{ config.stdout[0] }}"
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -51,7 +46,6 @@
eos_config: eos_config:
lines: hostname {{ inventory_hostname_short }} lines: hostname {{ inventory_hostname_short }}
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- debug: msg="END cli/config.yaml on connection={{ ansible_connection }}" - debug: msg="END cli/config.yaml on connection={{ ansible_connection }}"

View file

@ -9,14 +9,12 @@
parents: parents:
- interface Ethernet2 - interface Ethernet2
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- name: configure device with defaults included - name: configure device with defaults included
eos_config: eos_config:
src: defaults/config.j2 src: defaults/config.j2
defaults: yes defaults: yes
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -31,7 +29,6 @@
eos_config: eos_config:
src: defaults/config.j2 src: defaults/config.j2
defaults: yes defaults: yes
provider: "{{ cli }}"
become: yes become: yes
register: result register: result

View file

@ -9,14 +9,12 @@
parents: parents:
- interface Ethernet2 - interface Ethernet2
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- name: save config always - name: save config always
eos_config: eos_config:
save_when: always save_when: always
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -27,7 +25,6 @@
- name: save always again (not idempotent) - name: save always again (not idempotent)
eos_config: eos_config:
save_when: always save_when: always
provider: "{{ cli }}"
become: yes become: yes
register: result register: result

View file

@ -9,13 +9,11 @@
parents: parents:
- interface Ethernet2 - interface Ethernet2
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- name: configure device with config - name: configure device with config
eos_config: eos_config:
src: basic/config.j2 src: basic/config.j2
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -29,7 +27,6 @@
eos_config: eos_config:
src: basic/config.j2 src: basic/config.j2
defaults: yes defaults: yes
provider: "{{ cli }}"
become: yes become: yes
register: result register: result

View file

@ -6,7 +6,6 @@
- name: configure with invalid src - name: configure with invalid src
eos_config: eos_config:
src: basic/foobar.j2 src: basic/foobar.j2
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
ignore_errors: yes ignore_errors: yes

View file

@ -9,13 +9,11 @@
parents: parents:
- interface Ethernet2 - interface Ethernet2
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- name: configure device with config - name: configure device with config
eos_config: eos_config:
src: basic/config.j2 src: basic/config.j2
provider: "{{ cli }}"
match: none match: none
become: yes become: yes
register: result register: result
@ -30,7 +28,6 @@
eos_config: eos_config:
src: basic/config.j2 src: basic/config.j2
defaults: yes defaults: yes
provider: "{{ cli }}"
become: yes become: yes
register: result register: result

View file

@ -5,14 +5,12 @@
eos_config: eos_config:
lines: no vlan 10 lines: no vlan 10
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- name: configure sub level command - name: configure sub level command
eos_config: eos_config:
lines: name test lines: name test
parents: vlan 10 parents: vlan 10
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -26,7 +24,6 @@
eos_config: eos_config:
lines: name test lines: name test
parents: vlan 10 parents: vlan 10
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -38,7 +35,6 @@
eos_config: eos_config:
lines: no vlan 10 lines: no vlan 10
match: none match: none
provider: "{{ cli }}"
become: yes become: yes

View file

@ -11,7 +11,6 @@
before: no ip access-list test before: no ip access-list test
after: exit after: exit
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- name: configure sub level command using block resplace - name: configure sub level command using block resplace
@ -24,7 +23,6 @@
parents: ip access-list test parents: ip access-list test
replace: block replace: block
after: exit after: exit
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -47,7 +45,6 @@
parents: ip access-list test parents: ip access-list test
replace: block replace: block
after: exit after: exit
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -59,7 +56,6 @@
eos_config: eos_config:
lines: no ip access-list test lines: no ip access-list test
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- debug: msg="END cli/sublevel_block.yaml on connection={{ ansible_connection }}" - debug: msg="END cli/sublevel_block.yaml on connection={{ ansible_connection }}"

View file

@ -13,7 +13,6 @@
before: no ip access-list test before: no ip access-list test
after: exit after: exit
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- name: configure sub level command using exact match - name: configure sub level command using exact match
@ -28,7 +27,6 @@
after: exit after: exit
match: exact match: exact
replace: block replace: block
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -51,7 +49,6 @@
- 40 permit ip host 4.4.4.4 any log - 40 permit ip host 4.4.4.4 any log
parents: ip access-list test parents: ip access-list test
match: exact match: exact
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -63,7 +60,6 @@
eos_config: eos_config:
lines: no ip access-list test lines: no ip access-list test
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- debug: msg="END cli/sublevel_exact.yaml on connection={{ ansible_connection }}" - debug: msg="END cli/sublevel_exact.yaml on connection={{ ansible_connection }}"

View file

@ -13,7 +13,6 @@
before: no ip access-list test before: no ip access-list test
after: exit after: exit
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- name: configure sub level command using strict match - name: configure sub level command using strict match
@ -28,7 +27,6 @@
after: exit after: exit
match: strict match: strict
replace: block replace: block
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -51,7 +49,6 @@
- 40 permit ip host 4.4.4.4 any log - 40 permit ip host 4.4.4.4 any log
parents: ip access-list test parents: ip access-list test
match: strict match: strict
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -63,7 +60,6 @@
eos_config: eos_config:
lines: no ip access-list test lines: no ip access-list test
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- debug: msg="END cli/sublevel_strict.yaml on connection={{ ansible_connection }}" - debug: msg="END cli/sublevel_strict.yaml on connection={{ ansible_connection }}"

View file

@ -5,13 +5,11 @@
eos_config: eos_config:
lines: hostname veos01 lines: hostname veos01
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- name: configure top level command - name: configure top level command
eos_config: eos_config:
lines: hostname foo lines: hostname foo
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -23,7 +21,6 @@
- name: configure top level command idempotent check - name: configure top level command idempotent check
eos_config: eos_config:
lines: hostname foo lines: hostname foo
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -35,7 +32,6 @@
eos_config: eos_config:
lines: hostname veos01 lines: hostname veos01
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- debug: msg="END cli/toplevel.yaml on connection={{ ansible_connection }}" - debug: msg="END cli/toplevel.yaml on connection={{ ansible_connection }}"

View file

@ -7,14 +7,12 @@
- snmp-server contact ansible - snmp-server contact ansible
- hostname veos01 - hostname veos01
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- name: configure top level command with before - name: configure top level command with before
eos_config: eos_config:
lines: hostname foo lines: hostname foo
after: snmp-server contact bar after: snmp-server contact bar
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -28,7 +26,6 @@
eos_config: eos_config:
lines: hostname foo lines: hostname foo
after: snmp-server contact foo after: snmp-server contact foo
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -42,7 +39,6 @@
- no snmp-server contact - no snmp-server contact
- hostname veos01 - hostname veos01
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- debug: msg="END cli/toplevel_after.yaml on connection={{ ansible_connection }}" - debug: msg="END cli/toplevel_after.yaml on connection={{ ansible_connection }}"

View file

@ -7,14 +7,12 @@
- snmp-server contact ansible - snmp-server contact ansible
- hostname veos01 - hostname veos01
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- name: configure top level command with before - name: configure top level command with before
eos_config: eos_config:
lines: hostname foo lines: hostname foo
before: snmp-server contact bar before: snmp-server contact bar
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -28,7 +26,6 @@
eos_config: eos_config:
lines: hostname foo lines: hostname foo
before: snmp-server contact foo before: snmp-server contact foo
provider: "{{ cli }}"
become: yes become: yes
register: result register: result
@ -42,7 +39,6 @@
- hostname veos01 - hostname veos01
- no snmp-server contact - no snmp-server contact
match: none match: none
provider: "{{ cli }}"
become: yes become: yes
- debug: msg="END cli/toplevel_before.yaml on connection={{ ansible_connection }}" - debug: msg="END cli/toplevel_before.yaml on connection={{ ansible_connection }}"

View file

@ -1,5 +1,5 @@
--- ---
- debug: msg="START eapi/backup.yaml" - debug: msg="START eapi/backup.yaml on connection={{ ansible_connection }}"
- name: setup - name: setup
eos_config: eos_config:
@ -9,14 +9,14 @@
parents: parents:
- interface Ethernet2 - interface Ethernet2
match: none match: none
provider: "{{ eapi }}" become: yes
- name: collect any backup files - name: collect any backup files
find: find:
paths: "{{ role_path }}/backup" paths: "{{ role_path }}/backup"
pattern: "{{ inventory_hostname_short }}_config*" pattern: "{{ inventory_hostname_short }}_config*"
register: backup_files register: backup_files
delegate_to: localhost connection: local
- name: delete backup files - name: delete backup files
file: file:
@ -28,7 +28,7 @@
eos_config: eos_config:
src: basic/config.j2 src: basic/config.j2
backup: yes backup: yes
provider: "{{ eapi }}" become: yes
register: result register: result
- assert: - assert:
@ -41,10 +41,10 @@
paths: "{{ role_path }}/backup" paths: "{{ role_path }}/backup"
pattern: "{{ inventory_hostname_short }}_config*" pattern: "{{ inventory_hostname_short }}_config*"
register: backup_files register: backup_files
delegate_to: localhost connection: local
- assert: - assert:
that: that:
- "backup_files.files is defined" - "backup_files.files is defined"
- debug: msg="END eapi/backup.yaml" - debug: msg="END eapi/backup.yaml on connection={{ ansible_connection }}"

View file

@ -9,13 +9,11 @@
parents: parents:
- interface Ethernet2 - interface Ethernet2
match: none match: none
provider: "{{ eapi }}"
- name: configure device with defaults included - name: configure device with defaults included
eos_config: eos_config:
src: defaults/config.j2 src: defaults/config.j2
defaults: yes defaults: yes
provider: "{{ eapi }}"
register: result register: result
- debug: var=result - debug: var=result
@ -29,7 +27,6 @@
eos_config: eos_config:
src: defaults/config.j2 src: defaults/config.j2
defaults: yes defaults: yes
provider: "{{ eapi }}"
register: result register: result
- debug: var=result - debug: var=result

View file

@ -9,13 +9,11 @@
parents: parents:
- interface Ethernet2 - interface Ethernet2
match: none match: none
provider: "{{ eapi }}"
- name: save config - name: save config
eos_config: eos_config:
save_when: always save_when: always
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -25,7 +23,6 @@
- name: save should always run - name: save should always run
eos_config: eos_config:
save_when: always save_when: always
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:

View file

@ -9,12 +9,10 @@
parents: parents:
- interface Ethernet2 - interface Ethernet2
match: none match: none
provider: "{{ eapi }}"
- name: configure device with config - name: configure device with config
eos_config: eos_config:
src: basic/config.j2 src: basic/config.j2
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -26,7 +24,6 @@
- name: check device with config - name: check device with config
eos_config: eos_config:
src: basic/config.j2 src: basic/config.j2
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:

View file

@ -6,7 +6,6 @@
- name: configure with invalid src - name: configure with invalid src
eos_config: eos_config:
src: basic/foobar.j2 src: basic/foobar.j2
provider: "{{ eapi }}"
register: result register: result
ignore_errors: yes ignore_errors: yes

View file

@ -9,12 +9,10 @@
parents: parents:
- interface Ethernet2 - interface Ethernet2
match: none match: none
provider: "{{ eapi }}"
- name: configure device with config - name: configure device with config
eos_config: eos_config:
src: basic/config.j2 src: basic/config.j2
provider: "{{ eapi }}"
match: none match: none
register: result register: result
@ -27,7 +25,6 @@
- name: check device with config - name: check device with config
eos_config: eos_config:
src: basic/config.j2 src: basic/config.j2
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:

View file

@ -5,14 +5,12 @@
eos_config: eos_config:
lines: no ip access-list test lines: no ip access-list test
match: none match: none
provider: "{{ eapi }}"
- name: configure sub level command - name: configure sub level command
eos_config: eos_config:
lines: 10 permit ip any any log lines: 10 permit ip any any log
parents: ip access-list test parents: ip access-list test
after: exit after: exit
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -25,7 +23,6 @@
eos_config: eos_config:
lines: 10 permit ip any any log lines: 10 permit ip any any log
parents: ip access-list test parents: ip access-list test
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -36,6 +33,5 @@
eos_config: eos_config:
lines: no ip access-list test lines: no ip access-list test
match: none match: none
provider: "{{ cli }}"
- debug: msg="END eapi/sublevel.yaml" - debug: msg="END eapi/sublevel.yaml"

View file

@ -10,7 +10,6 @@
parents: ip access-list test parents: ip access-list test
before: no ip access-list test before: no ip access-list test
match: none match: none
provider: "{{ eapi }}"
- name: configure sub level command using block resplace - name: configure sub level command using block resplace
eos_config: eos_config:
@ -22,7 +21,6 @@
parents: ip access-list test parents: ip access-list test
after: end after: end
replace: block replace: block
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -43,7 +41,6 @@
- 40 permit ip host 4.4.4.4 any log - 40 permit ip host 4.4.4.4 any log
parents: ip access-list test parents: ip access-list test
replace: block replace: block
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -54,6 +51,5 @@
eos_config: eos_config:
lines: no ip access-list test lines: no ip access-list test
match: none match: none
provider: "{{ eapi }}"
- debug: msg="END eapi/sublevel_block.yaml" - debug: msg="END eapi/sublevel_block.yaml"

View file

@ -13,7 +13,6 @@
before: no ip access-list test before: no ip access-list test
after: exit after: exit
match: none match: none
provider: "{{ eapi }}"
- name: configure sub level command using exact match - name: configure sub level command using exact match
eos_config: eos_config:
@ -26,7 +25,6 @@
parents: ip access-list test parents: ip access-list test
after: exit after: exit
match: exact match: exact
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -49,7 +47,6 @@
before: no ip access-list test before: no ip access-list test
parents: ip access-list test parents: ip access-list test
match: exact match: exact
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -60,6 +57,5 @@
eos_config: eos_config:
lines: no ip access-list test lines: no ip access-list test
match: none match: none
provider: "{{ eapi }}"
- debug: msg="END eapi/sublevel_exact.yaml" - debug: msg="END eapi/sublevel_exact.yaml"

View file

@ -11,7 +11,6 @@
- 50 permit ip host 5.5.5.5 any log - 50 permit ip host 5.5.5.5 any log
parents: ip access-list test parents: ip access-list test
before: no ip access-list test before: no ip access-list test
provider: "{{ eapi }}"
match: none match: none
- name: configure sub level command using strict match - name: configure sub level command using strict match
@ -26,7 +25,6 @@
after: exit after: exit
match: strict match: strict
replace: block replace: block
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -48,7 +46,6 @@
- 40 permit ip host 4.4.4.4 any log - 40 permit ip host 4.4.4.4 any log
parents: ip access-list test parents: ip access-list test
match: strict match: strict
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -59,6 +56,5 @@
eos_config: eos_config:
lines: no ip access-list test lines: no ip access-list test
match: none match: none
provider: "{{ eapi }}"
- debug: msg="END eapi/sublevel_strict.yaml" - debug: msg="END eapi/sublevel_strict.yaml"

View file

@ -5,12 +5,10 @@
eos_config: eos_config:
lines: hostname {{ inventory_hostname_short }} lines: hostname {{ inventory_hostname_short }}
match: none match: none
provider: "{{ eapi }}"
- name: configure top level command - name: configure top level command
eos_config: eos_config:
lines: hostname foo lines: hostname foo
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -21,7 +19,6 @@
- name: configure top level command idempotent check - name: configure top level command idempotent check
eos_config: eos_config:
lines: hostname foo lines: hostname foo
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -32,6 +29,5 @@
eos_config: eos_config:
lines: hostname {{ inventory_hostname_short }} lines: hostname {{ inventory_hostname_short }}
match: none match: none
provider: "{{ eapi }}"
- debug: msg="END eapi/toplevel.yaml" - debug: msg="END eapi/toplevel.yaml"

View file

@ -7,13 +7,11 @@
- "snmp-server contact ansible" - "snmp-server contact ansible"
- "hostname {{ inventory_hostname_short }}" - "hostname {{ inventory_hostname_short }}"
match: none match: none
provider: "{{ eapi }}"
- name: configure top level command with before - name: configure top level command with before
eos_config: eos_config:
lines: hostname foo lines: hostname foo
after: snmp-server contact bar after: snmp-server contact bar
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -26,7 +24,6 @@
eos_config: eos_config:
lines: hostname foo lines: hostname foo
after: snmp-server contact foo after: snmp-server contact foo
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -39,6 +36,5 @@
- no snmp-server contact - no snmp-server contact
- hostname {{ inventory_hostname_short }} - hostname {{ inventory_hostname_short }}
match: none match: none
provider: "{{ eapi }}"
- debug: msg="END eapi/toplevel_after.yaml" - debug: msg="END eapi/toplevel_after.yaml"

View file

@ -7,13 +7,11 @@
- "snmp-server contact ansible" - "snmp-server contact ansible"
- "hostname {{ inventory_hostname_short }}" - "hostname {{ inventory_hostname_short }}"
match: none match: none
provider: "{{ eapi }}"
- name: configure top level command with before - name: configure top level command with before
eos_config: eos_config:
lines: hostname foo lines: hostname foo
before: snmp-server contact bar before: snmp-server contact bar
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -26,7 +24,6 @@
eos_config: eos_config:
lines: hostname foo lines: hostname foo
before: snmp-server contact foo before: snmp-server contact foo
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -39,6 +36,5 @@
- no snmp-server contact ansible - no snmp-server contact ansible
- hostname {{ inventory_hostname_short }} - hostname {{ inventory_hostname_short }}
match: none match: none
provider: "{{ eapi }}"
- debug: msg="END eapi/toplevel_before.yaml" - debug: msg="END eapi/toplevel_before.yaml"

View file

@ -14,9 +14,3 @@
with_items: "{{ test_items }}" with_items: "{{ test_items }}"
loop_control: loop_control:
loop_var: test_case_to_run loop_var: test_case_to_run
- name: run test case (connection=local)
include: "{{ test_case_to_run }} ansible_connection=local ansible_become=no"
with_first_found: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run

View file

@ -9,8 +9,8 @@
- name: set test_items - name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test case (connection=local) - name: run test cases (connection=httpapi)
include: "{{ test_case_to_run }} ansible_connection=local" include: "{{ test_case_to_run }} ansible_connection=httpapi"
with_items: "{{ test_items }}" with_items: "{{ test_items }}"
loop_control: loop_control:
loop_var: test_case_to_run loop_var: test_case_to_run

View file

@ -4,7 +4,6 @@
- name: test getting all facts - name: test getting all facts
eos_facts: eos_facts:
provider: "{{ cli }}"
gather_subset: gather_subset:
- all - all
become: yes become: yes

View file

@ -4,7 +4,6 @@
- name: test getting default facts - name: test getting default facts
eos_facts: eos_facts:
provider: "{{ cli }}"
become: yes become: yes
register: result register: result

View file

@ -4,7 +4,6 @@
- name: test invalid subset (foobar) - name: test invalid subset (foobar)
eos_facts: eos_facts:
provider: "{{ cli }}"
gather_subset: gather_subset:
- "foobar" - "foobar"
register: result register: result
@ -26,7 +25,6 @@
- name: test subset specified multiple times - name: test subset specified multiple times
eos_facts: eos_facts:
provider: "{{ cli }}"
gather_subset: gather_subset:
- "!hardware" - "!hardware"
- "hardware" - "hardware"

View file

@ -4,7 +4,6 @@
- name: test not hardware - name: test not hardware
eos_facts: eos_facts:
provider: "{{ cli }}"
gather_subset: gather_subset:
- "!hardware" - "!hardware"
become: yes become: yes

View file

@ -5,11 +5,9 @@
eos_config: eos_config:
lines: lldp run lines: lldp run
authorize: yes authorize: yes
provider: "{{ eapi }}"
- name: test getting all facts - name: test getting all facts
eos_facts: eos_facts:
provider: "{{ eapi }}"
gather_subset: gather_subset:
- all - all
register: result register: result
@ -35,6 +33,5 @@
eos_config: eos_config:
lines: no lldp run lines: no lldp run
authorize: yes authorize: yes
provider: "{{ eapi }}"
- debug: msg="END eapi/all_facts.yaml" - debug: msg="END eapi/all_facts.yaml"

View file

@ -5,11 +5,9 @@
eos_config: eos_config:
lines: lldp run lines: lldp run
authorize: yes authorize: yes
provider: "{{ eapi }}"
- name: test getting default facts - name: test getting default facts
eos_facts: eos_facts:
provider: "{{ eapi }}"
register: result register: result
- assert: - assert:
@ -37,6 +35,5 @@
eos_config: eos_config:
lines: lldp run lines: lldp run
authorize: yes authorize: yes
provider: "{{ eapi }}"
- debug: msg="END eapi/default.yaml" - debug: msg="END eapi/default.yaml"

View file

@ -4,7 +4,6 @@
- name: test invalid subset (foobar) - name: test invalid subset (foobar)
eos_facts: eos_facts:
provider: "{{ eapi }}"
gather_subset: gather_subset:
- "foobar" - "foobar"
register: result register: result
@ -26,7 +25,6 @@
- name: test subset specified multiple times - name: test subset specified multiple times
eos_facts: eos_facts:
provider: "{{ eapi }}"
gather_subset: gather_subset:
- "!hardware" - "!hardware"
- "hardware" - "hardware"

View file

@ -5,11 +5,9 @@
eos_config: eos_config:
lines: lldp run lines: lldp run
authorize: yes authorize: yes
provider: "{{ eapi }}"
- name: test not hardware - name: test not hardware
eos_facts: eos_facts:
provider: "{{ eapi }}"
gather_subset: gather_subset:
- "!hardware" - "!hardware"
register: result register: result
@ -36,6 +34,5 @@
eos_config: eos_config:
lines: no lldp run lines: no lldp run
authorize: yes authorize: yes
provider: "{{ eapi }}"
- debug: msg="END eapi/not_hardware_facts.yaml" - debug: msg="END eapi/not_hardware_facts.yaml"

View file

@ -9,8 +9,8 @@
- name: set test_items - name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test case (connection=local) - name: run test cases (connection=httpapi)
include: "{{ test_case_to_run }} ansible_connection=local" include: "{{ test_case_to_run }} ansible_connection=httpapi"
with_items: "{{ test_items }}" with_items: "{{ test_items }}"
loop_control: loop_control:
loop_var: test_case_to_run loop_var: test_case_to_run

View file

@ -9,8 +9,8 @@
- name: set test_items - name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test case (connection=local) - name: run test cases (connection=httpapi)
include: "{{ test_case_to_run }} ansible_connection=local" include: "{{ test_case_to_run }} ansible_connection=httpapi"
with_items: "{{ test_items }}" with_items: "{{ test_items }}"
loop_control: loop_control:
loop_var: test_case_to_run loop_var: test_case_to_run

View file

@ -9,8 +9,8 @@
- name: set test_items - name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test case (connection=local) - name: run test cases (connection=httpapi)
include: "{{ test_case_to_run }} ansible_connection=local" include: "{{ test_case_to_run }} ansible_connection=httpapi"
with_items: "{{ test_items }}" with_items: "{{ test_items }}"
loop_control: loop_control:
loop_var: test_case_to_run loop_var: test_case_to_run

View file

@ -9,8 +9,8 @@
- name: set test_items - name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test case (connection=local) - name: run test cases (connection=httpapi)
include: "{{ test_case_to_run }} ansible_connection=local" include: "{{ test_case_to_run }} ansible_connection=httpapi"
with_items: "{{ test_items }}" with_items: "{{ test_items }}"
loop_control: loop_control:
loop_var: test_case_to_run loop_var: test_case_to_run

View file

@ -9,8 +9,8 @@
- name: set test_items - name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test case (connection=local) - name: run test cases (connection=httpapi)
include: "{{ test_case_to_run }} ansible_connection=local" include: "{{ test_case_to_run }} ansible_connection=httpapi"
with_items: "{{ test_items }}" with_items: "{{ test_items }}"
loop_control: loop_control:
loop_var: test_case_to_run loop_var: test_case_to_run

View file

@ -17,6 +17,6 @@
- name: run test case (connection=local) - name: run test case (connection=local)
include: "{{ test_case_to_run }} ansible_connection=local ansible_become=no" include: "{{ test_case_to_run }} ansible_connection=local ansible_become=no"
with_first_found: "{{ test_items }}" with_items: "{{ test_items }}"
loop_control: loop_control:
loop_var: test_case_to_run loop_var: test_case_to_run

View file

@ -9,6 +9,12 @@
- name: set test_items - name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test cases (connection=httpapi)
include: "{{ test_case_to_run }} ansible_connection=httpapi"
with_items: "{{ test_items }}"
loop_control:
loop_var: test_case_to_run
- name: run test case (connection=local) - name: run test case (connection=local)
include: "{{ test_case_to_run }} ansible_connection=local" include: "{{ test_case_to_run }} ansible_connection=local"
with_items: "{{ test_items }}" with_items: "{{ test_items }}"

View file

@ -45,64 +45,65 @@
become: yes become: yes
# hit block and diffs # hit block and diffs
- block:
- name: setup
eos_config:
lines:
- 10 permit ip host 1.1.1.1 any log
- 20 permit ip host 2.2.2.2 any log
- 30 permit ip host 3.3.3.3 any log
parents: ip access-list test
before: no ip access-list test
after: exit
match: strict
provider: "{{ cli }}"
become: yes
- name: setup - name: configure sub level command using block replace
eos_config: eos_config:
lines: lines:
- 10 permit ip host 1.1.1.1 any log - 10 permit ip host 1.1.1.1 any log
- 20 permit ip host 2.2.2.2 any log - 20 permit ip host 2.2.2.2 any log
- 30 permit ip host 3.3.3.3 any log - 30 permit ip host 3.3.3.3 any log
parents: ip access-list test - 40 permit ip host 4.4.4.4 any log
before: no ip access-list test parents: ip access-list test
after: exit replace: block
match: strict after: exit
provider: "{{ cli }}" provider: "{{ cli }}"
become: yes match: line
become: yes
register: result
- name: configure sub level command using block resplace - assert:
eos_config: that:
lines: - "result.changed == true"
- 10 permit ip host 1.1.1.1 any log - "'ip access-list test' in result.updates"
- 20 permit ip host 2.2.2.2 any log - "'10 permit ip host 1.1.1.1 any log' in result.updates"
- 30 permit ip host 3.3.3.3 any log - "'20 permit ip host 2.2.2.2 any log' in result.updates"
- 40 permit ip host 4.4.4.4 any log - "'30 permit ip host 3.3.3.3 any log' in result.updates"
parents: ip access-list test - "'40 permit ip host 4.4.4.4 any log' in result.updates"
replace: block
after: exit
provider: "{{ cli }}"
match: line
become: yes
register: result
- assert: - name: check sub level command using block replace
that: eos_config:
- "result.changed == true" lines:
- "'ip access-list test' in result.updates" - 10 permit ip host 1.1.1.1 any log
- "'10 permit ip host 1.1.1.1 any log' in result.updates" - 20 permit ip host 2.2.2.2 any log
- "'20 permit ip host 2.2.2.2 any log' in result.updates" - 30 permit ip host 3.3.3.3 any log
- "'30 permit ip host 3.3.3.3 any log' in result.updates" - 40 permit ip host 4.4.4.4 any log
- "'40 permit ip host 4.4.4.4 any log' in result.updates" parents: ip access-list test
replace: block
after: exit
provider: "{{ cli }}"
match: exact
become: yes
register: result
- name: check sub level command using block replace always:
eos_config: - name: teardown
lines: eos_config:
- 10 permit ip host 1.1.1.1 any log lines: no ip access-list test
- 20 permit ip host 2.2.2.2 any log match: none
- 30 permit ip host 3.3.3.3 any log provider: "{{ cli }}"
- 40 permit ip host 4.4.4.4 any log become: yes
parents: ip access-list test
replace: block
after: exit
provider: "{{ cli }}"
match: exact
become: yes
register: result
- name: teardown
eos_config:
lines: no ip access-list test
match: none
provider: "{{ cli }}"
become: yes
- debug: msg="END cli/common_config.yaml on connection={{ ansible_connection }}" - debug: msg="END cli/common_config.yaml on connection={{ ansible_connection }}"

View file

@ -40,60 +40,61 @@
provider: "{{ eapi }}" provider: "{{ eapi }}"
# hit block and diffs # hit block and diffs
- block:
- name: setup
eos_config:
lines:
- 10 permit ip host 1.1.1.1 any log
- 20 permit ip host 2.2.2.2 any log
- 30 permit ip host 3.3.3.3 any log
parents: ip access-list test
before: no ip access-list test
after: exit
match: strict
provider: "{{ eapi }}"
- name: setup - name: configure sub level command using block replace
eos_config: eos_config:
lines: lines:
- 10 permit ip host 1.1.1.1 any log - 10 permit ip host 1.1.1.1 any log
- 20 permit ip host 2.2.2.2 any log - 20 permit ip host 2.2.2.2 any log
- 30 permit ip host 3.3.3.3 any log - 30 permit ip host 3.3.3.3 any log
parents: ip access-list test - 40 permit ip host 4.4.4.4 any log
before: no ip access-list test parents: ip access-list test
after: exit replace: block
match: strict after: exit
provider: "{{ eapi }}" provider: "{{ eapi }}"
match: line
register: result
- name: configure sub level command using block resplace - assert:
eos_config: that:
lines: - "result.changed == true"
- 10 permit ip host 1.1.1.1 any log - "'ip access-list test' in result.updates"
- 20 permit ip host 2.2.2.2 any log - "'10 permit ip host 1.1.1.1 any log' in result.updates"
- 30 permit ip host 3.3.3.3 any log - "'20 permit ip host 2.2.2.2 any log' in result.updates"
- 40 permit ip host 4.4.4.4 any log - "'30 permit ip host 3.3.3.3 any log' in result.updates"
parents: ip access-list test - "'40 permit ip host 4.4.4.4 any log' in result.updates"
replace: block
after: exit
provider: "{{ eapi }}"
match: line
register: result
- assert: - name: check sub level command using block replace
that: eos_config:
- "result.changed == true" lines:
- "'ip access-list test' in result.updates" - 10 permit ip host 1.1.1.1 any log
- "'10 permit ip host 1.1.1.1 any log' in result.updates" - 20 permit ip host 2.2.2.2 any log
- "'20 permit ip host 2.2.2.2 any log' in result.updates" - 30 permit ip host 3.3.3.3 any log
- "'30 permit ip host 3.3.3.3 any log' in result.updates" - 40 permit ip host 4.4.4.4 any log
- "'40 permit ip host 4.4.4.4 any log' in result.updates" parents: ip access-list test
replace: block
after: exit
provider: "{{ eapi }}"
match: exact
register: result
- name: check sub level command using block replace always:
eos_config: - name: teardown
lines: eos_config:
- 10 permit ip host 1.1.1.1 any log lines: no ip access-list test
- 20 permit ip host 2.2.2.2 any log match: none
- 30 permit ip host 3.3.3.3 any log provider: "{{ eapi }}"
- 40 permit ip host 4.4.4.4 any log
parents: ip access-list test
replace: block
after: exit
provider: "{{ eapi }}"
match: exact
register: result
- name: teardown
eos_config:
lines: no ip access-list test
match: none
provider: "{{ eapi }}"
- debug: msg="END cli/common_config.yaml on connection={{ ansible_connection }}" - debug: msg="END cli/common_config.yaml on connection={{ ansible_connection }}"

View file

@ -1,26 +0,0 @@
---
- debug: msg="START cli/misc_tests.yaml on connection={{ ansible_connection }}"
# test become and unbecome
- block:
- name: command that does require become (should fail)
eos_command:
commands: show running-config
provider: "{{ eapi }}"
become: no
ignore_errors: yes
register: result
- assert:
that:
- 'result.failed == true'
- '"privileged mode required" in result.module_stderr'
- name: command that doesn't require become
eos_command:
commands: show uptime
provider: "{{ eapi }}"
become: no
when: "ansible_connection != 'local'"

View file

@ -9,8 +9,8 @@
- name: set test_items - name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test case (connection=local) - name: run test cases (connection=httpapi)
include: "{{ test_case_to_run }} ansible_connection=local" include: "{{ test_case_to_run }} ansible_connection=httpapi"
with_items: "{{ test_items }}" with_items: "{{ test_items }}"
loop_control: loop_control:
loop_var: test_case_to_run loop_var: test_case_to_run

View file

@ -9,8 +9,8 @@
- name: set test_items - name: set test_items
set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}" set_fact: test_items="{{ test_cases.files | map(attribute='path') | list }}"
- name: run test case (connection=local) - name: run test cases (connection=httpapi)
include: "{{ test_case_to_run }} ansible_connection=local" include: "{{ test_case_to_run }} ansible_connection=httpapi"
with_items: "{{ test_items }}" with_items: "{{ test_items }}"
loop_control: loop_control:
loop_var: test_case_to_run loop_var: test_case_to_run

Some files were not shown because too many files have changed in this diff Show more