Add new Ansible plugins: ara_playbook and ara_api
These new action and lookup plugins makes it easier to query ARA from inside a playbook. In terms of practical use, this first iteration allows us to have an integration test playbook that asserts some of ARA's features such as playbook names and labels. Change-Id: I38bea1062f0002886ecde70827f70d27248a1868
This commit is contained in:
parent
a8b8ff5c59
commit
8e5dcd976a
|
@ -0,0 +1,102 @@
|
|||
# Copyright (c) 2019 Red Hat, Inc.
|
||||
#
|
||||
# This file is part of ARA: Ansible Run Analysis.
|
||||
#
|
||||
# ARA is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ARA is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with ARA. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from ansible.playbook.play import Play
|
||||
from ansible.plugins.action import ActionBase
|
||||
|
||||
from ara.clients import utils as client_utils
|
||||
|
||||
DOCUMENTATION = """
|
||||
---
|
||||
module: ara_playbook
|
||||
short_description: Retrieves either a specific playbook from ARA or the one currently running
|
||||
version_added: "2.9"
|
||||
author: "David Moreau-Simard <dmsimard@redhat.com>"
|
||||
description:
|
||||
- Retrieves either a specific playbook from ARA or the one currently running
|
||||
options:
|
||||
playbook_id:
|
||||
description:
|
||||
- id of the playbook to retrieve
|
||||
- if not set, the module will use the ongoing playbook's id
|
||||
required: false
|
||||
|
||||
requirements:
|
||||
- "python >= 3.5"
|
||||
- "ara >= 1.4.0"
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
- name: Get a specific playbook
|
||||
ara_playbook:
|
||||
playbook_id: 5
|
||||
register: playbook_query
|
||||
|
||||
- name: Get current playbook by not specifying a playbook id
|
||||
ara_playbook:
|
||||
register: playbook_query
|
||||
|
||||
- name: Do something with the playbook
|
||||
debug:
|
||||
msg: "Playbook report: http://ara_api/playbook/{{ playbook_query.playbook.id | string }}.html"
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
playbook:
|
||||
description: playbook object returned by the API
|
||||
returned: on success
|
||||
type: dict
|
||||
"""
|
||||
|
||||
|
||||
class ActionModule(ActionBase):
|
||||
""" Retrieves either a specific playbook from ARA or the one currently running """
|
||||
|
||||
TRANSFERS_FILES = False
|
||||
VALID_ARGS = frozenset(("playbook_id"))
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(ActionModule, self).__init__(*args, **kwargs)
|
||||
self.client = client_utils.active_client()
|
||||
|
||||
def run(self, tmp=None, task_vars=None):
|
||||
if task_vars is None:
|
||||
task_vars = dict()
|
||||
|
||||
for arg in self._task.args:
|
||||
if arg not in self.VALID_ARGS:
|
||||
result = {"failed": True, "msg": "{0} is not a valid option.".format(arg)}
|
||||
return result
|
||||
|
||||
result = super(ActionModule, self).run(tmp, task_vars)
|
||||
|
||||
playbook_id = self._task.args.get("playbook_id", None)
|
||||
if playbook_id is None:
|
||||
# Retrieve the playbook id by working our way up from the task to find
|
||||
# the play uuid. Once we have the play uuid, we can find the playbook.
|
||||
parent = self._task
|
||||
while not isinstance(parent._parent._play, Play):
|
||||
parent = parent._parent
|
||||
|
||||
play = self.client.get("/api/v1/plays?uuid=%s" % parent._parent._play._uuid)
|
||||
playbook_id = play["results"][0]["playbook"]
|
||||
|
||||
result["playbook"] = self.client.get("/api/v1/playbooks/%s" % playbook_id)
|
||||
result["changed"] = False
|
||||
result["msg"] = "Queried playbook %s from ARA" % playbook_id
|
||||
|
||||
return result
|
|
@ -0,0 +1,63 @@
|
|||
# Copyright (c) 2019 Red Hat, Inc.
|
||||
#
|
||||
# This file is part of ARA Records Ansible.
|
||||
#
|
||||
# ARA is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ARA is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with ARA. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
from __future__ import absolute_import, division, print_function
|
||||
|
||||
from ansible.plugins.lookup import LookupBase
|
||||
|
||||
from ara.clients import utils as client_utils
|
||||
|
||||
__metaclass__ = type
|
||||
|
||||
DOCUMENTATION = """
|
||||
lookup: ara_api
|
||||
author: David Moreau-Simard (@dmsimard)
|
||||
version_added: "2.9"
|
||||
short_description: Queries the ARA API for data
|
||||
description:
|
||||
- Queries the ARA API for data
|
||||
options:
|
||||
_terms:
|
||||
description:
|
||||
- The endpoint to query
|
||||
type: list
|
||||
elements: string
|
||||
required: True
|
||||
"""
|
||||
|
||||
EXAMPLES = """
|
||||
- debug: msg="{{ lookup('ara_api','/api/v1/playbooks/1') }}"
|
||||
"""
|
||||
|
||||
RETURN = """
|
||||
_raw:
|
||||
description: response from query
|
||||
"""
|
||||
|
||||
|
||||
class LookupModule(LookupBase):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(LookupModule, self).__init__(*args, **kwargs)
|
||||
self.client = client_utils.active_client()
|
||||
|
||||
def run(self, terms, variables, **kwargs):
|
||||
ret = []
|
||||
for term in terms:
|
||||
ret.append(self.client.get(term))
|
||||
|
||||
return ret
|
|
@ -23,3 +23,4 @@ path = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))
|
|||
plugins = os.path.abspath(os.path.join(path, "plugins"))
|
||||
action_plugins = os.path.abspath(os.path.join(plugins, "action"))
|
||||
callback_plugins = os.path.abspath(os.path.join(plugins, "callback"))
|
||||
lookup_plugins = os.path.abspath(os.path.join(plugins, "lookup"))
|
||||
|
|
|
@ -17,14 +17,15 @@
|
|||
|
||||
from __future__ import print_function
|
||||
|
||||
from . import action_plugins, callback_plugins
|
||||
from . import action_plugins, callback_plugins, lookup_plugins
|
||||
|
||||
config = """
|
||||
[defaults]
|
||||
callback_plugins={}
|
||||
action_plugins={}
|
||||
lookup_plugins={}
|
||||
""".format(
|
||||
callback_plugins, action_plugins
|
||||
callback_plugins, action_plugins, lookup_plugins
|
||||
)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|
|
|
@ -20,13 +20,14 @@ from __future__ import print_function
|
|||
import os
|
||||
from distutils.sysconfig import get_python_lib
|
||||
|
||||
from . import action_plugins, callback_plugins
|
||||
from . import action_plugins, callback_plugins, lookup_plugins
|
||||
|
||||
exports = """
|
||||
export ANSIBLE_CALLBACK_PLUGINS=${{ANSIBLE_CALLBACK_PLUGINS:-}}${{ANSIBLE_CALLBACK_PLUGINS+:}}{}
|
||||
export ANSIBLE_ACTION_PLUGINS=${{ANSIBLE_ACTION_PLUGINS:-}}${{ANSIBLE_ACTION_PLUGINS+:}}{}
|
||||
export ANSIBLE_LOOKUP_PLUGINS=${{ANSIBLE_LOOKUP_PLUGINS:-}}${{ANSIBLE_LOOKUP_PLUGINS+:}}{}
|
||||
""".format(
|
||||
callback_plugins, action_plugins
|
||||
callback_plugins, action_plugins, lookup_plugins
|
||||
)
|
||||
|
||||
if "VIRTUAL_ENV" in os.environ:
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Copyright (c) 2019 Red Hat, Inc.
|
||||
#
|
||||
# This file is part of ARA Records Ansible.
|
||||
#
|
||||
# ARA is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# ARA is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with ARA. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from __future__ import print_function
|
||||
|
||||
from . import lookup_plugins
|
||||
|
||||
if __name__ == "__main__":
|
||||
print(lookup_plugins)
|
|
@ -13,9 +13,11 @@ Once you've set up the ``callback_plugins`` configuration or the
|
|||
``ANSIBLE_CALLBACK_PLUGINS`` environment variable, Ansible will automatically
|
||||
use the ARA callback plugin to start recording data.
|
||||
|
||||
If you'd like to use the ``ara_record`` action plugin to record arbitrary data
|
||||
during your playbook, you'll need to set ``action_plugins`` and
|
||||
``ANSIBLE_ACTION_PLUGINS`` as well.
|
||||
``ANSIBLE_ACTION_PLUGINS`` or ``action_plugins`` must be set if you'd like to
|
||||
use the ``ara_record`` or ``ara_playbook`` action plugins.
|
||||
|
||||
If you would like to use the ``ara_api`` lookup plugin, then
|
||||
``ANSIBLE_LOOKUP_PLUGINS`` or ``lookup_plugins`` must also be set.
|
||||
|
||||
Using setup helper modules
|
||||
--------------------------
|
||||
|
@ -36,17 +38,22 @@ The modules can be used directly on the command line:
|
|||
$ python3 -m ara.setup.callback_plugins
|
||||
/usr/lib/python3.7/site-packages/ara/plugins/callback
|
||||
|
||||
$ python3 -m ara.setup.lookup_plugins
|
||||
/usr/lib/python3.7/site-packages/ara/plugins/lookup
|
||||
|
||||
# Note: This doesn't export anything, it only prints the commands.
|
||||
# If you want to export directly from the command, you can use:
|
||||
# source <(python3 -m ara.setup.env)
|
||||
$ python3 -m ara.setup.env
|
||||
export ANSIBLE_CALLBACK_PLUGINS=/usr/lib/python3.7/site-packages/ara/plugins/callback
|
||||
export ANSIBLE_ACTION_PLUGINS=/usr/lib/python3.7/site-packages/ara/plugins/action
|
||||
export ANSIBLE_LOOKUP_PLUGINS=/usr/lib/python3.7/site-packages/ara/plugins/lookup
|
||||
|
||||
$ python3 -m ara.setup.ansible
|
||||
[defaults]
|
||||
callback_plugins=/usr/lib/python3.7/site-packages/ara/plugins/callback
|
||||
action_plugins=/usr/lib/python3.7/site-packages/ara/plugins/action
|
||||
lookup_plugins=/usr/lib/python3.7/site-packages/ara/plugins/lookup
|
||||
|
||||
Or from python, for example:
|
||||
|
||||
|
@ -59,3 +66,7 @@ Or from python, for example:
|
|||
>>> from ara.setup import action_plugins
|
||||
>>> print(action_plugins)
|
||||
/usr/lib/python3.7/site-packages/ara/plugins/action
|
||||
|
||||
>>> from ara.setup import lookup_plugins
|
||||
>>> print(lookup_plugins)
|
||||
/usr/lib/python3.7/site-packages/ara/plugins/lookup
|
||||
|
|
|
@ -0,0 +1,58 @@
|
|||
.. _ara_api_lookup:
|
||||
|
||||
Querying ARA from inside playbooks
|
||||
==================================
|
||||
|
||||
ara_api
|
||||
-------
|
||||
|
||||
ARA comes with a built-in Ansible lookup plugin called ``ara_api`` that can be
|
||||
made available by :ref:`configuring Ansible <ansible-configuration>` with the
|
||||
``ANSIBLE_LOOKUP_PLUGINS`` environment variable or the ``lookup_plugins``
|
||||
setting in an ``ansible.cfg`` file.
|
||||
|
||||
There is no other configuration required for this lookup plugin to work since
|
||||
it retrieves necessary settings (such as API server endpoint and authentication)
|
||||
from the callback plugin.
|
||||
|
||||
The ``ara_api`` lookup plugin can be used to do free-form queries to the
|
||||
ARA API while the playbook is running:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
- name: Test playbook
|
||||
hosts: localhost
|
||||
tasks:
|
||||
- name: Get list of playbooks
|
||||
set_fact:
|
||||
playbooks: "{{ lookup('ara_api', '/api/v1/playbooks') }}"
|
||||
|
||||
ara_playbook
|
||||
------------
|
||||
|
||||
The ``ara_playbook`` Ansible action plugin can be enabled by
|
||||
:ref:`configuring Ansible <ansible-configuration>` with the
|
||||
``ANSIBLE_ACTION_PLUGINS`` environment variable or the ``action_plugins``
|
||||
setting in an ``ansible.cfg`` file.
|
||||
|
||||
There is no other configuration required for this action plugin to work since
|
||||
it retrieves necessary settings (such as API server endpoint and authentication)
|
||||
from the callback plugin.
|
||||
|
||||
The ``ara_playbook`` action plugin can be used in combination with ``ara_api``
|
||||
to query the API about the current playbook:
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
- name: Test playbook
|
||||
hosts: localhost
|
||||
tasks:
|
||||
- name: Get the currently running playbook
|
||||
ara_playbook:
|
||||
register: playbook_query
|
||||
|
||||
- name: Get failed tasks for the currently running playbook
|
||||
vars:
|
||||
playbook_id: "{{ playbook_query.playbook.id | string }}"
|
||||
set_fact:
|
||||
tasks: "{{ lookup('ara_api', '/api/v1/tasks?status=failed&playbook=' + playbook_id) }}"
|
|
@ -20,6 +20,7 @@ Table of Contents
|
|||
API: Distributed sqlite backend <distributed-sqlite-backend>
|
||||
Setting playbook names and labels <playbook-names-and-labels>
|
||||
Recording arbitrary data in playbooks <ara-record>
|
||||
Querying ARA from inside playbooks <ara-api-lookup>
|
||||
Contributing to ARA <contributing>
|
||||
|
||||
.. toctree::
|
||||
|
|
|
@ -105,6 +105,7 @@
|
|||
- environment:
|
||||
ANSIBLE_CALLBACK_PLUGINS: "{{ ara_setup_plugins.stdout }}/callback"
|
||||
ANSIBLE_ACTION_PLUGINS: "{{ ara_setup_plugins.stdout }}/action"
|
||||
ANSIBLE_LOOKUP_PLUGINS: "{{ ara_setup_plugins.stdout }}/lookup"
|
||||
ARA_DEBUG: "{{ ara_api_debug }}"
|
||||
ARA_LOG_LEVEL: "{{ ara_api_log_level }}"
|
||||
ARA_BASE_DIR: "{{ ara_api_root_dir }}/server"
|
||||
|
@ -120,6 +121,9 @@
|
|||
- name: Run smoke.yaml integration test
|
||||
command: "ansible-playbook -vvv {{ _test_root }}/smoke.yaml"
|
||||
|
||||
- name: Run lookup integration tests
|
||||
command: "ansible-playbook -vvv {{ _test_root }}/lookups.yaml"
|
||||
|
||||
- name: Run hosts.yaml integration test
|
||||
command: "ansible-playbook -vvv {{ _test_root }}/hosts.yaml"
|
||||
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
- name: Assert playbook properties
|
||||
hosts: localhost
|
||||
gather_facts: yes
|
||||
vars:
|
||||
ara_playbook_name: ARA self tests
|
||||
ara_playbook_labels:
|
||||
- lookup-tests
|
||||
tasks:
|
||||
- name: Retrieve the current playbook so we can get the ID
|
||||
ara_playbook:
|
||||
register: playbook_query
|
||||
|
||||
- name: Recover data from ARA
|
||||
vars:
|
||||
playbook_id: "{{ playbook_query.playbook.id | string }}"
|
||||
set_fact:
|
||||
playbook: "{{ lookup('ara_api', '/api/v1/playbooks/' + playbook_id) }}"
|
||||
tasks: "{{ lookup('ara_api', '/api/v1/tasks?playbook=' + playbook_id) }}"
|
||||
results: "{{ lookup('ara_api', '/api/v1/results?playbook=' + playbook_id) }}"
|
||||
|
||||
- name: Assert playbook properties
|
||||
assert:
|
||||
that:
|
||||
- playbook.name == 'ARA self tests'
|
||||
- "playbook.labels | selectattr('name', 'search', 'lookup-tests') | list | length == 1"
|
||||
- playbook.ansible_version == ansible_version.full
|
||||
- playbook_dir in playbook.path
|
||||
- "'tests/integration/lookups.yaml' in playbook.path"
|
||||
- "playbook.files | length == playbook['items']['files']"
|
||||
- "playbook.hosts | length == playbook['items']['hosts']"
|
||||
- "playbook.plays | length == playbook['items']['plays']"
|
||||
- "tasks.results | length == playbook['items']['tasks']"
|
||||
- "results.results | length == playbook['items']['results']"
|
|
@ -78,6 +78,7 @@
|
|||
- environment:
|
||||
ANSIBLE_CALLBACK_PLUGINS: "{{ ara_setup_plugins.stdout }}/callback"
|
||||
ANSIBLE_ACTION_PLUGINS: "{{ ara_setup_plugins.stdout }}/action"
|
||||
ANSIBLE_LOOKUP_PLUGINS: "{{ ara_setup_plugins.stdout }}/lookup"
|
||||
ARA_SETTINGS: "{{ ara_api_settings }}"
|
||||
ARA_API_CLIENT: "{{ ara_api_client | default('offline') }}"
|
||||
ARA_API_SERVER: "{{ ara_api_server | default('http://127.0.0.1:8000') }}"
|
||||
|
@ -90,6 +91,9 @@
|
|||
- name: Run smoke.yaml integration test
|
||||
command: "ansible-playbook -vvv {{ _test_root }}/smoke.yaml"
|
||||
|
||||
- name: Run lookups.yaml integration test
|
||||
command: "ansible-playbook -vvv {{ _test_root }}/lookups.yaml"
|
||||
|
||||
- name: Run hosts.yaml integration test
|
||||
command: "ansible-playbook -vvv {{ _test_root }}/hosts.yaml"
|
||||
|
||||
|
|
Loading…
Reference in New Issue