diff --git a/changelogs/fragments/lookup_all_folders.yml b/changelogs/fragments/lookup_all_folders.yml new file mode 100644 index 000000000..a8af31cd5 --- /dev/null +++ b/changelogs/fragments/lookup_all_folders.yml @@ -0,0 +1,2 @@ +major_changes: ++ - all_folders lookup plugin - Add a lookup plugin that exposes the REST API endpoint /domain-types/folder_config/collections/all diff --git a/changelogs/fragments/lookup_folder.yml b/changelogs/fragments/lookup_folder.yml new file mode 100644 index 000000000..6bf95d17e --- /dev/null +++ b/changelogs/fragments/lookup_folder.yml @@ -0,0 +1,2 @@ +major_changes: ++ - folder lookup plugin - Add a lookup plugin that exposes the REST API endpoint /objects/folder_config/ diff --git a/playbooks/demo/full.yml b/playbooks/demo/full.yml index a7b54fb69..934d44e8e 100644 --- a/playbooks/demo/full.yml +++ b/playbooks/demo/full.yml @@ -1,4 +1,6 @@ --- +- name: "Lookup Plugins." + ansible.builtin.import_playbook: lookup.yml - name: "Hosts and Folders." ansible.builtin.import_playbook: hosts-and-folders.yml - name: "Groups." diff --git a/playbooks/demo/lookup.yml b/playbooks/demo/lookup.yml new file mode 100644 index 000000000..6c5278d77 --- /dev/null +++ b/playbooks/demo/lookup.yml @@ -0,0 +1,72 @@ +--- +- name: "Showcase Lookup Plugins." + hosts: test + strategy: linear + gather_facts: false + vars_files: + - ../vars/auth.yml # This vars file provides details about your site + tasks: + + - name: "Get Checkmk version." + debug: + msg: "Version is {{ version }}" + vars: + version: "{{ lookup('checkmk.general.version', + server_url + '/' + site, + validate_certs=False, + automation_user=automation_user, + automation_secret=automation_secret + )}}" + + delegate_to: localhost + run_once: 'true' + + - name: "Get all subfolders of the main folder recursively" + ansible.builtin.debug: + msg: "Folder tree: {{ item.id }}" + loop: "{{ + lookup('checkmk.general.all_folders', + '~', + show_hosts=False, + recursive=True, + site_url=server_url + '/' + site, + automation_user=automation_user, + automation_secret=automation_secret, + validate_certs=False + ) + }}" + loop_control: + label: "{{ item.id }}" + + - name: "Get all hosts of the folder /test recursively" + ansible.builtin.debug: + msg: "Host found in {{ item.0.id }}: {{ item.1.title }}" + vars: + looping: "{{ + lookup('checkmk.general.all_folders', + '~tests', + show_hosts=True, + recursive=True, + site_url=server_url + '/' + site, + automation_user=automation_user, + automation_secret=automation_secret, + validate_certs=False + ) + }}" + loop: "{{ looping|subelements('members.hosts.value') }}" + loop_control: + label: "{{ item.0.id }}" + + - name: "Get the attributes of folder /tests" + ansible.builtin.debug: + msg: "Attributes of folder /network: {{ attributes }}" + vars: + attributes: "{{ + lookup('checkmk.general.folder', + '~tests', + site_url=server_url + '/' + site, + automation_user=automation_user, + automation_secret=automation_secret, + validate_certs=False + ) + }}" diff --git a/plugins/lookup/all_folders.py b/plugins/lookup/all_folders.py new file mode 100644 index 000000000..e81ad6d43 --- /dev/null +++ b/plugins/lookup/all_folders.py @@ -0,0 +1,128 @@ +# Copyright: (c) 2023, Lars Getwan +# 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 = """ + name: all_folders + author: Lars Getwan (@lgetwan) + version_added: "3.1.0" + short_description: Get various information about a folder + description: + - Returns a list of subfolders + - Returns a list of hosts of the folder + options: + _terms: + description: complete folder path using tilde as a delimiter + required: True + show_hosts: + description: Also show the hosts of the folder(s) found + type: boolean + required: False + default: False + recursive: + description: Do a recursive query + type: boolean + required: False + default: False + site_url: + description: site url + required: True + automation_user: + description: automation user for the REST API access + required: True + automation_secret: + description: automation secret for the REST API access + required: True + validate_certs: + description: Wether or not to validate TLS cerificates + type: boolean + required: False + default: True +""" + +EXAMPLES = """ +- name: Get all subfolders of the main folder recursively + ansible.builtin.debug: + msg: "Folder tree: {{ item.id }}" + loop: "{{ + lookup('checkmk.general.all_folders', + '~', + show_hosts=False, + recursive=True, + site_url=server_url + '/' + site, + automation_user=automation_user, + automation_secret=automation_secret, + validate_certs=False + ) + }}" + loop_control: + label: "{{ item.id }}" + +- name: Get all hosts of the folder /test recursively + ansible.builtin.debug: + msg: "Host found in {{ item.0.id }}: {{ item.1.title }}" + vars: + looping: "{{ + lookup('checkmk.general.all_folders', + '~tests', + show_hosts=True, + recursive=True, + site_url=server_url + '/' + site, + automation_user=automation_user, + automation_secret=automation_secret, + validate_certs=False + ) + }}" + loop: "{{ looping|subelements('members.hosts.value') }}" + loop_control: + label: "{{ item.0.id }}" +""" + +RETURN = """ + _list: + description: + - A list of folders and, optionally, hosts of a folder + type: list + elements: str +""" + +import json + +from ansible.plugins.lookup import LookupBase +from .api import CheckMKLookupAPI + + +class LookupModule(LookupBase): + def run(self, terms, variables, **kwargs): + self.set_options(var_options=variables, direct=kwargs) + show_hosts = self.get_option("show_hosts") + recursive = self.get_option("recursive") + site_url = self.get_option("site_url") + user = self.get_option("automation_user") + secret = self.get_option("automation_secret") + validate_certs = self.get_option("validate_certs") + + api = CheckMKLookupAPI( + site_url=site_url, + user=user, + secret=secret, + validate_certs=validate_certs, + ) + + ret = [] + for term in terms: + parameters = { + "parent": term, + "recursive": recursive, + "show_hosts": show_hosts, + } + + response = json.loads( + api.get("/domain-types/folder_config/collections/all", parameters) + ) + ret.append(response.get("value")) + + return ret diff --git a/plugins/lookup/api.py b/plugins/lookup/api.py new file mode 100644 index 000000000..3ea7c7a08 --- /dev/null +++ b/plugins/lookup/api.py @@ -0,0 +1,59 @@ +#!/usr/bin/env python +# -*- encoding: utf-8; py-indent-offset: 4 -*- + +# Copyright: (c) 2023, Lars Getwan +# 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 + +from urllib.error import HTTPError, URLError +from urllib.parse import urlencode + +from ansible.errors import AnsibleError +from ansible.module_utils.common.text.converters import to_native, to_text +from ansible.module_utils.urls import ConnectionError, SSLValidationError, open_url + + +class CheckMKLookupAPI: + """Base class to contact a Checkmk server for ~Lookup calls""" + + def __init__(self, site_url, user, secret, validate_certs=True): + self.site_url = site_url + self.user = user + self.secret = secret + self.validate_certs = validate_certs + self.url = "%s/check_mk/api/1.0" % site_url + self.headers = { + "Accept": "application/json", + "Content-Type": "application/json", + "Authorization": "Bearer %s %s" % (user, secret), + } + + def get(self, endpoint="", parameters={}): + url = self.url + endpoint + + if parameters: + url = "%s?%s" % (url, urlencode(parameters)) + + response = "" + try: + raw_response = open_url( + url, headers=self.headers, validate_certs=self.validate_certs + ) + response = to_text(raw_response.read()) + + except HTTPError as e: + raise AnsibleError("Received HTTP error for %s : %s" % (url, to_native(e))) + except URLError as e: + raise AnsibleError("Failed lookup url for %s : %s" % (url, to_native(e))) + except SSLValidationError as e: + raise AnsibleError( + "Error validating the server's certificate for %s: %s" + % (url, to_native(e)) + ) + except ConnectionError as e: + raise AnsibleError("Error connecting to %s: %s" % (url, to_native(e))) + + return response diff --git a/plugins/lookup/folder.py b/plugins/lookup/folder.py new file mode 100644 index 000000000..941430459 --- /dev/null +++ b/plugins/lookup/folder.py @@ -0,0 +1,87 @@ +# Copyright: (c) 2023, Lars Getwan +# 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 = """ + name: folder + author: Lars Getwan (@lgetwan) + version_added: "3.1.0" + short_description: Get folder attributes + description: + - Returns the attributes of a folder + options: + _terms: + description: complete folder path using tilde as a delimiter + required: True + site_url: + description: site url + required: True + automation_user: + description: automation user for the REST API access + required: True + automation_secret: + description: automation secret for the REST API access + required: True + validate_certs: + description: Wether or not to validate TLS cerificates + type: boolean + required: False + default: True +""" + +EXAMPLES = """ +- name: Get the attributes of folder /tests + ansible.builtin.debug: + msg: "Attributes of folder /network: {{ attributes }}" + vars: + attributes: "{{ + lookup('checkmk.general.folder', + '~tests', + site_url=server_url + '/' + site, + automation_user=automation_user, + automation_secret=automation_secret, + validate_certs=False + ) + }}" +""" + +RETURN = """ + _list: + description: + - A list of dicts of attributes of the folder(s) + type: list + elements: str +""" + +import json + +from ansible.plugins.lookup import LookupBase +from .api import CheckMKLookupAPI + + +class LookupModule(LookupBase): + def run(self, terms, variables, **kwargs): + self.set_options(var_options=variables, direct=kwargs) + site_url = self.get_option("site_url") + user = self.get_option("automation_user") + secret = self.get_option("automation_secret") + validate_certs = self.get_option("validate_certs") + + api = CheckMKLookupAPI( + site_url=site_url, + user=user, + secret=secret, + validate_certs=validate_certs, + ) + + ret = [] + for term in terms: + api_endpoint = "/objects/folder_config/" + term + + response = json.loads(api.get("/objects/folder_config/" + term)) + ret.append(response.get("extensions", {}).get("attributes")) + + return ret