diff --git a/ara/plugins/action/ara_playbook.py b/ara/plugins/action/ara_playbook.py
new file mode 100644
index 00000000..33da11e9
--- /dev/null
+++ b/ara/plugins/action/ara_playbook.py
@@ -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 .
+
+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 "
+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
diff --git a/ara/plugins/lookup/ara_api.py b/ara/plugins/lookup/ara_api.py
new file mode 100644
index 00000000..84ff7155
--- /dev/null
+++ b/ara/plugins/lookup/ara_api.py
@@ -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 .
+
+
+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
diff --git a/ara/setup/__init__.py b/ara/setup/__init__.py
index e413f344..8ef87a08 100644
--- a/ara/setup/__init__.py
+++ b/ara/setup/__init__.py
@@ -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"))
diff --git a/ara/setup/ansible.py b/ara/setup/ansible.py
index d2ef26a0..49172668 100644
--- a/ara/setup/ansible.py
+++ b/ara/setup/ansible.py
@@ -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__":
diff --git a/ara/setup/env.py b/ara/setup/env.py
index 51bdf469..305a2b56 100644
--- a/ara/setup/env.py
+++ b/ara/setup/env.py
@@ -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:
diff --git a/ara/setup/lookup_plugins.py b/ara/setup/lookup_plugins.py
new file mode 100644
index 00000000..5c247832
--- /dev/null
+++ b/ara/setup/lookup_plugins.py
@@ -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 .
+
+from __future__ import print_function
+
+from . import lookup_plugins
+
+if __name__ == "__main__":
+ print(lookup_plugins)
diff --git a/doc/source/ansible-configuration.rst b/doc/source/ansible-configuration.rst
index 6102aa24..ae4afe60 100644
--- a/doc/source/ansible-configuration.rst
+++ b/doc/source/ansible-configuration.rst
@@ -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
diff --git a/doc/source/ara-api-lookup.rst b/doc/source/ara-api-lookup.rst
new file mode 100644
index 00000000..d38f9071
--- /dev/null
+++ b/doc/source/ara-api-lookup.rst
@@ -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 ` 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 ` 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) }}"
diff --git a/doc/source/index.rst b/doc/source/index.rst
index be667b34..e827836a 100644
--- a/doc/source/index.rst
+++ b/doc/source/index.rst
@@ -20,6 +20,7 @@ Table of Contents
API: Distributed sqlite backend
Setting playbook names and labels
Recording arbitrary data in playbooks
+ Querying ARA from inside playbooks
Contributing to ARA
.. toctree::
diff --git a/tests/basic.yaml b/tests/basic.yaml
index e0744dda..bf2394f3 100644
--- a/tests/basic.yaml
+++ b/tests/basic.yaml
@@ -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"
diff --git a/tests/integration/lookups.yaml b/tests/integration/lookups.yaml
new file mode 100644
index 00000000..7e55cbdd
--- /dev/null
+++ b/tests/integration/lookups.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']"
diff --git a/tests/test_tasks.yaml b/tests/test_tasks.yaml
index 956818a1..df56b396 100644
--- a/tests/test_tasks.yaml
+++ b/tests/test_tasks.yaml
@@ -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"