diff --git a/src/rougail/output_ansible/__init__.py b/src/rougail/output_ansible/__init__.py index 2ffbed4..22f2607 100644 --- a/src/rougail/output_ansible/__init__.py +++ b/src/rougail/output_ansible/__init__.py @@ -38,35 +38,43 @@ class RougailOutputAnsible(RougailOutputJson): **kwargs, ) -> None: super().__init__(config, rougailconfig=rougailconfig, **kwargs) - try: - groups.namespace - self.support_namespace = True - except AttributeError: - self.support_namespace = False def exporter(self) -> None: self.host_namespace = self.rougailconfig["ansible.host_namespace"] self.export_warnings = self.rougailconfig["ansible.export_warnings"] self.no_namespace_in_vars = self.rougailconfig["ansible.no_namespace_in_vars"] + self.hosts = {} super().exporter() self.json_to_ansible() # never return code 1, error are in the output data return True + def parse_variable(self, option, child, namespace): + if self.support_namespace and namespace and "ansible_host" in option.information.get("tags", tuple()): + hosts = option.value.get() + if not isinstance(hosts, list): + hosts = [hosts] + if namespace in self.hosts: + self.hosts[namespace].update(hosts) + else: + self.hosts[namespace] = hosts + super().parse_variable(option, child, namespace) + def manage_errors(self) -> bool: if not super().manage_errors(): if not self.support_namespace: self.errors.append(_("no namespace configured")) - hosts_config = self.config.option("hosts") + hosts_config = self.config.option(self.host_namespace) try: if hosts_config.group_type() != groups.namespace: hosts_config = None except AttributeError: hosts_config = None if not hosts_config: - self.errors.append( - _('cannot find host namespace "{0}"').format(self.host_namespace) - ) + if not self.hosts: + self.errors.append( + _('cannot find host namespace "{0}"').format(self.host_namespace) + ) else: try: hosts_config.option("hostnames").name() @@ -98,6 +106,7 @@ class RougailOutputAnsible(RougailOutputJson): ret["ungrouped"] = {"hosts": ["localhost"]} if self.host_namespace in self.dico: hosts = self.dico.pop(self.host_namespace) + # manage groups if "hostnames" not in hosts: ret["_meta"]["hostvars"].setdefault("localhost", {}).setdefault( "_errors", [] @@ -130,6 +139,7 @@ class RougailOutputAnsible(RougailOutputJson): ) else: ret[name] = hosts + # manage hostsnames and vars in hostsname for hosts in ret_hosts.values(): for host, domain_name in hosts.items(): ret["_meta"]["hostvars"][host] = {"ansible_host": domain_name} @@ -148,6 +158,19 @@ class RougailOutputAnsible(RougailOutputJson): ret["_meta"]["hostvars"][host][namespace] = self.dico[namespace] else: ret["_meta"]["hostvars"][host].update(self.dico) + # manage hostnames define with tag ansible_host and add groups + for namespace, hosts in self.hosts.items(): + if namespace not in ret: + ret[namespace] = {"hosts": []} + for host in hosts: + if host not in ret["_meta"]["hostvars"]: + ret["_meta"]["hostvars"][host] = {"ansible_host": host} + if self.no_namespace_in_vars: + ret["_meta"]["hostvars"][host].update(self.dico[namespace]) + elif namespace not in ret["_meta"]["hostvars"][host]: + ret["_meta"]["hostvars"][host][namespace] = self.dico[namespace] + if host not in ret[namespace]["hosts"]: + ret[namespace]["hosts"].append(host) self.dico = ret diff --git a/tests/results/test_namespace/01_6string_multi_length.json b/tests/results/test_namespace/01_6string_multi_length.json new file mode 100644 index 0000000..e84b7fc --- /dev/null +++ b/tests/results/test_namespace/01_6string_multi_length.json @@ -0,0 +1,99 @@ +{ + "_meta": { + "hostvars": { + "GROUP1_01": { + "ansible_host": "group1.net", + "rougail": { + "var1": [ + "val1", + "val2", + "val3" + ], + "var2": [ + "val4", + "val5" + ] + } + }, + "GROUP2_01": { + "ansible_host": "group2.net", + "rougail": { + "var1": [ + "val1", + "val2", + "val3" + ], + "var2": [ + "val4", + "val5" + ] + } + }, + "GROUP2_02": { + "ansible_host": "group3.net", + "rougail": { + "var1": [ + "val1", + "val2", + "val3" + ], + "var2": [ + "val4", + "val5" + ] + } + }, + "group4.net": { + "ansible_host": "group4.net", + "rougail": { + "var1": [ + "val1", + "val2", + "val3" + ], + "var2": [ + "val4", + "val5" + ] + } + }, + "group5.net": { + "ansible_host": "group5.net", + "rougail": { + "var1": [ + "val1", + "val2", + "val3" + ], + "var2": [ + "val4", + "val5" + ] + } + } + } + }, + "group1": { + "hosts": [ + "GROUP1_01" + ] + }, + "group2": { + "hosts": [ + "GROUP2_01", + "GROUP2_02" + ] + }, + "group3": { + "hosts": [ + "group4.net", + "group5.net" + ] + }, + "groups": { + "children": [ + "group1", + "group2" + ] + } +} \ No newline at end of file diff --git a/tests/results/test_namespace_mandatory/01_6string_multi_length.json b/tests/results/test_namespace_mandatory/01_6string_multi_length.json new file mode 100644 index 0000000..a4af998 --- /dev/null +++ b/tests/results/test_namespace_mandatory/01_6string_multi_length.json @@ -0,0 +1,104 @@ +{ + "_meta": { + "hostvars": { + "GROUP1_01": { + "ansible_host": "group1.net", + "rougail": { + "var1": [ + "string1", + "string2", + "string3" + ], + "var2": [ + "string1", + "string2", + "string3" + ] + } + }, + "GROUP2_01": { + "ansible_host": "group2.net", + "rougail": { + "var1": [ + "string1", + "string2", + "string3" + ], + "var2": [ + "string1", + "string2", + "string3" + ] + } + }, + "GROUP2_02": { + "ansible_host": "group3.net", + "rougail": { + "var1": [ + "string1", + "string2", + "string3" + ], + "var2": [ + "string1", + "string2", + "string3" + ] + } + }, + "group4.net": { + "ansible_host": "group4.net", + "rougail": { + "var1": [ + "string1", + "string2", + "string3" + ], + "var2": [ + "string1", + "string2", + "string3" + ] + } + }, + "group5.net": { + "ansible_host": "group5.net", + "rougail": { + "var1": [ + "string1", + "string2", + "string3" + ], + "var2": [ + "string1", + "string2", + "string3" + ] + } + } + } + }, + "group1": { + "hosts": [ + "GROUP1_01" + ] + }, + "group2": { + "hosts": [ + "GROUP2_01", + "GROUP2_02" + ] + }, + "group3": { + "hosts": [ + "group4.net", + "group5.net" + ] + }, + "groups": { + "children": [ + "group1", + "group2" + ] + } +} \ No newline at end of file diff --git a/tests/results/test_namespace_mandatory/60_5family_dynamic_calc_description.json b/tests/results/test_namespace_mandatory/60_5family_dynamic_calc_description.json new file mode 100644 index 0000000..d803fb4 --- /dev/null +++ b/tests/results/test_namespace_mandatory/60_5family_dynamic_calc_description.json @@ -0,0 +1,114 @@ +{ + "_meta": { + "hostvars": { + "GROUP1_01": { + "ansible_host": "group1.net", + "rougail": { + "dynval1": { + "var": "string1" + }, + "dynval2": { + "var": "string1" + }, + "var1": "string1", + "var2": [ + "string1", + "string2", + "string3" + ] + } + }, + "GROUP2_01": { + "ansible_host": "group2.net", + "rougail": { + "dynval1": { + "var": "string1" + }, + "dynval2": { + "var": "string1" + }, + "var1": "string1", + "var2": [ + "string1", + "string2", + "string3" + ] + } + }, + "GROUP2_02": { + "ansible_host": "group3.net", + "rougail": { + "dynval1": { + "var": "string1" + }, + "dynval2": { + "var": "string1" + }, + "var1": "string1", + "var2": [ + "string1", + "string2", + "string3" + ] + } + }, + "group4.net": { + "ansible_host": "group4.net", + "rougail": { + "dynval1": { + "var": "string1" + }, + "dynval2": { + "var": "string1" + }, + "var1": "string1", + "var2": [ + "string1", + "string2", + "string3" + ] + } + }, + "group5.net": { + "ansible_host": "group5.net", + "rougail": { + "dynval1": { + "var": "string1" + }, + "dynval2": { + "var": "string1" + }, + "var1": "string1", + "var2": [ + "string1", + "string2", + "string3" + ] + } + } + } + }, + "group1": { + "hosts": [ + "GROUP1_01" + ] + }, + "group2": { + "hosts": [ + "GROUP2_01", + "GROUP2_02" + ] + }, + "group3": { + "hosts": [ + "group4.net", + "group5.net" + ] + }, + "groups": { + "children": [ + "group1", + "group2" + ] + } +} \ No newline at end of file diff --git a/tests/results/test_namespace_read_write/01_6string_multi_length.json b/tests/results/test_namespace_read_write/01_6string_multi_length.json new file mode 100644 index 0000000..e84b7fc --- /dev/null +++ b/tests/results/test_namespace_read_write/01_6string_multi_length.json @@ -0,0 +1,99 @@ +{ + "_meta": { + "hostvars": { + "GROUP1_01": { + "ansible_host": "group1.net", + "rougail": { + "var1": [ + "val1", + "val2", + "val3" + ], + "var2": [ + "val4", + "val5" + ] + } + }, + "GROUP2_01": { + "ansible_host": "group2.net", + "rougail": { + "var1": [ + "val1", + "val2", + "val3" + ], + "var2": [ + "val4", + "val5" + ] + } + }, + "GROUP2_02": { + "ansible_host": "group3.net", + "rougail": { + "var1": [ + "val1", + "val2", + "val3" + ], + "var2": [ + "val4", + "val5" + ] + } + }, + "group4.net": { + "ansible_host": "group4.net", + "rougail": { + "var1": [ + "val1", + "val2", + "val3" + ], + "var2": [ + "val4", + "val5" + ] + } + }, + "group5.net": { + "ansible_host": "group5.net", + "rougail": { + "var1": [ + "val1", + "val2", + "val3" + ], + "var2": [ + "val4", + "val5" + ] + } + } + } + }, + "group1": { + "hosts": [ + "GROUP1_01" + ] + }, + "group2": { + "hosts": [ + "GROUP2_01", + "GROUP2_02" + ] + }, + "group3": { + "hosts": [ + "group4.net", + "group5.net" + ] + }, + "groups": { + "children": [ + "group1", + "group2" + ] + } +} \ No newline at end of file diff --git a/tests/results/test_namespace_read_write/60_5family_dynamic_calc_description.json b/tests/results/test_namespace_read_write/60_5family_dynamic_calc_description.json new file mode 100644 index 0000000..1aa5e21 --- /dev/null +++ b/tests/results/test_namespace_read_write/60_5family_dynamic_calc_description.json @@ -0,0 +1,109 @@ +{ + "_meta": { + "hostvars": { + "GROUP1_01": { + "ansible_host": "group1.net", + "rougail": { + "dynval1": { + "var": null + }, + "dynval2": { + "var": null + }, + "var1": null, + "var2": [ + null, + null + ] + } + }, + "GROUP2_01": { + "ansible_host": "group2.net", + "rougail": { + "dynval1": { + "var": null + }, + "dynval2": { + "var": null + }, + "var1": null, + "var2": [ + null, + null + ] + } + }, + "GROUP2_02": { + "ansible_host": "group3.net", + "rougail": { + "dynval1": { + "var": null + }, + "dynval2": { + "var": null + }, + "var1": null, + "var2": [ + null, + null + ] + } + }, + "group4.net": { + "ansible_host": "group4.net", + "rougail": { + "dynval1": { + "var": null + }, + "dynval2": { + "var": null + }, + "var1": null, + "var2": [ + null, + null + ] + } + }, + "group5.net": { + "ansible_host": "group5.net", + "rougail": { + "dynval1": { + "var": null + }, + "dynval2": { + "var": null + }, + "var1": null, + "var2": [ + null, + null + ] + } + } + } + }, + "group1": { + "hosts": [ + "GROUP1_01" + ] + }, + "group2": { + "hosts": [ + "GROUP2_01", + "GROUP2_02" + ] + }, + "group3": { + "hosts": [ + "group4.net", + "group5.net" + ] + }, + "groups": { + "children": [ + "group1", + "group2" + ] + } +} \ No newline at end of file diff --git a/tests/results/test_namespace_read_write_mandatory/01_6string_multi_length.json b/tests/results/test_namespace_read_write_mandatory/01_6string_multi_length.json new file mode 100644 index 0000000..a4af998 --- /dev/null +++ b/tests/results/test_namespace_read_write_mandatory/01_6string_multi_length.json @@ -0,0 +1,104 @@ +{ + "_meta": { + "hostvars": { + "GROUP1_01": { + "ansible_host": "group1.net", + "rougail": { + "var1": [ + "string1", + "string2", + "string3" + ], + "var2": [ + "string1", + "string2", + "string3" + ] + } + }, + "GROUP2_01": { + "ansible_host": "group2.net", + "rougail": { + "var1": [ + "string1", + "string2", + "string3" + ], + "var2": [ + "string1", + "string2", + "string3" + ] + } + }, + "GROUP2_02": { + "ansible_host": "group3.net", + "rougail": { + "var1": [ + "string1", + "string2", + "string3" + ], + "var2": [ + "string1", + "string2", + "string3" + ] + } + }, + "group4.net": { + "ansible_host": "group4.net", + "rougail": { + "var1": [ + "string1", + "string2", + "string3" + ], + "var2": [ + "string1", + "string2", + "string3" + ] + } + }, + "group5.net": { + "ansible_host": "group5.net", + "rougail": { + "var1": [ + "string1", + "string2", + "string3" + ], + "var2": [ + "string1", + "string2", + "string3" + ] + } + } + } + }, + "group1": { + "hosts": [ + "GROUP1_01" + ] + }, + "group2": { + "hosts": [ + "GROUP2_01", + "GROUP2_02" + ] + }, + "group3": { + "hosts": [ + "group4.net", + "group5.net" + ] + }, + "groups": { + "children": [ + "group1", + "group2" + ] + } +} \ No newline at end of file diff --git a/tests/results/test_namespace_read_write_mandatory/60_5family_dynamic_calc_description.json b/tests/results/test_namespace_read_write_mandatory/60_5family_dynamic_calc_description.json new file mode 100644 index 0000000..d803fb4 --- /dev/null +++ b/tests/results/test_namespace_read_write_mandatory/60_5family_dynamic_calc_description.json @@ -0,0 +1,114 @@ +{ + "_meta": { + "hostvars": { + "GROUP1_01": { + "ansible_host": "group1.net", + "rougail": { + "dynval1": { + "var": "string1" + }, + "dynval2": { + "var": "string1" + }, + "var1": "string1", + "var2": [ + "string1", + "string2", + "string3" + ] + } + }, + "GROUP2_01": { + "ansible_host": "group2.net", + "rougail": { + "dynval1": { + "var": "string1" + }, + "dynval2": { + "var": "string1" + }, + "var1": "string1", + "var2": [ + "string1", + "string2", + "string3" + ] + } + }, + "GROUP2_02": { + "ansible_host": "group3.net", + "rougail": { + "dynval1": { + "var": "string1" + }, + "dynval2": { + "var": "string1" + }, + "var1": "string1", + "var2": [ + "string1", + "string2", + "string3" + ] + } + }, + "group4.net": { + "ansible_host": "group4.net", + "rougail": { + "dynval1": { + "var": "string1" + }, + "dynval2": { + "var": "string1" + }, + "var1": "string1", + "var2": [ + "string1", + "string2", + "string3" + ] + } + }, + "group5.net": { + "ansible_host": "group5.net", + "rougail": { + "dynval1": { + "var": "string1" + }, + "dynval2": { + "var": "string1" + }, + "var1": "string1", + "var2": [ + "string1", + "string2", + "string3" + ] + } + } + } + }, + "group1": { + "hosts": [ + "GROUP1_01" + ] + }, + "group2": { + "hosts": [ + "GROUP2_01", + "GROUP2_02" + ] + }, + "group3": { + "hosts": [ + "group4.net", + "group5.net" + ] + }, + "groups": { + "children": [ + "group1", + "group2" + ] + } +} \ No newline at end of file diff --git a/tests/results/test_namespace_read_write_mandatory_errors/01_6string_multi_length.json b/tests/results/test_namespace_read_write_mandatory_errors/01_6string_multi_length.json new file mode 100644 index 0000000..e84b7fc --- /dev/null +++ b/tests/results/test_namespace_read_write_mandatory_errors/01_6string_multi_length.json @@ -0,0 +1,99 @@ +{ + "_meta": { + "hostvars": { + "GROUP1_01": { + "ansible_host": "group1.net", + "rougail": { + "var1": [ + "val1", + "val2", + "val3" + ], + "var2": [ + "val4", + "val5" + ] + } + }, + "GROUP2_01": { + "ansible_host": "group2.net", + "rougail": { + "var1": [ + "val1", + "val2", + "val3" + ], + "var2": [ + "val4", + "val5" + ] + } + }, + "GROUP2_02": { + "ansible_host": "group3.net", + "rougail": { + "var1": [ + "val1", + "val2", + "val3" + ], + "var2": [ + "val4", + "val5" + ] + } + }, + "group4.net": { + "ansible_host": "group4.net", + "rougail": { + "var1": [ + "val1", + "val2", + "val3" + ], + "var2": [ + "val4", + "val5" + ] + } + }, + "group5.net": { + "ansible_host": "group5.net", + "rougail": { + "var1": [ + "val1", + "val2", + "val3" + ], + "var2": [ + "val4", + "val5" + ] + } + } + } + }, + "group1": { + "hosts": [ + "GROUP1_01" + ] + }, + "group2": { + "hosts": [ + "GROUP2_01", + "GROUP2_02" + ] + }, + "group3": { + "hosts": [ + "group4.net", + "group5.net" + ] + }, + "groups": { + "children": [ + "group1", + "group2" + ] + } +} \ No newline at end of file diff --git a/tests/results/test_namespace_read_write_mandatory_errors/60_5family_dynamic_calc_description.json b/tests/results/test_namespace_read_write_mandatory_errors/60_5family_dynamic_calc_description.json new file mode 100644 index 0000000..fc1038b --- /dev/null +++ b/tests/results/test_namespace_read_write_mandatory_errors/60_5family_dynamic_calc_description.json @@ -0,0 +1,20 @@ +{ + "_meta": { + "hostvars": { + "localhost": { + "_errors": [ + "The following variables are mandatory but have no value:", + " - rougail.dynval1.var (A dynamic variable for val1)", + " - rougail.dynval2.var (A dynamic variable for val2)", + " - rougail.var1 (A new variable)", + " - rougail.var2 (A new variable)" + ] + } + } + }, + "ungrouped": { + "hosts": [ + "localhost" + ] + } +} \ No newline at end of file diff --git a/tests/test_load.py b/tests/test_load.py index 2098a90..dbcc40a 100644 --- a/tests/test_load.py +++ b/tests/test_load.py @@ -57,6 +57,7 @@ def _test_structural_files(test_dir, namespace, ext, *, read_write=True, mandato ################################## rougail = Rougail(rougailconfig) config = rougail.run() + config.information.set("description_type", "name_and_description") ################################## if do_calc and (mandatory or not read_write): if mandatory: