<commit_before>
from ansible.plugins.action import ActionBase
from distutils.version import LooseVersion

try:
    from __main__ import display
except ImportError:
    from ansible.utils.display import Display
    display = Display()

try:
    import notario
except ImportError:
    msg = "The python-notario library is missing. Please install it on the node you are running ceph-ansible to continue."
    display.error(msg)
    raise SystemExit(msg)

if LooseVersion(notario.__version__) < LooseVersion("0.0.13"):
    msg = "The python-notario libary has an incompatible version. Version >= 0.0.13 is needed, current version: %s" % notario.__version__
    display.error(msg)
    raise SystemExit(msg)

from notario.exceptions import Invalid
from notario.validators import types, chainable, iterables
from notario.decorators import optional
from notario.store import store as notario_store


CEPH_RELEASES = ['jewel', 'kraken', 'luminous', 'mimic']


class ActionModule(ActionBase):

    def run(self, tmp=None, task_vars=None):
        # we must use vars, since task_vars will have un-processed variables
        host_vars = task_vars['vars']
        host = host_vars['ansible_hostname']
        mode = self._task.args.get('mode', 'permissive')

        self._supports_check_mode = False # XXX ?
        self._supports_async = True

        result = {}
        result['_ansible_verbose_always'] = True

        try:
            notario_store["groups"] = host_vars["groups"]
            notario_store["containerized_deployment"] = host_vars["containerized_deployment"]
            notario.validate(host_vars, install_options, defined_keys=True)

            if host_vars["ceph_origin"] == "repository":
                notario.validate(host_vars, ceph_origin_repository, defined_keys=True)

                if host_vars["ceph_repository"] == "community":
                    notario.validate(host_vars, ceph_repository_community, defined_keys=True)

                if host_vars["ceph_repository"] == "rhcs":
                    notario.validate(host_vars, ceph_repository_rhcs, defined_keys=True)

                if host_vars["ceph_repository"] == "dev":
                    notario.validate(host_vars, ceph_repository_dev, defined_keys=True)

            # store these values because one must be defined and the validation method
            # will need access to all three through the store
            notario_store["monitor_address"] = host_vars.get("monitor_address", None)
            notario_store["monitor_address_block"] = host_vars.get("monitor_address_block", None)
            notario_store["monitor_interface"] = host_vars.get("monitor_interface", None)

            if host_vars["mon_group_name"] in host_vars["group_names"]:
                notario.validate(host_vars, monitor_options, defined_keys=True)

            notario_store["radosgw_address"] = host_vars.get("radosgw_address", None)
            notario_store["radosgw_address_block"] = host_vars.get("radosgw_address_block", None)
            notario_store["radosgw_interface"] = host_vars.get("radosgw_interface", None)

            if host_vars["rgw_group_name"] in host_vars["group_names"]:
                notario.validate(host_vars, rados_options, defined_keys=True)

            # validate osd scenario setup
            if host_vars["osd_group_name"] in host_vars["group_names"]:
                notario.validate(host_vars, osd_options, defined_keys=True)
                notario_store['osd_objectstore'] = host_vars["osd_objectstore"]
                if host_vars["osd_scenario"] == "collocated":
                    if not host_vars.get("osd_auto_discovery", False):
                        notario.validate(host_vars, collocated_osd_scenario, defined_keys=True)

                if host_vars["osd_scenario"] == "non-collocated":
                    notario.validate(host_vars, non_collocated_osd_scenario, defined_keys=True)

                if host_vars["osd_scenario"] == "lvm":
                    if host_vars.get("devices"):
                        notario.validate(host_vars, lvm_batch_scenario, defined_keys=True)
                    elif notario_store['osd_objectstore'] == 'filestore':
                        notario.validate(host_vars, lvm_filestore_scenario, defined_keys=True)
                    elif notario_store['osd_objectstore'] == 'bluestore':
                        notario.validate(host_vars, lvm_bluestore_scenario, defined_keys=True)

        except Invalid as error:
            display.vvvv("Notario Failure: %s" % str(error))
            msg = "[{}] Validation failed for variable: {}".format(host, error.path[0])
            display.error(msg)
            reason = "[{}] Reason: {}".format(host, error.reason)
            try:
                if "schema is missing" not in error.message:
                    for i in range(0, len(error.path)):
                        if i == 0:
                            given = "[{}] Given value for {}".format(
                                    host, error.path[0])
                        else:
                            given = given + ": {}".format(error.path[i])
                    display.error(given)
                else:
                    given = ""
                    reason = "[{}] Reason: {}".format(host, error.message)
            except KeyError:
                given = ""
            display.error(reason)
            result['failed'] = mode == 'strict'
            result['msg'] = "\n".join([msg, reason, given])
            result['stderr_lines'] = msg.split('\n')

        return result

# Schemas


def osd_objectstore_choices(value):
    assert value in ['bluestore', 'filestore'], "osd_objectstore must be either 'bluestore' or 'filestore'"


def ceph_origin_choices(value):
    if not notario_store["containerized_deployment"]:
        assert value in ['repository', 'distro', 'local'], "ceph_origin must be either 'repository', 'distro' or 'local'"


def ceph_repository_choices(value):
    assert value in ['community', 'rhcs', 'dev'], "ceph_repository must be either 'community', 'rhcs' or 'dev'"

<commit_msg>DNM: allow expanding Jinja2 template for Ansible custom plugin<commit_after>
from ansible.plugins.action import ActionBase
from distutils.version import LooseVersion
from ansible.errors import AnsibleUndefinedVariable

try:
    from __main__ import display
except ImportError:
    from ansible.utils.display import Display
    display = Display()

try:
    import notario
except ImportError:
    msg = "The python-notario library is missing. Please install it on the node you are running ceph-ansible to continue."
    display.error(msg)
    raise SystemExit(msg)

if LooseVersion(notario.__version__) < LooseVersion("0.0.13"):
    msg = "The python-notario libary has an incompatible version. Version >= 0.0.13 is needed, current version: %s" % notario.__version__
    display.error(msg)
    raise SystemExit(msg)

from notario.exceptions import Invalid
from notario.validators import types, chainable, iterables
from notario.decorators import optional
from notario.store import store as notario_store


CEPH_RELEASES = ['jewel', 'kraken', 'luminous', 'mimic']


