From d4964af1afb9c6e41ed7a7e78dccaaf587b296a8 Mon Sep 17 00:00:00 2001 From: Robin Pierre Cordier Date: Fri, 11 Feb 2022 12:20:15 -0500 Subject: [PATCH] Update: the whole code --- plugins/inventory/kheops.py | 215 ++++------------- plugins/lookup/kheops.py | 221 +++++++++++++++++ plugins/plugin_utils/common.py | 424 +++++++++++++++++++++++++++++++++ 3 files changed, 693 insertions(+), 167 deletions(-) create mode 100644 plugins/lookup/kheops.py create mode 100644 plugins/plugin_utils/common.py diff --git a/plugins/inventory/kheops.py b/plugins/inventory/kheops.py index 313985c..31fdba4 100644 --- a/plugins/inventory/kheops.py +++ b/plugins/inventory/kheops.py @@ -7,7 +7,17 @@ from __future__ import (absolute_import, division, print_function) __metaclass__ = type -from pprint import pprint + +import sys +import os +import logging + +from ansible import constants as C +from ansible.errors import AnsibleError +from ansible.plugins.inventory import BaseInventoryPlugin, Cacheable, Constructable + +#sys.path.append("/home/jez/prj/bell/training/tiger-ansible/ext/kheops") +from ansible_collections.barbu_it.ansible_kheops.plugins.plugin_utils.common import DOCUMENTATION_OPTION_FRAGMENT, AnsibleKheops DOCUMENTATION = ''' name: kheops @@ -26,102 +36,12 @@ DOCUMENTATION = ''' - inventory_cache - constructed options: + plugin: description: token that ensures this is a source file for the C(kheops) plugin. required: True choices: ['kheops', 'barbu_it.ansible_kheops.kheops'] - - - # Query configuration - # ========================== - query_namespace: - description: - - The Kheops namespace to use - default: 'default' - env: - - name: ANSIBLE_KHEOPS_NAMESPACE - query_scope: - description: - - A hash containing the scope to use for the request, the values will be resolved as Ansible facts. - - Use a dot notation to dig deeper into nested hash facts. - default: {} - query_keys: - description: - - A list of keys to lookup - default: {} - - - # Instance configuration - # ========================== - configuration: - description: - - Path to Kheops configuration yaml file - default: 'kheops.yml' - env: - - name: ANSIBLE_KHEOPS_CONFIG - log_level: - description: - - Khéops logging level - choices: ['DEBUG', 'INFO', 'WARNING', 'ERROR'] - default: 'WARNING' - env: - - name: ANSIBLE_KHEOPS_LOG_LEVEL - - # turfu # Client configuration - # turfu token: - # turfu description: - # turfu - The Kheops token to use to authenticate against Kheops server. - # turfu default: '' - # turfu env: - # turfu - name: ANSIBLE_KHEOPS_TOKEN - # turfu host: - # turfu description: - # turfu - Hostname of the Kheops Server. - # turfu default: '127.0.0.1' - # turfu env: - # turfu - name: ANSIBLE_KHEOPS_HOST - # turfu port: - # turfu description: - # turfu - Kheops port to connect to. - # turfu default: '9843' - # turfu env: - # turfu - name: ANSIBLE_KHEOPS_PORT - # turfu protocol: - # turfu description: - # turfu - The URL protocol to use. - # turfu default: 'http' - # turfu choices: ['http', 'https'] - # turfu env: - # turfu - name: ANSIBLE_KHEOPS_PROTOCOL - # turfu validate_certs: - # turfu description: - # turfu - Whether or not to verify the TLS certificates of the Kheops server. - # turfu type: boolean - # turfu default: False - # turfu env: - # turfu - name: ANSIBLE_KHEOPS_VALIDATE_CERTS - - # Uneeded # Misc - # Uneeded version: - # Uneeded description: - # Uneeded - Kheops API version to use. - # Uneeded default: 1 - # Uneeded choices: [1] - # Uneeded env: - # Uneeded - name: ANSIBLE_KHEOPS_VERSION - # Uneeded cache: - # Uneeded description: - # Uneeded - Enable Kheops inventory cache. - # Uneeded default: false - # Uneeded type: boolean - # Uneeded env: - # Uneeded - name: ANSIBLE_KHEOPS_CACHE - # Uneeded policy: - # Uneeded description: - # Uneeded - Kheops policy to use for the lookups. - # Uneeded default: 'default' - -''' +''' + DOCUMENTATION_OPTION_FRAGMENT EXAMPLES = ''' # zzz_dev.kheops.yml @@ -145,17 +65,7 @@ query_scope: environment: foreman_environment_name ''' -import sys -import os -import logging -from ansible import constants as C -from ansible.errors import AnsibleError -from ansible.plugins.inventory import BaseInventoryPlugin, Cacheable, Constructable - -#import kheops.app as Kheops -from kheops.app import Kheops - -sys.path.append("/home/jez/prj/bell/training/tiger-ansible/ext/kheops") +from pprint import pprint class InventoryModule(BaseInventoryPlugin, Cacheable, Constructable): @@ -172,81 +82,52 @@ class InventoryModule(BaseInventoryPlugin, Cacheable, Constructable): '''Return dynamic inventory from source ''' super(InventoryModule, self).parse(inventory, loader, path, cache) - self._read_config_data(path) - - # Read configuration - self.keys = self.get_option('query_keys') - self.scope = self.get_option('query_scope') - self.namespace = self.get_option('query_namespace') + config_data = self._read_config_data(path) + #self._consume_options(config_data) self.strict = self.get_option('strict') - self.configuration = self.get_option('configuration') - self.log_level = self.get_option('log_level') - self.cache_enabled = os.environ.get( - 'ANSIBLE_KHEOPS_CACHE', - str(self.get_option('cache')) - ).lower() in ('true', '1', 't') + self.compose = self.get_option('compose') + self.groups = self.get_option('groups') + self.keyed_groups = self.get_option('keyed_groups') + + self.config_file = self.get_option('config') - # Determine cache behavior - #attempt_to_read_cache = self.cache_enabled and cache - - # Khéops instance - kheops = Kheops(config=self.configuration, namespace=self.namespace) - - # Khéops log support - log_level = getattr(logging, self.log_level, 'DEBUG') - - logger = logging.getLogger('kheops') - logger.setLevel(log_level) - - # See for logging: https://medium.com/opsops/debugging-requests-1989797736cc - class ListLoggerHandler(logging.Handler): - def emit(self, record): - msg = self.format(record) - - list_logging_handler = ListLoggerHandler() - main_logger = logging.getLogger() - main_logger.addHandler(list_logging_handler) - main_logger.setLevel(logging.DEBUG) - - # from pyinstrument import Profiler - #profiler = Profiler() - #profiler.start() + configs = [ + self.config_file, + path, + ] + kheops = AnsibleKheops(configs=configs, display=self.display) # Loop over each keys for host_name in inventory.hosts: - host = self.inventory.get_host(host_name) + host = self.inventory.get_host(host_name) - # Build the scope - scope = {} - host_vars = host.get_vars() - for key, val in self.scope.items(): - scope[key] = host_vars.get(val, None) - self.display.vvv(f"Kheops scope for {host.name}: {scope} for keys: {self.keys}") + scope = kheops.get_scope_from_host_inventory(host.get_vars(), scope=None) - # Fetch the results - ret = kheops.lookup( - keys=[ key_src for key_dst, key_src in self.keys.items() ], - scope=scope, - #trace=True, - #explain=True, - ) + # Fetch the results + ret = kheops.lookup( + keys=None, + scope=scope, + #trace=True, + #explain=True, + ) - # Inject variables into host - for ansible_key, kheops_key in self.keys.items(): - ansible_value = ret.get(kheops_key) - host.set_variable(ansible_key, ansible_value) + # Inject variables into host + for key, value in ret.items(): + self.display.vv (f"Set {host_name} var: {key}={value}") + host.set_variable(key, value) - # Call constructed inventory plugin methods - hostvars = self.inventory.get_host(host_name).get_vars() - self._set_composite_vars(self.get_option('compose'), hostvars, host_name, self.strict) - self._add_host_to_composed_groups(self.get_option('groups'), hostvars, host_name, self.strict) - self._add_host_to_keyed_groups(self.get_option('keyed_groups'), hostvars, host_name, self.strict) + # Call constructed inventory plugin methods + #hostvars = self.inventory.get_host(host_name).get_vars() + hostvars = host.get_vars() + + #tutu = hostvars.get('tiger_profiles', "MISSSSINGGGG") + #print ("YOOOOO", tutu, self.keyed_groups, host_name, self.strict) - #profiler.stop() - ##profiler.print() - #profiler.open_in_browser() + self._set_composite_vars(self.compose, hostvars, host_name, self.strict) + self._add_host_to_composed_groups(self.groups, hostvars, host_name, self.strict) + self._add_host_to_keyed_groups(self.keyed_groups, hostvars, host_name, self.strict) diff --git a/plugins/lookup/kheops.py b/plugins/lookup/kheops.py new file mode 100644 index 0000000..42e7829 --- /dev/null +++ b/plugins/lookup/kheops.py @@ -0,0 +1,221 @@ +# Copyright 2021 Robin Cordier +# Copyright 2017 Craig Dunn +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import json +import os +import sys +import requests +import yaml + + +from copy import deepcopy +from ansible.errors import AnsibleError +from ansible.plugins.lookup import LookupBase +from ansible.template import generate_ansible_template_vars, AnsibleEnvironment, USE_JINJA2_NATIVE + +from ansible_collections.barbu_it.ansible_kheops.plugins.plugin_utils.common import DOCUMENTATION_OPTION_FRAGMENT, AnsibleKheops + + +try: + from __main__ import display +except ImportError: + from ansible.utils.display import Display + display = Display() + +if USE_JINJA2_NATIVE: + from ansible.utils.native_jinja import NativeJinjaText + +DOCUMENTATION = """ + lookup: kheops + author: Robin Cordier + version_added: "3" + short_description: read key/values from Kheops + description: + - This lookup returns the contents of a Kheops key + - This is an improved fork of https://github.com/kheops/kheops-ansible-lookup-plugin + - This fork provides python3 support and more query options + options: + _terms: + description: One or more string terms prefixed by a namespace. Format is `/`. + required: True + + enable_jinja: + description: + - Enable or not Jinja rendering + default: True + version_added: '2.11' + type: bool + jinja2_native: + description: + - Controls whether to use Jinja2 native types. + - It is off by default even if global jinja2_native is True. + - Has no effect if global jinja2_native is False. + - This offers more flexibility than the template module which does not use Jinja2 native types at all. + - Mutually exclusive with the convert_data option. + default: False + version_added: '2.11' + type: bool + notes: + - Kheops documentation is available on http://kheops.io/ + - You can add more parameters as documented in http://kheops.io/server/api + +""" + DOCUMENTATION_OPTION_FRAGMENT + +EXAMPLES = """ +- name: Return the value of key + debug: + msg: "{{ lookup('kheops', 'default/key') }}" + +- name: Return a list of values + debug: + msg: "{{ lookup('kheops', 'ansible/yum_packages', 'ansible/yum_repos') }}" + +- name: Advanced usage + debug: + msg: "{{ lookup('kheops', 'ansible/yum_packages', merge='deep_hash', lookup_type='cascade') }}" + +- name: Advanced usage with custom parameters + debug: + msg: "{{ lookup('kheops', 'ansible/yum_packages', policy='ansible') }}" + +""" + +RETURN = """ + _data: + description: + - Value of the key, when only one term is searched + _list: + description: + - List of value of the keys, when more than one term is searched + type: list + +""" + +from pprint import pprint + +# Entry point for Ansible starts here with the LookupModule class +class LookupModule(LookupBase): + def run(self, terms, variables=None, scope=None, **kwargs): + + + self.set_options(direct=kwargs) + #self.config_file = self.get_option('config') + + self.config_file = self.get_option('config') + + configs = [ + self.config_file, +# { +# "instance_log_level": 'DEBUG', +# } + ] + kheops = AnsibleKheops(configs=configs, display=self._display) + + + scope = kheops.get_scope_from_host_inventory(variables, scope=None) + scope = kheops.get_scope_from_jinja(variables, self._templar, scope=None) + + #assert False , f"OUTOUT: {scope2}" + + + #for key, value in self.get_option('scope').items(): + # scope[key] = variables[value] + + ret = [] + for term in terms: + result = kheops.lookup( + keys=term, + scope=scope, + ) + ret.append(result) + + return ret + + + + + + # if isinstance(terms, str): + # terms = terms.split(',') + + # import ansible_collections.barbu_it.ansible_kheops.plugins.plugin_utils.common as kheops_utils + # AnsibleKheops = kheops_utils.AnsibleKheops + # kheops = AnsibleKheops() + + # return None + + # assert isinstance(terms, list), f"Expected a list, got: {terms}" + + # # Parse arguments + # kwargs = kwargs or {} + # #enable_jinja = kwargs.pop('enable_jinja', True) + # #jinja2_native = kwargs.pop('jinja2_native', False) + + # #enable_jinja = kwargs.pop('enable_jinja', True) + # #jinja2_native = kwargs.pop('jinja2_native', False) + + # self.namespace = self.get_option('query_namespace') + # self.configuration = self.get_option('configuration') + + # # Instanciate Kheops client + # kheops = Kheops(config=self.configuration, namespace=self.namespace) + + # for term in terms: + # print ("Lookup for key: ", term) + + + # print ("WIIIIIIIIPPPPPPPPPPPPPPPPP") + + # # Start jinja template engine + # if enable_jinja: + # if USE_JINJA2_NATIVE and not jinja2_native: + # templar = self._templar.copy_with_new_env(environment_class=AnsibleEnvironment) + # else: + # templar = self._templar + + # # Look for each terms + # ret = [] + # for term in terms: + # lookuppath = term.split('/') + # key = lookuppath.pop() + # namespace = lookuppath + + # if not namespace: + # raise AnsibleError("No namespace given for lookup of key %s" % key) + + # response = kheops.lookup(key=key, namespace=namespace, variables=variables, kwargs=kwargs) + + # # Render data with Jinja + # if enable_jinja: + # # Build a copy of environment vars + # vars = deepcopy(variables) + + # # Render data with Templar + # with templar.set_temporary_context(available_variables=vars): + # res = templar.template(response['payload'], preserve_trailing_newlines=True, + # convert_data=False, escape_backslashes=False) + + # if USE_JINJA2_NATIVE and not jinja2_native: + # # jinja2_native is true globally but off for the lookup, we need this text + # # not to be processed by literal_eval anywhere in Ansible + # res = NativeJinjaText(res) + # else: + # res = response['payload'] + + # # Append response to response array + # ret.append(res) + + # return ret + diff --git a/plugins/plugin_utils/common.py b/plugins/plugin_utils/common.py new file mode 100644 index 0000000..39d44fe --- /dev/null +++ b/plugins/plugin_utils/common.py @@ -0,0 +1,424 @@ +# -*- coding: utf-8 -*- + + + + +DOCUMENTATION_OPTION_FRAGMENT = ''' + + # Plugin configuration + # ========================== + config: + description: + - Path to Kheops configuration yaml file + - Can be useful to reuse and merge existing configurations + - All settings of the target files can be overriden from this file + - Ignored if blank or Null + default: Null + env: + - name: ANSIBLE_KHEOPS_CONFIG + + mode: + description: + - Choose `client` to use a remote Khéops instance + - Choose `instance` to use a Khéops directly + default: 'instance' + choices: ['instance', 'client'] + env: + - name: ANSIBLE_KHEOPS_MODE + + # default_namespace: + # description: + # - The Kheops namespace to use + # default: 'default' + # env: + # - name: ANSIBLE_KHEOPS_DEFAULT_NAMESPACE + + # default_scope: + # description: + # - A list of default variables to inject in scope. + # default: 'default' + # env: + # - name: ANSIBLE_KHEOPS_DEFAULT_SCOPE + + + # Instance configuration (Direct) + # ========================== + # Instance configuration + instance_config: + description: + - The Kheops configuration file to use. + default: 'site/kheops.yml' + env: + - name: ANSIBLE_KHEOPS_INSTANCE_CONFIG + instance_namespace: + description: + - The Kheops configuration file to use. + default: 'default' + env: + - name: ANSIBLE_KHEOPS_INSTANCE_NAMESPACE + instance_log_level: + description: + - Khéops logging level + choices: ['DEBUG', 'INFO', 'WARNING', 'ERROR'] + default: 'WARNING' + env: + - name: ANSIBLE_KHEOPS_LOG_LEVEL + + + # Instance configuration (Client) + # ========================== + # turfu # Client configuration + # turfu client_token: + # turfu description: + # turfu - The Kheops token to use to authenticate against Kheops server. + # turfu default: '' + # turfu env: + # turfu - name: ANSIBLE_KHEOPS_TOKEN + # turfu client_host: + # turfu description: + # turfu - Hostname of the Kheops Server. + # turfu default: '127.0.0.1' + # turfu env: + # turfu - name: ANSIBLE_KHEOPS_HOST + # turfu client_port: + # turfu description: + # turfu - Kheops port to connect to. + # turfu default: '9843' + # turfu env: + # turfu - name: ANSIBLE_KHEOPS_PORT + # turfu client_protocol: + # turfu description: + # turfu - The URL protocol to use. + # turfu default: 'http' + # turfu choices: ['http', 'https'] + # turfu env: + # turfu - name: ANSIBLE_KHEOPS_PROTOCOL + # turfu client_validate_certs: + # turfu description: + # turfu - Whether or not to verify the TLS certificates of the Kheops server. + # turfu type: boolean + # turfu default: False + # turfu env: + # turfu - name: ANSIBLE_KHEOPS_VALIDATE_CERTS + + + # Query configuration + # ========================== + namespace: + description: + - The Kheops namespace to use + default: 'default' + env: + - name: ANSIBLE_KHEOPS_DEFAULT_NAMESPACE + scope: + description: + - A hash containing the scope to use for the request, the values will be resolved as Ansible facts. + - Use a dot notation to dig deeper into nested hash facts. + default: + node: inventory_hostname + groups: group_names + + keys: + description: + - A list of keys to lookup + default: Null + + + # Uneeded # Misc + # Uneeded version: + # Uneeded description: + # Uneeded - Kheops API version to use. + # Uneeded default: 1 + # Uneeded choices: [1] + # Uneeded env: + # Uneeded - name: ANSIBLE_KHEOPS_VERSION + # Uneeded cache: + # Uneeded description: + # Uneeded - Enable Kheops inventory cache. + # Uneeded default: false + # Uneeded type: boolean + # Uneeded env: + # Uneeded - name: ANSIBLE_KHEOPS_CACHE + # Uneeded policy: + # Uneeded description: + # Uneeded - Kheops policy to use for the lookups. + # Uneeded default: 'default' + +''' + +import os +import sys +import yaml +import logging +from dataclasses import dataclass +from typing import Any, Union + +from copy import deepcopy + +# Devel mode +sys.path.append("/home/jez/prj/bell/training/tiger-ansible/ext/kheops") + +from kheops.app import Kheops + +from ansible.errors import AnsibleError +from ansible.module_utils.common.text.converters import to_native +from ansible.template import generate_ansible_template_vars, AnsibleEnvironment, USE_JINJA2_NATIVE + +from pprint import pprint + +KEY_NS_SEP = '/' +if USE_JINJA2_NATIVE: + from ansible.utils.native_jinja import NativeJinjaText + + +@dataclass +class Key: + key: str + remap: Union[str, type(None)] + namespace: Union[type(None), str] + + def show(self): + ret = self.key + if self.namespace is not None: + ret = f"{self.namespace}{KEY_NS_SEP}{ret}" + return ret + + +class AnsibleKheops(): + + + def __init__(self, configs=None, display=None): + + self.configs = configs or [] + self.display = display or print + + config = self.get_config() + # print ("CURRENT CONFIG vv") + # pprint (config) + # print ("CURRENT CONFIG ^^") + + self.init_templar() + + # Instanciate Kheops + if config["mode"] == 'instance': + + # Confiogure logging + logger = logging.getLogger('kheops') + logger.setLevel(config["instance_log_level"]) + + # See for logging: https://medium.com/opsops/debugging-requests-1989797736cc + class ListLoggerHandler(logging.Handler): + def emit(self, record): + msg = self.format(record) + + main_logger = logging.getLogger() + main_logger.addHandler(ListLoggerHandler()) + main_logger.setLevel(logging.DEBUG) + + # Start instance + self.kheops = Kheops( + config=config['instance_config'], + namespace=config['instance_namespace'] + ) + elif config["mode"] == 'client': + raise AnsibleError("Kheops client mode is not implemented") + + self.config = config + print ("Kheops instance is OK") + + + def get_config(self): + items = [ + # We exclude 'config' + 'mode', + 'instance_config', 'instance_namespace', 'instance_log_level', + 'namespace', 'scope', 'keys'] + + + # Extract default value from doc + data_doc = yaml.safe_load(DOCUMENTATION_OPTION_FRAGMENT) + default_config = {key: value.get("default", None) for key, value in data_doc.items()} + + + merged_configs = {} + for config in self.configs: + + conf_data = None + if isinstance(config, str): + #print ("Read file", config) + if os.path.isfile(config): + data = open(config, "r") + conf_data = yaml.safe_load(data) + else: + raise AnsibleError("Unable to find configuration file %s" % config_file) + + elif isinstance(config, dict): + #print ("Read Config", config) + conf_data = config + else: + assert False, f"Bad config for: {config}" + + assert isinstance(conf_data, dict), f"Bug with conf_data: {config_data}" + if isinstance(conf_data, dict): + merged_configs.update(conf_data) + + + # Get environment config + env_config = {} + for item in items: + envvar = "ANSIBLE_KHEOPS_" + item.upper() + try: + env_config[item] = os.environ[envvar] + except KeyError as err: + pass + + # Merge results + combined_config = {} + combined_config.update(default_config) + combined_config.update(env_config) + combined_config.update(merged_configs) + + + # out = { + # "0_default": default_config, + # "1_env": env_config, + # "2_common": merged_configs, + # } + # print ('=' * 20) + # pprint (out) + # print ('=' * 20) + # pprint (combined_config) + # print ('=' * 20) + + + return combined_config + + + + @staticmethod + def parse_string(item, default_namespace): + key = None + remap = key + namespace = default_namespace + + if isinstance(item, str): + + parts = item.split('/', 3) + #print (len(parts)) + + if len(parts) > 0: + key = parts[0] + if len(parts) > 1: + namespace = parts[0] + key = parts[1] + if len(parts) > 2: + remap = parts[2] + + elif isinstance(item, dict): + key = item.get('key') + remap = item.get('remap', key) + namespace = item.get('namespace', namespace) + + return Key(key=key, + remap=remap, + namespace=namespace) + + + @classmethod + def parse_keys(self, data, namespace): + + keys = [] + + if isinstance(data, str): + keys.append(self.parse_string(data, namespace)) + + elif isinstance(data, list): + for item in data: + keys.append(self.parse_string(item, namespace)) + elif isinstance(data, dict): + for key, value in data.items(): + item = key + if value: + assert isinstance(value, str), f"Need a string, got: {value}" + item = f"{key}{KEY_NS_SEP}{value}" + + keys.append(self.parse_string(item, namespace)) + + else: + raise AnsibleError("Unable to process Kheops keys: %s" % keys) + + return keys + + + def get_scope_from_host_inventory(self, host_vars, scope=None): + scope = scope or self.config['scope'] + ret = {} + for key, val in scope.items(): + # Tofix should this fail silently ? + ret[key] = host_vars.get(val, None) + + return ret + + def init_templar(self, enable_jinja=True, jinja2_native=False): + pass + + def get_scope_from_jinja(self, host_vars, templar, scope=None, jinja2_native=False): + scope = scope or self.config['scope'] + ret = {} + + if USE_JINJA2_NATIVE and not jinja2_native: + _templar = templar.copy_with_new_env(environment_class=AnsibleEnvironment) + else: + _templar = templar + + _vars = deepcopy(host_vars) + with _templar.set_temporary_context(available_variables=_vars): + res = _templar.template(scope, preserve_trailing_newlines=True, + convert_data=False, escape_backslashes=False) + if USE_JINJA2_NATIVE and not jinja2_native: + # jinja2_native is true globally but off for the lookup, we need this text + # not to be processed by literal_eval anywhere in Ansible + res = NativeJinjaText(res) + + return res + + + + def lookup(self, keys, namespace=None, scope=None, kwargs=None): + + namespace = namespace or self.config['namespace'] + scope = scope or self.config['scope'] + keys = keys or self.config['keys'] + keys_config = self.parse_keys(keys, namespace) + keys = [ i.show() for i in keys_config ] + + # self.base.display.v(f"Kheops keys: {keys}") + # self.base.display.vv(f"Kheops scope: {scope}") + + + print ("LOOKUP QUERY: ", keys, scope) + #try: + ret = self.kheops.lookup( + keys=keys, + scope=scope, + #trace=True, + #explain=True, + ) + #except Exception as err: + # assert False, f"{err.__traceback__}" + # assert False, f"{dir(err)}" + # raise AnsibleError('Something happened, this was original exception: %s' % to_native(err)) + # assert False, f"MY ERRRROR {err}" + + # self.display.v(err) + + print ("RESULT: ", ret) + # Remap output + #for key in keys_config: + # if key.remap != key.key: + # ret[key.remap] = ret[key.key] + # del ret[key.key] + + return ret or {} + +