class ActionModule(ActionBase):

    def run(self, tmp=None, task_vars=None):
        # we must use vars, since task_vars will have un-processed variables
        host_vars = task_vars['vars']

        # process jinja2 templates
        reqd_type = "<class 'ansible.parsing.yaml.objects.AnsibleUnicode'>"
        for k, v in host_vars.items():
            if str(type(v)) == reqd_type and len(v) > 2:
                if v[0] == v[1] == '{' and v[-1] == v[-2] == '}' and v[2] == \
                   v[-3] == ' ':
                    host_vars[k] = self._expand_jinja2_template(v)

        host = host_vars['ansible_hostname']
        mode = self._task.args.get('mode', 'permissive')

        self._supports_check_mode = False # XXX ?
        self._supports_async = True

        result = {}
        result['_ansible_verbose_always'] = True

        try:
            notario_store["groups"] = host_vars["groups"]
            notario_store["containerized_deployment"] = host_vars["containerized_deployment"]
            notario.validate(host_vars, install_options, defined_keys=True)

            if host_vars["ceph_origin"] == "repository":
                notario.validate(host_vars, ceph_origin_repository, defined_keys=True)

                if host_vars["ceph_repository"] == "community":
                    notario.validate(host_vars, ceph_repository_community, defined_keys=True)

                if host_vars["ceph_repository"] == "rhcs":
                    notario.validate(host_vars, ceph_repository_rhcs, defined_keys=True)

                if host_vars["ceph_repository"] == "dev":
                    notario.validate(host_vars, ceph_repository_dev, defined_keys=True)

            # store these values because one must be defined and the validation method
            # will need access to all three through the store
            notario_store["monitor_address"] = host_vars.get("monitor_address", None)
            notario_store["monitor_address_block"] = host_vars.get("monitor_address_block", None)
            notario_store["monitor_interface"] = host_vars.get("monitor_interface", None)

            if host_vars["mon_group_name"] in host_vars["group_names"]:
                notario.validate(host_vars, monitor_options, defined_keys=True)

            notario_store["radosgw_address"] = host_vars.get("radosgw_address", None)
            notario_store["radosgw_address_block"] = host_vars.get("radosgw_address_block", None)
            notario_store["radosgw_interface"] = host_vars.get("radosgw_interface", None)

            if host_vars["rgw_group_name"] in host_vars["group_names"]:
                notario.validate(host_vars, rados_options, defined_keys=True)

            # validate osd scenario setup
            if host_vars["osd_group_name"] in host_vars["group_names"]:
                notario.validate(host_vars, osd_options, defined_keys=True)
                notario_store['osd_objectstore'] = host_vars["osd_objectstore"]
                if host_vars["osd_scenario"] == "collocated":
                    if not host_vars.get("osd_auto_discovery", False):
                        notario.validate(host_vars, collocated_osd_scenario, defined_keys=True)

                if host_vars["osd_scenario"] == "non-collocated":
                    notario.validate(host_vars, non_collocated_osd_scenario, defined_keys=True)

                if host_vars["osd_scenario"] == "lvm":
                    if host_vars.get("devices"):
                        notario.validate(host_vars, lvm_batch_scenario, defined_keys=True)
                    elif notario_store['osd_objectstore'] == 'filestore':
                        notario.validate(host_vars, lvm_filestore_scenario, defined_keys=True)
                    elif notario_store['osd_objectstore'] == 'bluestore':
                        notario.validate(host_vars, lvm_bluestore_scenario, defined_keys=True)

        except Invalid as error:
            display.vvvv("Notario Failure: %s" % str(error))
            msg = "[{}] Validation failed for variable: {}".format(host, error.path[0])
            display.error(msg)
            reason = "[{}] Reason: {}".format(host, error.reason)
            try:
                if "schema is missing" not in error.message:
                    for i in range(0, len(error.path)):
                        if i == 0:
                            given = "[{}] Given value for {}".format(
                                    host, error.path[0])
                        else:
                            given = given + ": {}".format(error.path[i])
                    display.error(given)
                else:
                    given = ""
                    reason = "[{}] Reason: {}".format(host, error.message)
            except KeyError:
                given = ""
            display.error(reason)
            result['failed'] = mode == 'strict'
            result['msg'] = "\n".join([msg, reason, given])
            result['stderr_lines'] = msg.split('\n')

        return result

    def _expand_jinja2_template(self, var):
        try:
            expanded_var = self._templar.template(var, convert_bare=True, fail_on_undefined=True)
            if expanded_var == var:
                # if expanded_var is not str/unicode type, raise an exception
                if not isinstance(expanded_var, string_types):
                    raise AnsibleUndefinedVariable
                # If var name is same as result, try to template it
                expanded_var = self._templar.template("{{" + expanded_var + "}}", convert_bare=True, fail_on_undefined=True)
        except AnsibleUndefinedVariable as e:
            expanded_var = u"VARIABLE IS NOT DEFINED!"
            if self._display.verbosity > 0:
                expanded_var += u": %s" % str(e)

        return expanded_var

# Schemas


def osd_objectstore_choices(value):
    assert value in ['bluestore', 'filestore'], "osd_objectstore must be either 'bluestore' or 'filestore'"


def ceph_origin_choices(value):
    if not notario_store["containerized_deployment"]:
        assert value in ['repository', 'distro', 'local'], "ceph_origin must be either 'repository', 'distro' or 'local'"


def ceph_repository_choices(value):
    assert value in ['community', 'rhcs', 'dev'], "ceph_repository must be either 'community', 'rhcs' or 'dev'"


{'fraction_non_alphanumeric': 0.1058369799006156, 'fraction_numerical': 0.0026700289253133577, 'mean_word_length': 2.5169535732916013, 'pattern_counts': {'":': 17, '<': 6, '<?xml version=': 0, '>': 8, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6172070', 'n_tokens_mistral': 3940, 'n_tokens_neox': 3776, 'n_words': 858}