From 2bb34923fe93a44e212b5173749d5aac14794b7b Mon Sep 17 00:00:00 2001 From: Anil Gadiyar Date: Mon, 18 Nov 2024 13:50:19 +0530 Subject: [PATCH 1/5] wip --- meta/runtime.yml | 2 + plugins/modules/dns_auth_nsg.py | 603 ++++++++++++++++++ plugins/modules/dns_auth_nsg_info.py | 386 +++++++++++ .../targets/dns_auth_nsg/tasks/main.yml | 170 +++++ .../targets/dns_auth_nsg_info/tasks/main.yml | 60 ++ 5 files changed, 1221 insertions(+) create mode 100644 plugins/modules/dns_auth_nsg.py create mode 100644 plugins/modules/dns_auth_nsg_info.py create mode 100644 tests/integration/targets/dns_auth_nsg/tasks/main.yml create mode 100644 tests/integration/targets/dns_auth_nsg_info/tasks/main.yml diff --git a/meta/runtime.yml b/meta/runtime.yml index 55f479e..04cf94a 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -11,6 +11,8 @@ action_groups: - dns_auth_zone_info - dns_forward_zone - dns_forward_zone_info + - dns_auth_nsg + - dns_auth_nsg_info ipam: - ipam_ip_space - ipam_ip_space_info diff --git a/plugins/modules/dns_auth_nsg.py b/plugins/modules/dns_auth_nsg.py new file mode 100644 index 0000000..905afdb --- /dev/null +++ b/plugins/modules/dns_auth_nsg.py @@ -0,0 +1,603 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: Infoblox Inc. +# 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 = r""" +--- +module: dns_auth_nsg +short_description: Manage AuthNsg +description: + - Manage AuthNsg +version_added: 2.0.0 +author: Infoblox Inc. (@infobloxopen) +options: + id: + description: + - ID of the object + type: str + required: false + state: + description: + - Indicate desired state of the object + type: str + required: false + choices: + - present + - absent + default: present + comment: + description: + - "Optional. Comment for the object." + type: str + external_primaries: + description: + - "Optional. DNS primaries external to BloxOne DDI. Order is not significant." + type: list + elements: dict + suboptions: + address: + description: + - "Optional. Required only if I(type) is I(server). IP Address of nameserver." + type: str + fqdn: + description: + - "Optional. Required only if I(type) is I(server). FQDN of nameserver." + type: str + nsg: + description: + - "The resource identifier." + type: str + tsig_enabled: + description: + - "Optional. If enabled, secondaries will use the configured TSIG key when requesting a zone transfer from this primary." + type: bool + tsig_key: + description: + - "Optional. TSIG key." + - "Error if empty while I(tsig_enabled) is I(true)." + type: dict + suboptions: + algorithm: + description: + - "TSIG key algorithm." + - "Possible values:" + - "* I(hmac_sha256)," + - "* I(hmac_sha1)," + - "* I(hmac_sha224)," + - "* I(hmac_sha384)," + - "* I(hmac_sha512)." + type: str + comment: + description: + - "Comment for TSIG key." + type: str + key: + description: + - "The resource identifier." + type: str + name: + description: + - "TSIG key name, FQDN." + type: str + secret: + description: + - "TSIG key secret, base64 string." + type: str + type: + description: + - "Allowed values:" + - "* I(nsg)," + - "* I(primary)." + type: str + external_secondaries: + description: + - "DNS secondaries external to BloxOne DDI. Order is not significant." + type: list + elements: dict + suboptions: + address: + description: + - "IP Address of nameserver." + type: str + fqdn: + description: + - "FQDN of nameserver." + type: str + stealth: + description: + - "If enabled, the NS record and glue record will NOT be automatically generated according to secondaries nameserver assignment." + - "Default: I(false)" + type: bool + tsig_enabled: + description: + - "If enabled, secondaries will use the configured TSIG key when requesting a zone transfer." + - "Default: I(false)" + type: bool + tsig_key: + description: + - "TSIG key." + - "Error if empty while I(tsig_enabled) is I(true)." + type: dict + suboptions: + algorithm: + description: + - "TSIG key algorithm." + - "Possible values:" + - "* I(hmac_sha256)," + - "* I(hmac_sha1)," + - "* I(hmac_sha224)," + - "* I(hmac_sha384)," + - "* I(hmac_sha512)." + type: str + comment: + description: + - "Comment for TSIG key." + type: str + key: + description: + - "The resource identifier." + type: str + name: + description: + - "TSIG key name, FQDN." + type: str + secret: + description: + - "TSIG key secret, base64 string." + type: str + internal_secondaries: + description: + - "Optional. BloxOne DDI hosts acting as internal secondaries. Order is not significant." + type: list + elements: dict + suboptions: + host: + description: + - "The resource identifier." + type: str + name: + description: + - "Name of the object." + type: str + nsgs: + description: + - "The resource identifier." + type: list + elements: str + tags: + description: + - "Tagging specifics." + type: dict + +extends_documentation_fragment: + - infoblox.bloxone.common +""" # noqa: E501 + +EXAMPLES = r""" + - name: Create an Auth NSG + infoblox.bloxone.dns_auth_nsg: + name: "example_nsg" + state: "present" + + - name: Create an Auth NSG with Additional Fields + infoblox.bloxone.dns_auth_nsg: + name: "example_nsg" + comment: "Example Auth NSG" + external_primaries: + - address: "1.1.1.1" + fqdn: "a.com." + type: "primary" + state: "present" + tags: + location: "my-location" + + - name: Delete the Auth NSG + infoblox.bloxone.dns_auth_nsg: + name: "example_nsg" + state: "absent" +""" # noqa: E501 + +RETURN = r""" +id: + description: + - ID of the AuthNsg object + type: str + returned: Always +item: + description: + - AuthNsg object + type: complex + returned: Always + contains: + comment: + description: + - "Optional. Comment for the object." + type: str + returned: Always + external_primaries: + description: + - "Optional. DNS primaries external to BloxOne DDI. Order is not significant." + type: list + returned: Always + elements: dict + contains: + address: + description: + - "Optional. Required only if I(type) is I(server). IP Address of nameserver." + type: str + returned: Always + fqdn: + description: + - "Optional. Required only if I(type) is I(server). FQDN of nameserver." + type: str + returned: Always + nsg: + description: + - "The resource identifier." + type: str + returned: Always + protocol_fqdn: + description: + - "FQDN of nameserver in punycode." + type: str + returned: Always + tsig_enabled: + description: + - "Optional. If enabled, secondaries will use the configured TSIG key when requesting a zone transfer from this primary." + type: bool + returned: Always + tsig_key: + description: + - "Optional. TSIG key." + - "Error if empty while I(tsig_enabled) is I(true)." + type: dict + returned: Always + contains: + algorithm: + description: + - "TSIG key algorithm." + - "Possible values:" + - "* I(hmac_sha256)," + - "* I(hmac_sha1)," + - "* I(hmac_sha224)," + - "* I(hmac_sha384)," + - "* I(hmac_sha512)." + type: str + returned: Always + comment: + description: + - "Comment for TSIG key." + type: str + returned: Always + key: + description: + - "The resource identifier." + type: str + returned: Always + name: + description: + - "TSIG key name, FQDN." + type: str + returned: Always + protocol_name: + description: + - "TSIG key name in punycode." + type: str + returned: Always + secret: + description: + - "TSIG key secret, base64 string." + type: str + returned: Always + type: + description: + - "Allowed values:" + - "* I(nsg)," + - "* I(primary)." + type: str + returned: Always + external_secondaries: + description: + - "DNS secondaries external to BloxOne DDI. Order is not significant." + type: list + returned: Always + elements: dict + contains: + address: + description: + - "IP Address of nameserver." + type: str + returned: Always + fqdn: + description: + - "FQDN of nameserver." + type: str + returned: Always + protocol_fqdn: + description: + - "FQDN of nameserver in punycode." + type: str + returned: Always + stealth: + description: + - "If enabled, the NS record and glue record will NOT be automatically generated according to secondaries nameserver assignment." + - "Default: I(false)" + type: bool + returned: Always + tsig_enabled: + description: + - "If enabled, secondaries will use the configured TSIG key when requesting a zone transfer." + - "Default: I(false)" + type: bool + returned: Always + tsig_key: + description: + - "TSIG key." + - "Error if empty while I(tsig_enabled) is I(true)." + type: dict + returned: Always + contains: + algorithm: + description: + - "TSIG key algorithm." + - "Possible values:" + - "* I(hmac_sha256)," + - "* I(hmac_sha1)," + - "* I(hmac_sha224)," + - "* I(hmac_sha384)," + - "* I(hmac_sha512)." + type: str + returned: Always + comment: + description: + - "Comment for TSIG key." + type: str + returned: Always + key: + description: + - "The resource identifier." + type: str + returned: Always + name: + description: + - "TSIG key name, FQDN." + type: str + returned: Always + protocol_name: + description: + - "TSIG key name in punycode." + type: str + returned: Always + secret: + description: + - "TSIG key secret, base64 string." + type: str + returned: Always + id: + description: + - "The resource identifier." + type: str + returned: Always + internal_secondaries: + description: + - "Optional. BloxOne DDI hosts acting as internal secondaries. Order is not significant." + type: list + returned: Always + elements: dict + contains: + host: + description: + - "The resource identifier." + type: str + returned: Always + name: + description: + - "Name of the object." + type: str + returned: Always + nsgs: + description: + - "The resource identifier." + type: list + returned: Always + tags: + description: + - "Tagging specifics." + type: dict + returned: Always +""" # noqa: E501 + +from ansible_collections.infoblox.bloxone.plugins.module_utils.modules import BloxoneAnsibleModule + +try: + from bloxone_client import ApiException, NotFoundException + from dns_config import AuthNSG, AuthNsgApi +except ImportError: + pass # Handled by BloxoneAnsibleModule + + +class AuthNsgModule(BloxoneAnsibleModule): + def __init__(self, *args, **kwargs): + super(AuthNsgModule, self).__init__(*args, **kwargs) + + exclude = ["state", "csp_url", "api_key", "id"] + self._payload_params = {k: v for k, v in self.params.items() if v is not None and k not in exclude} + self._payload = AuthNSG.from_dict(self._payload_params) + self._existing = None + + @property + def existing(self): + return self._existing + + @existing.setter + def existing(self, value): + self._existing = value + + @property + def payload_params(self): + return self._payload_params + + @property + def payload(self): + return self._payload + + def payload_changed(self): + if self.existing is None: + # if existing is None, then it is a create operation + return True + + return self.is_changed(self.existing.model_dump(by_alias=True, exclude_none=True), self.payload_params) + + def find(self): + if self.params["id"] is not None: + try: + resp = AuthNsgApi(self.client).read(self.params["id"], inherit="full") + return resp.result + except NotFoundException as e: + if self.params["state"] == "absent": + return None + raise e + else: + filter = f"name=='{self.params['name']}'" + resp = AuthNsgApi(self.client).list(filter=filter) + if len(resp.results) == 1: + return resp.results[0] + if len(resp.results) > 1: + self.fail_json(msg=f"Found multiple AuthNsg: {resp.results}") + if len(resp.results) == 0: + return None + + def create(self): + if self.check_mode: + return None + + resp = AuthNsgApi(self.client).create(body=self.payload) + return resp.result.model_dump(by_alias=True, exclude_none=True) + + def update(self): + if self.check_mode: + return None + + resp = AuthNsgApi(self.client).update(id=self.existing.id, body=self.payload) + return resp.result.model_dump(by_alias=True, exclude_none=True) + + def delete(self): + if self.check_mode: + return + + AuthNsgApi(self.client).delete(self.existing.id) + + def run_command(self): + result = dict(changed=False, object={}, id=None) + + # based on the state that is passed in, we will execute the appropriate + # functions + try: + self.existing = self.find() + item = {} + if self.params["state"] == "present" and self.existing is None: + item = self.create() + result["changed"] = True + result["msg"] = "AuthNsg created" + elif self.params["state"] == "present" and self.existing is not None: + if self.payload_changed(): + item = self.update() + result["changed"] = True + result["msg"] = "AuthNsg updated" + elif self.params["state"] == "absent" and self.existing is not None: + self.delete() + result["changed"] = True + result["msg"] = "AuthNsg deleted" + + if self.check_mode: + # if in check mode, do not update the result or the diff, just return the changed state + self.exit_json(**result) + + result["diff"] = dict( + before=self.existing.model_dump(by_alias=True, exclude_none=True) if self.existing is not None else {}, + after=item, + ) + result["object"] = item + result["id"] = ( + self.existing.id if self.existing is not None else item["id"] if (item and "id" in item) else None + ) + except ApiException as e: + self.fail_json(msg=f"Failed to execute command: {e.status} {e.reason} {e.body}") + + self.exit_json(**result) + + +def main(): + module_args = dict( + id=dict(type="str", required=False), + state=dict(type="str", required=False, choices=["present", "absent"], default="present"), + comment=dict(type="str"), + external_primaries=dict( + type="list", + elements="dict", + options=dict( + address=dict(type="str"), + fqdn=dict(type="str"), + nsg=dict(type="str"), + tsig_enabled=dict(type="bool"), + tsig_key=dict( + type="dict", + options=dict( + algorithm=dict(type="str"), + comment=dict(type="str"), + key=dict(type="str"), + name=dict(type="str"), + secret=dict(type="str"), + ), + ), + type=dict(type="str"), + ), + ), + external_secondaries=dict( + type="list", + elements="dict", + options=dict( + address=dict(type="str"), + fqdn=dict(type="str"), + stealth=dict(type="bool"), + tsig_enabled=dict(type="bool"), + tsig_key=dict( + type="dict", + options=dict( + algorithm=dict(type="str"), + comment=dict(type="str"), + key=dict(type="str"), + name=dict(type="str"), + secret=dict(type="str"), + ), + ), + ), + ), + internal_secondaries=dict( + type="list", + elements="dict", + options=dict( + host=dict(type="str"), + ), + ), + name=dict(type="str"), + nsgs=dict(type="list", elements="str"), + tags=dict(type="dict"), + ) + + module = AuthNsgModule( + argument_spec=module_args, + supports_check_mode=True, + required_if=[("state", "present", ["name"])], + ) + + module.run_command() + + +if __name__ == "__main__": + main() diff --git a/plugins/modules/dns_auth_nsg_info.py b/plugins/modules/dns_auth_nsg_info.py new file mode 100644 index 0000000..f27966e --- /dev/null +++ b/plugins/modules/dns_auth_nsg_info.py @@ -0,0 +1,386 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- + +# Copyright: Infoblox Inc. +# 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 = r""" +--- +module: dns_auth_nsg_info +short_description: Manage AuthNsg +description: + - Manage AuthNsg +version_added: 2.0.0 +author: Infoblox Inc. (@infobloxopen) +options: + id: + description: + - ID of the object + type: str + required: false + filters: + description: + - Filter dict to filter objects + type: dict + required: false + filter_query: + description: + - Filter query to filter objects + type: str + required: false + inherit: + description: + - Return inheritance information + type: str + required: false + choices: + - full + - partial + - none + default: full + tag_filters: + description: + - Filter dict to filter objects by tags + type: dict + required: false + tag_filter_query: + description: + - Filter query to filter objects by tags + type: str + required: false + +extends_documentation_fragment: + - infoblox.bloxone.common +""" # noqa: E501 + +EXAMPLES = r""" + - name: Get Auth NSG information by ID + infoblox.bloxone.dns_auth_nsg_info: + id: "{{ auth_nsg_id }}" + + - name: Get Auth NSG information by filters (e.g. name) + infoblox.bloxone.dns_auth_nsg_info: + filters: + name: "example_nsg" + + - name: Get Auth NSG information by raw filter query + infoblox.bloxone.dns_auth_nsg_info: + filter_query: "name=='example_nsg'" + + - name: Get Auth NSG information by tag filters + infoblox.bloxone.dns_auth_nsg_info: + tag_filters: + location: "site-1" +""" # noqa: E501 + +RETURN = r""" +id: + description: + - ID of the AuthNsg object + type: str + returned: Always +objects: + description: + - AuthNsg object + type: list + elements: dict + returned: Always + contains: + comment: + description: + - "Optional. Comment for the object." + type: str + returned: Always + external_primaries: + description: + - "Optional. DNS primaries external to BloxOne DDI. Order is not significant." + type: list + returned: Always + elements: dict + contains: + address: + description: + - "Optional. Required only if I(type) is I(server). IP Address of nameserver." + type: str + returned: Always + fqdn: + description: + - "Optional. Required only if I(type) is I(server). FQDN of nameserver." + type: str + returned: Always + nsg: + description: + - "The resource identifier." + type: str + returned: Always + protocol_fqdn: + description: + - "FQDN of nameserver in punycode." + type: str + returned: Always + tsig_enabled: + description: + - "Optional. If enabled, secondaries will use the configured TSIG key when requesting a zone transfer from this primary." + type: bool + returned: Always + tsig_key: + description: + - "Optional. TSIG key." + - "Error if empty while I(tsig_enabled) is I(true)." + type: dict + returned: Always + contains: + algorithm: + description: + - "TSIG key algorithm." + - "Possible values:" + - "* I(hmac_sha256)," + - "* I(hmac_sha1)," + - "* I(hmac_sha224)," + - "* I(hmac_sha384)," + - "* I(hmac_sha512)." + type: str + returned: Always + comment: + description: + - "Comment for TSIG key." + type: str + returned: Always + key: + description: + - "The resource identifier." + type: str + returned: Always + name: + description: + - "TSIG key name, FQDN." + type: str + returned: Always + protocol_name: + description: + - "TSIG key name in punycode." + type: str + returned: Always + secret: + description: + - "TSIG key secret, base64 string." + type: str + returned: Always + type: + description: + - "Allowed values:" + - "* I(nsg)," + - "* I(primary)." + type: str + returned: Always + external_secondaries: + description: + - "DNS secondaries external to BloxOne DDI. Order is not significant." + type: list + returned: Always + elements: dict + contains: + address: + description: + - "IP Address of nameserver." + type: str + returned: Always + fqdn: + description: + - "FQDN of nameserver." + type: str + returned: Always + protocol_fqdn: + description: + - "FQDN of nameserver in punycode." + type: str + returned: Always + stealth: + description: + - "If enabled, the NS record and glue record will NOT be automatically generated according to secondaries nameserver assignment." + - "Default: I(false)" + type: bool + returned: Always + tsig_enabled: + description: + - "If enabled, secondaries will use the configured TSIG key when requesting a zone transfer." + - "Default: I(false)" + type: bool + returned: Always + tsig_key: + description: + - "TSIG key." + - "Error if empty while I(tsig_enabled) is I(true)." + type: dict + returned: Always + contains: + algorithm: + description: + - "TSIG key algorithm." + - "Possible values:" + - "* I(hmac_sha256)," + - "* I(hmac_sha1)," + - "* I(hmac_sha224)," + - "* I(hmac_sha384)," + - "* I(hmac_sha512)." + type: str + returned: Always + comment: + description: + - "Comment for TSIG key." + type: str + returned: Always + key: + description: + - "The resource identifier." + type: str + returned: Always + name: + description: + - "TSIG key name, FQDN." + type: str + returned: Always + protocol_name: + description: + - "TSIG key name in punycode." + type: str + returned: Always + secret: + description: + - "TSIG key secret, base64 string." + type: str + returned: Always + id: + description: + - "The resource identifier." + type: str + returned: Always + internal_secondaries: + description: + - "Optional. BloxOne DDI hosts acting as internal secondaries. Order is not significant." + type: list + returned: Always + elements: dict + contains: + host: + description: + - "The resource identifier." + type: str + returned: Always + name: + description: + - "Name of the object." + type: str + returned: Always + nsgs: + description: + - "The resource identifier." + type: list + returned: Always + tags: + description: + - "Tagging specifics." + type: dict + returned: Always +""" # noqa: E501 + +from ansible_collections.infoblox.bloxone.plugins.module_utils.modules import BloxoneAnsibleModule + +try: + from bloxone_client import ApiException, NotFoundException + from dns_config import AuthNsgApi +except ImportError: + pass # Handled by BloxoneAnsibleModule + + +class AuthNsgInfoModule(BloxoneAnsibleModule): + def __init__(self, *args, **kwargs): + super(AuthNsgInfoModule, self).__init__(*args, **kwargs) + self._existing = None + self._limit = 1000 + + def find_by_id(self): + try: + resp = AuthNsgApi(self.client).read(self.params["id"], inherit="full") + return [resp.result] + except NotFoundException as e: + return None + + def find(self): + if self.params["id"] is not None: + return self.find_by_id() + + filter_str = None + if self.params["filters"] is not None: + filter_str = " and ".join([f"{k}=='{v}'" for k, v in self.params["filters"].items()]) + elif self.params["filter_query"] is not None: + filter_str = self.params["filter_query"] + + tag_filter_str = None + if self.params["tag_filters"] is not None: + tag_filter_str = " and ".join([f"{k}=='{v}'" for k, v in self.params["tag_filters"].items()]) + elif self.params["tag_filter_query"] is not None: + tag_filter_str = self.params["tag_filter_query"] + + all_results = [] + offset = 0 + + while True: + try: + resp = AuthNsgApi(self.client).list( + offset=offset, limit=self._limit, filter=filter_str, tfilter=tag_filter_str + ) + all_results.extend(resp.results) + + if len(resp.results) < self._limit: + break + offset += self._limit + + except ApiException as e: + self.fail_json(msg=f"Failed to execute command: {e.status} {e.reason} {e.body}") + + return all_results + + def run_command(self): + result = dict(objects=[]) + + if self.check_mode: + self.exit_json(**result) + + find_results = self.find() + + all_results = [] + for r in find_results: + all_results.append(r.model_dump(by_alias=True, exclude_none=True)) + + result["objects"] = all_results + self.exit_json(**result) + + +def main(): + # define available arguments/parameters a user can pass to the module + module_args = dict( + id=dict(type="str", required=False), + filters=dict(type="dict", required=False), + filter_query=dict(type="str", required=False), + inherit=dict(type="str", required=False, choices=["full", "partial", "none"], default="full"), + tag_filters=dict(type="dict", required=False), + tag_filter_query=dict(type="str", required=False), + ) + + module = AuthNsgInfoModule( + argument_spec=module_args, + supports_check_mode=True, + mutually_exclusive=[ + ["id", "filters", "filter_query"], + ["id", "tag_filters", "tag_filter_query"], + ], + ) + module.run_command() + + +if __name__ == "__main__": + main() diff --git a/tests/integration/targets/dns_auth_nsg/tasks/main.yml b/tests/integration/targets/dns_auth_nsg/tasks/main.yml new file mode 100644 index 0000000..7351221 --- /dev/null +++ b/tests/integration/targets/dns_auth_nsg/tasks/main.yml @@ -0,0 +1,170 @@ +--- + +#TODO: add tests +# The following require additional plugins to be supported. +# - internal_secondaries +# - nsgs + +- module_defaults: + group/infoblox.bloxone.all: + csp_url: "{{ csp_url }}" + api_key: "{{ api_key }}" + + block: + - ansible.builtin.set_fact: + auth_nsg_name: "test-auth-nsg-{{ 999999 | random | string }}" + + - name: Create an Auth NSG (check mode) + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + state: present + check_mode: true + register: auth_nsg + - name: Get Information about the Auth NSG + infoblox.bloxone.dns_auth_nsg_info: + filters: + name: "{{ auth_nsg_name }}" + register: auth_nsg_info + - assert: + that: + - auth_nsg is changed + - auth_nsg_info is not failed + - auth_nsg_info.objects | length == 0 + + - name: Create an Auth NSG + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + state: present + register: auth_nsg + - name: Get Information about the Auth NSG + infoblox.bloxone.dns_auth_nsg_info: + filters: + name: "{{ auth_nsg_name }}" + register: auth_nsg_info + - assert: + that: + - auth_nsg is changed + - auth_nsg_info is not failed + - auth_nsg_info.objects | length == 1 + + - name: Create an Auth NSG (idempotent) + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + state: present + register: auth_nsg + - assert: + that: + - auth_nsg is not changed + - auth_nsg is not failed + + - name: Delete the Auth NSG (check mode) + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + state: absent + check_mode: true + register: auth_nsg + - name: Get Information about the Auth NSG + infoblox.bloxone.dns_auth_nsg_info: + filters: + name: "{{ auth_nsg_name }}" + register: auth_nsg_info + - assert: + that: + - auth_nsg is changed + - auth_nsg_info is not failed + - auth_nsg_info.objects | length == 1 + + - name: Delete the Auth NSG + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + state: absent + register: auth_nsg + - name: Get Information about the Auth NSG + infoblox.bloxone.dns_auth_nsg_info: + filters: + name: "{{ auth_nsg_name }}" + register: auth_nsg_info + - assert: + that: + - auth_nsg is changed + - auth_nsg_info is not failed + - auth_nsg_info.objects | length == 0 + + - name: Delete the Auth NSG (idempotent) + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + state: absent + register: auth_nsg + - assert: + that: + - auth_nsg is not changed + - auth_nsg is not failed + + - name: Create an Auth NSG with a comment + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + comment: "Test Comment" + state: present + register: auth_nsg + - name: Get Information about the Auth NSG + infoblox.bloxone.dns_auth_nsg_info: + filters: + name: "{{ auth_nsg_name }}" + register: auth_nsg_info + - assert: + that: + - auth_nsg_info is not failed + - auth_nsg_info.objects | length == 1 + - auth_nsg_info.objects[0].id == auth_nsg.id + - auth_nsg_info.objects[0].comment == "Test Comment" + + - name: Create Auth NSG with external primary + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + external_primaries: + - address: "1.1.1.1" + fqdn: "a.com." + type: "primary" + state: present + register: auth_nsg + - name: Get Information about the Auth NSG + infoblox.bloxone.dns_auth_nsg_info: + filters: + name: "{{ auth_nsg_name }}" + register: auth_nsg_info + - assert: + that: + - auth_nsg is not failed + - auth_nsg_info.objects | length == 1 + - auth_nsg_info.objects[0].external_primaries | length == 1 + - auth_nsg_info.objects[0].external_primaries[0].address == "1.1.1.1" + - auth_nsg_info.objects[0].external_primaries[0].fqdn == "a.com." + - auth_nsg_info.objects[0].external_primaries[0].type == "primary" + + - name: Create an Auth NSG with tags + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + comment: "Test Comment" + tags: + location: "site-1" + state: present + register: auth_nsg + - name: Get Information about the Auth NSG + infoblox.bloxone.dns_auth_nsg_info: + filters: + name: "{{ auth_nsg_name }}" + register: auth_nsg_info + - assert: + that: + - auth_nsg_info is not failed + - auth_nsg_info.objects | length == 1 + - auth_nsg_info.objects[0].id == auth_nsg.id + - auth_nsg_info.objects[0].tags.location == "site-1" + + always: + # Cleanup if the test fails + - name: Clean up Auth NSG + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + state: absent + ignore_errors: true diff --git a/tests/integration/targets/dns_auth_nsg_info/tasks/main.yml b/tests/integration/targets/dns_auth_nsg_info/tasks/main.yml new file mode 100644 index 0000000..f9068ca --- /dev/null +++ b/tests/integration/targets/dns_auth_nsg_info/tasks/main.yml @@ -0,0 +1,60 @@ +--- +- module_defaults: + group/infoblox.bloxone.all: + csp_url: "{{ csp_url }}" + api_key: "{{ api_key }}" + block: + - ansible.builtin.set_fact: + auth_nsg_name: "test-auth-nsg-{{ 999999 | random | string }}" + tag_value: "site-{{ 999999 | random | string }}" + + - name: Create an Auth NSG + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + state: present + register: auth_nsg + + - name: Get Information about the Auth NSG + infoblox.bloxone.dns_auth_nsg_info: + filters: + name: "{{ auth_nsg_name }}" + register: auth_nsg_info + - assert: + that: + - auth_nsg_info.objects | length == 1 + - auth_nsg_info.objects[0].name == auth_nsg.object.name + + - name: Get Auth NSG information by filters (Name) + infoblox.bloxone.dns_auth_nsg_info: + filters: + name: "{{ auth_nsg_name }}" + register: auth_nsg_info + - assert: + that: + - auth_nsg_info.objects | length == 1 + - auth_nsg_info.objects[0].id == auth_nsg.id + + - name: Get Auth NSG information by filter query + infoblox.bloxone.dns_auth_nsg_info: + filter_query: "name=='{{ auth_nsg_name }}'" + - assert: + that: + - auth_nsg_info.objects | length == 1 + - auth_nsg_info.objects[0].id == auth_nsg.id + + - name: Get Auth NSG information by tag filters + infoblox.bloxone.dns_auth_nsg_info: + tag_filters: + location: "{{ tag_value }}" + - assert: + that: + - auth_nsg_info.objects | length == 1 + - auth_nsg_info.objects[0].id == auth_nsg.id + + always: + # Cleanup if the test fails + - name: "Delete Auth NSG" + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + state: "absent" + ignore_errors: true From 91efd4a3f9f93af31cfb80a0847af7ac9ab7eb4e Mon Sep 17 00:00:00 2001 From: Anil Gadiyar Date: Mon, 18 Nov 2024 16:06:14 +0530 Subject: [PATCH 2/5] wip --- plugins/modules/dns_auth_nsg.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/plugins/modules/dns_auth_nsg.py b/plugins/modules/dns_auth_nsg.py index 905afdb..7d78c5b 100644 --- a/plugins/modules/dns_auth_nsg.py +++ b/plugins/modules/dns_auth_nsg.py @@ -547,12 +547,13 @@ def main(): tsig_enabled=dict(type="bool"), tsig_key=dict( type="dict", + no_log=True, options=dict( algorithm=dict(type="str"), comment=dict(type="str"), - key=dict(type="str"), + key=dict(type="str", no_log=True), name=dict(type="str"), - secret=dict(type="str"), + secret=dict(type="str", no_log=True), ), ), type=dict(type="str"), @@ -568,12 +569,13 @@ def main(): tsig_enabled=dict(type="bool"), tsig_key=dict( type="dict", + no_log=True, options=dict( algorithm=dict(type="str"), comment=dict(type="str"), - key=dict(type="str"), + key=dict(type="str", no_log=True), name=dict(type="str"), - secret=dict(type="str"), + secret=dict(type="str", no_log=True), ), ), ), From f8b5cc4c3aa2d0f599dc5801673c0fc561bb31ca Mon Sep 17 00:00:00 2001 From: Anil Gadiyar Date: Wed, 11 Dec 2024 17:27:29 +0530 Subject: [PATCH 3/5] addressed PR review --- plugins/modules/dns_auth_nsg.py | 2 +- plugins/modules/dns_auth_nsg_info.py | 13 +-------- .../targets/dns_auth_nsg/tasks/main.yml | 27 ++++++++++++++++++- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/plugins/modules/dns_auth_nsg.py b/plugins/modules/dns_auth_nsg.py index 7d78c5b..90a88ce 100644 --- a/plugins/modules/dns_auth_nsg.py +++ b/plugins/modules/dns_auth_nsg.py @@ -456,7 +456,7 @@ def payload_changed(self): def find(self): if self.params["id"] is not None: try: - resp = AuthNsgApi(self.client).read(self.params["id"], inherit="full") + resp = AuthNsgApi(self.client).read(self.params["id"]) return resp.result except NotFoundException as e: if self.params["state"] == "absent": diff --git a/plugins/modules/dns_auth_nsg_info.py b/plugins/modules/dns_auth_nsg_info.py index f27966e..e9de2f8 100644 --- a/plugins/modules/dns_auth_nsg_info.py +++ b/plugins/modules/dns_auth_nsg_info.py @@ -31,16 +31,6 @@ - Filter query to filter objects type: str required: false - inherit: - description: - - Return inheritance information - type: str - required: false - choices: - - full - - partial - - none - default: full tag_filters: description: - Filter dict to filter objects by tags @@ -304,7 +294,7 @@ def __init__(self, *args, **kwargs): def find_by_id(self): try: - resp = AuthNsgApi(self.client).read(self.params["id"], inherit="full") + resp = AuthNsgApi(self.client).read(self.params["id"]) return [resp.result] except NotFoundException as e: return None @@ -366,7 +356,6 @@ def main(): id=dict(type="str", required=False), filters=dict(type="dict", required=False), filter_query=dict(type="str", required=False), - inherit=dict(type="str", required=False, choices=["full", "partial", "none"], default="full"), tag_filters=dict(type="dict", required=False), tag_filter_query=dict(type="str", required=False), ) diff --git a/tests/integration/targets/dns_auth_nsg/tasks/main.yml b/tests/integration/targets/dns_auth_nsg/tasks/main.yml index 7351221..006eff2 100644 --- a/tests/integration/targets/dns_auth_nsg/tasks/main.yml +++ b/tests/integration/targets/dns_auth_nsg/tasks/main.yml @@ -3,7 +3,6 @@ #TODO: add tests # The following require additional plugins to be supported. # - internal_secondaries -# - nsgs - module_defaults: group/infoblox.bloxone.all: @@ -13,6 +12,7 @@ block: - ansible.builtin.set_fact: auth_nsg_name: "test-auth-nsg-{{ 999999 | random | string }}" + secondary_auth_nsg_name: "test-secondary-auth-nsg-{{ 999999 | random | string }}" - name: Create an Auth NSG (check mode) infoblox.bloxone.dns_auth_nsg: @@ -161,6 +161,31 @@ - auth_nsg_info.objects[0].id == auth_nsg.id - auth_nsg_info.objects[0].tags.location == "site-1" + - name: Create the Primary Auth NSG + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + state: present + register: auth_nsg + - name: Create the Secondary Auth NSG referencing Primary + infoblox.bloxone.dns_auth_nsg: + name: "{{ secondary_auth_nsg_name }}" + nsgs: + - "{{ auth_nsg.id }}" + state: present + register: secondary_auth_nsg + - name: Get Information about the Secondary Auth NSG + infoblox.bloxone.dns_auth_nsg_info: + filters: + name: "{{ secondary_auth_nsg_name }}" + register: secondary_auth_nsg_info + - name: Validate that the Secondary Auth NSG references the Primary + assert: + that: + - secondary_auth_nsg_info is not failed + - secondary_auth_nsg_info.objects | length == 1 + - secondary_auth_nsg_info.objects[0].nsgs | length == 1 + - secondary_auth_nsg_info.objects[0].nsgs[0] == auth_nsg.id + always: # Cleanup if the test fails - name: Clean up Auth NSG From 902025ac523d6bbdb8f640b9b95597f02753d596 Mon Sep 17 00:00:00 2001 From: Anil Gadiyar Date: Thu, 12 Dec 2024 13:03:45 +0530 Subject: [PATCH 4/5] added link code --- .../targets/dns_auth_nsg/tasks/main.yml | 312 ++++++++++-------- 1 file changed, 166 insertions(+), 146 deletions(-) diff --git a/tests/integration/targets/dns_auth_nsg/tasks/main.yml b/tests/integration/targets/dns_auth_nsg/tasks/main.yml index 006eff2..c6d346e 100644 --- a/tests/integration/targets/dns_auth_nsg/tasks/main.yml +++ b/tests/integration/targets/dns_auth_nsg/tasks/main.yml @@ -14,152 +14,152 @@ auth_nsg_name: "test-auth-nsg-{{ 999999 | random | string }}" secondary_auth_nsg_name: "test-secondary-auth-nsg-{{ 999999 | random | string }}" - - name: Create an Auth NSG (check mode) - infoblox.bloxone.dns_auth_nsg: - name: "{{ auth_nsg_name }}" - state: present - check_mode: true - register: auth_nsg - - name: Get Information about the Auth NSG - infoblox.bloxone.dns_auth_nsg_info: - filters: - name: "{{ auth_nsg_name }}" - register: auth_nsg_info - - assert: - that: - - auth_nsg is changed - - auth_nsg_info is not failed - - auth_nsg_info.objects | length == 0 - - - name: Create an Auth NSG - infoblox.bloxone.dns_auth_nsg: - name: "{{ auth_nsg_name }}" - state: present - register: auth_nsg - - name: Get Information about the Auth NSG - infoblox.bloxone.dns_auth_nsg_info: - filters: - name: "{{ auth_nsg_name }}" - register: auth_nsg_info - - assert: - that: - - auth_nsg is changed - - auth_nsg_info is not failed - - auth_nsg_info.objects | length == 1 - - - name: Create an Auth NSG (idempotent) - infoblox.bloxone.dns_auth_nsg: - name: "{{ auth_nsg_name }}" - state: present - register: auth_nsg - - assert: - that: - - auth_nsg is not changed - - auth_nsg is not failed - - - name: Delete the Auth NSG (check mode) - infoblox.bloxone.dns_auth_nsg: - name: "{{ auth_nsg_name }}" - state: absent - check_mode: true - register: auth_nsg - - name: Get Information about the Auth NSG - infoblox.bloxone.dns_auth_nsg_info: - filters: - name: "{{ auth_nsg_name }}" - register: auth_nsg_info - - assert: - that: - - auth_nsg is changed - - auth_nsg_info is not failed - - auth_nsg_info.objects | length == 1 - - - name: Delete the Auth NSG - infoblox.bloxone.dns_auth_nsg: - name: "{{ auth_nsg_name }}" - state: absent - register: auth_nsg - - name: Get Information about the Auth NSG - infoblox.bloxone.dns_auth_nsg_info: - filters: - name: "{{ auth_nsg_name }}" - register: auth_nsg_info - - assert: - that: - - auth_nsg is changed - - auth_nsg_info is not failed - - auth_nsg_info.objects | length == 0 - - - name: Delete the Auth NSG (idempotent) - infoblox.bloxone.dns_auth_nsg: - name: "{{ auth_nsg_name }}" - state: absent - register: auth_nsg - - assert: - that: - - auth_nsg is not changed - - auth_nsg is not failed - - - name: Create an Auth NSG with a comment - infoblox.bloxone.dns_auth_nsg: - name: "{{ auth_nsg_name }}" - comment: "Test Comment" - state: present - register: auth_nsg - - name: Get Information about the Auth NSG - infoblox.bloxone.dns_auth_nsg_info: - filters: - name: "{{ auth_nsg_name }}" - register: auth_nsg_info - - assert: - that: - - auth_nsg_info is not failed - - auth_nsg_info.objects | length == 1 - - auth_nsg_info.objects[0].id == auth_nsg.id - - auth_nsg_info.objects[0].comment == "Test Comment" - - - name: Create Auth NSG with external primary - infoblox.bloxone.dns_auth_nsg: - name: "{{ auth_nsg_name }}" - external_primaries: - - address: "1.1.1.1" - fqdn: "a.com." - type: "primary" - state: present - register: auth_nsg - - name: Get Information about the Auth NSG - infoblox.bloxone.dns_auth_nsg_info: - filters: - name: "{{ auth_nsg_name }}" - register: auth_nsg_info - - assert: - that: - - auth_nsg is not failed - - auth_nsg_info.objects | length == 1 - - auth_nsg_info.objects[0].external_primaries | length == 1 - - auth_nsg_info.objects[0].external_primaries[0].address == "1.1.1.1" - - auth_nsg_info.objects[0].external_primaries[0].fqdn == "a.com." - - auth_nsg_info.objects[0].external_primaries[0].type == "primary" - - - name: Create an Auth NSG with tags - infoblox.bloxone.dns_auth_nsg: - name: "{{ auth_nsg_name }}" - comment: "Test Comment" - tags: - location: "site-1" - state: present - register: auth_nsg - - name: Get Information about the Auth NSG - infoblox.bloxone.dns_auth_nsg_info: - filters: - name: "{{ auth_nsg_name }}" - register: auth_nsg_info - - assert: - that: - - auth_nsg_info is not failed - - auth_nsg_info.objects | length == 1 - - auth_nsg_info.objects[0].id == auth_nsg.id - - auth_nsg_info.objects[0].tags.location == "site-1" +# - name: Create an Auth NSG (check mode) +# infoblox.bloxone.dns_auth_nsg: +# name: "{{ auth_nsg_name }}" +# state: present +# check_mode: true +# register: auth_nsg +# - name: Get Information about the Auth NSG +# infoblox.bloxone.dns_auth_nsg_info: +# filters: +# name: "{{ auth_nsg_name }}" +# register: auth_nsg_info +# - assert: +# that: +# - auth_nsg is changed +# - auth_nsg_info is not failed +# - auth_nsg_info.objects | length == 0 +# +# - name: Create an Auth NSG +# infoblox.bloxone.dns_auth_nsg: +# name: "{{ auth_nsg_name }}" +# state: present +# register: auth_nsg +# - name: Get Information about the Auth NSG +# infoblox.bloxone.dns_auth_nsg_info: +# filters: +# name: "{{ auth_nsg_name }}" +# register: auth_nsg_info +# - assert: +# that: +# - auth_nsg is changed +# - auth_nsg_info is not failed +# - auth_nsg_info.objects | length == 1 +# +# - name: Create an Auth NSG (idempotent) +# infoblox.bloxone.dns_auth_nsg: +# name: "{{ auth_nsg_name }}" +# state: present +# register: auth_nsg +# - assert: +# that: +# - auth_nsg is not changed +# - auth_nsg is not failed +# +# - name: Delete the Auth NSG (check mode) +# infoblox.bloxone.dns_auth_nsg: +# name: "{{ auth_nsg_name }}" +# state: absent +# check_mode: true +# register: auth_nsg +# - name: Get Information about the Auth NSG +# infoblox.bloxone.dns_auth_nsg_info: +# filters: +# name: "{{ auth_nsg_name }}" +# register: auth_nsg_info +# - assert: +# that: +# - auth_nsg is changed +# - auth_nsg_info is not failed +# - auth_nsg_info.objects | length == 1 +# +# - name: Delete the Auth NSG +# infoblox.bloxone.dns_auth_nsg: +# name: "{{ auth_nsg_name }}" +# state: absent +# register: auth_nsg +# - name: Get Information about the Auth NSG +# infoblox.bloxone.dns_auth_nsg_info: +# filters: +# name: "{{ auth_nsg_name }}" +# register: auth_nsg_info +# - assert: +# that: +# - auth_nsg is changed +# - auth_nsg_info is not failed +# - auth_nsg_info.objects | length == 0 +# +# - name: Delete the Auth NSG (idempotent) +# infoblox.bloxone.dns_auth_nsg: +# name: "{{ auth_nsg_name }}" +# state: absent +# register: auth_nsg +# - assert: +# that: +# - auth_nsg is not changed +# - auth_nsg is not failed +# +# - name: Create an Auth NSG with a comment +# infoblox.bloxone.dns_auth_nsg: +# name: "{{ auth_nsg_name }}" +# comment: "Test Comment" +# state: present +# register: auth_nsg +# - name: Get Information about the Auth NSG +# infoblox.bloxone.dns_auth_nsg_info: +# filters: +# name: "{{ auth_nsg_name }}" +# register: auth_nsg_info +# - assert: +# that: +# - auth_nsg_info is not failed +# - auth_nsg_info.objects | length == 1 +# - auth_nsg_info.objects[0].id == auth_nsg.id +# - auth_nsg_info.objects[0].comment == "Test Comment" +# +# - name: Create Auth NSG with external primary +# infoblox.bloxone.dns_auth_nsg: +# name: "{{ auth_nsg_name }}" +# external_primaries: +# - address: "1.1.1.1" +# fqdn: "a.com." +# type: "primary" +# state: present +# register: auth_nsg +# - name: Get Information about the Auth NSG +# infoblox.bloxone.dns_auth_nsg_info: +# filters: +# name: "{{ auth_nsg_name }}" +# register: auth_nsg_info +# - assert: +# that: +# - auth_nsg is not failed +# - auth_nsg_info.objects | length == 1 +# - auth_nsg_info.objects[0].external_primaries | length == 1 +# - auth_nsg_info.objects[0].external_primaries[0].address == "1.1.1.1" +# - auth_nsg_info.objects[0].external_primaries[0].fqdn == "a.com." +# - auth_nsg_info.objects[0].external_primaries[0].type == "primary" +# +# - name: Create an Auth NSG with tags +# infoblox.bloxone.dns_auth_nsg: +# name: "{{ auth_nsg_name }}" +# comment: "Test Comment" +# tags: +# location: "site-1" +# state: present +# register: auth_nsg +# - name: Get Information about the Auth NSG +# infoblox.bloxone.dns_auth_nsg_info: +# filters: +# name: "{{ auth_nsg_name }}" +# register: auth_nsg_info +# - assert: +# that: +# - auth_nsg_info is not failed +# - auth_nsg_info.objects | length == 1 +# - auth_nsg_info.objects[0].id == auth_nsg.id +# - auth_nsg_info.objects[0].tags.location == "site-1" - name: Create the Primary Auth NSG infoblox.bloxone.dns_auth_nsg: @@ -185,6 +185,20 @@ - secondary_auth_nsg_info.objects | length == 1 - secondary_auth_nsg_info.objects[0].nsgs | length == 1 - secondary_auth_nsg_info.objects[0].nsgs[0] == auth_nsg.id + - block: # Unlinking block + - name: Unlink Primary auth NSG from Secondary + infoblox.bloxone.dns_auth_nsg: + id: "{{ secondary_auth_nsg.id }}" + name: "{{ secondary_auth_nsg_name }}" + nsgs: [ ] + state: present + rescue: + - name: Cleanup in case of failure (force unlink Secondary from Primary) + infoblox.bloxone.dns_auth_nsg: + id: "{{ secondary_auth_nsg.id | default('') }}" + nsgs: [ ] + state: present + when: secondary_auth_nsg is defined always: # Cleanup if the test fails @@ -193,3 +207,9 @@ name: "{{ auth_nsg_name }}" state: absent ignore_errors: true + + - name: Clean up Secondary Auth NSG + infoblox.bloxone.dns_auth_nsg: + name: "{{ secondary_auth_nsg_name }}" + state: absent + ignore_errors: true From f0aa451302c66b0a804887d24a5a12f27222bca1 Mon Sep 17 00:00:00 2001 From: Anil Gadiyar Date: Mon, 16 Dec 2024 13:08:46 +0530 Subject: [PATCH 5/5] addressed review comments --- plugins/modules/dns_auth_nsg.py | 2 +- .../targets/dns_auth_nsg/tasks/main.yml | 313 ++++++++---------- 2 files changed, 148 insertions(+), 167 deletions(-) diff --git a/plugins/modules/dns_auth_nsg.py b/plugins/modules/dns_auth_nsg.py index 90a88ce..53b3b43 100644 --- a/plugins/modules/dns_auth_nsg.py +++ b/plugins/modules/dns_auth_nsg.py @@ -194,7 +194,7 @@ type: "primary" state: "present" tags: - location: "my-location" + location: "site-1" - name: Delete the Auth NSG infoblox.bloxone.dns_auth_nsg: diff --git a/tests/integration/targets/dns_auth_nsg/tasks/main.yml b/tests/integration/targets/dns_auth_nsg/tasks/main.yml index c6d346e..cb0a96f 100644 --- a/tests/integration/targets/dns_auth_nsg/tasks/main.yml +++ b/tests/integration/targets/dns_auth_nsg/tasks/main.yml @@ -14,158 +14,153 @@ auth_nsg_name: "test-auth-nsg-{{ 999999 | random | string }}" secondary_auth_nsg_name: "test-secondary-auth-nsg-{{ 999999 | random | string }}" -# - name: Create an Auth NSG (check mode) -# infoblox.bloxone.dns_auth_nsg: -# name: "{{ auth_nsg_name }}" -# state: present -# check_mode: true -# register: auth_nsg -# - name: Get Information about the Auth NSG -# infoblox.bloxone.dns_auth_nsg_info: -# filters: -# name: "{{ auth_nsg_name }}" -# register: auth_nsg_info -# - assert: -# that: -# - auth_nsg is changed -# - auth_nsg_info is not failed -# - auth_nsg_info.objects | length == 0 -# -# - name: Create an Auth NSG -# infoblox.bloxone.dns_auth_nsg: -# name: "{{ auth_nsg_name }}" -# state: present -# register: auth_nsg -# - name: Get Information about the Auth NSG -# infoblox.bloxone.dns_auth_nsg_info: -# filters: -# name: "{{ auth_nsg_name }}" -# register: auth_nsg_info -# - assert: -# that: -# - auth_nsg is changed -# - auth_nsg_info is not failed -# - auth_nsg_info.objects | length == 1 -# -# - name: Create an Auth NSG (idempotent) -# infoblox.bloxone.dns_auth_nsg: -# name: "{{ auth_nsg_name }}" -# state: present -# register: auth_nsg -# - assert: -# that: -# - auth_nsg is not changed -# - auth_nsg is not failed -# -# - name: Delete the Auth NSG (check mode) -# infoblox.bloxone.dns_auth_nsg: -# name: "{{ auth_nsg_name }}" -# state: absent -# check_mode: true -# register: auth_nsg -# - name: Get Information about the Auth NSG -# infoblox.bloxone.dns_auth_nsg_info: -# filters: -# name: "{{ auth_nsg_name }}" -# register: auth_nsg_info -# - assert: -# that: -# - auth_nsg is changed -# - auth_nsg_info is not failed -# - auth_nsg_info.objects | length == 1 -# -# - name: Delete the Auth NSG -# infoblox.bloxone.dns_auth_nsg: -# name: "{{ auth_nsg_name }}" -# state: absent -# register: auth_nsg -# - name: Get Information about the Auth NSG -# infoblox.bloxone.dns_auth_nsg_info: -# filters: -# name: "{{ auth_nsg_name }}" -# register: auth_nsg_info -# - assert: -# that: -# - auth_nsg is changed -# - auth_nsg_info is not failed -# - auth_nsg_info.objects | length == 0 -# -# - name: Delete the Auth NSG (idempotent) -# infoblox.bloxone.dns_auth_nsg: -# name: "{{ auth_nsg_name }}" -# state: absent -# register: auth_nsg -# - assert: -# that: -# - auth_nsg is not changed -# - auth_nsg is not failed -# -# - name: Create an Auth NSG with a comment -# infoblox.bloxone.dns_auth_nsg: -# name: "{{ auth_nsg_name }}" -# comment: "Test Comment" -# state: present -# register: auth_nsg -# - name: Get Information about the Auth NSG -# infoblox.bloxone.dns_auth_nsg_info: -# filters: -# name: "{{ auth_nsg_name }}" -# register: auth_nsg_info -# - assert: -# that: -# - auth_nsg_info is not failed -# - auth_nsg_info.objects | length == 1 -# - auth_nsg_info.objects[0].id == auth_nsg.id -# - auth_nsg_info.objects[0].comment == "Test Comment" -# -# - name: Create Auth NSG with external primary -# infoblox.bloxone.dns_auth_nsg: -# name: "{{ auth_nsg_name }}" -# external_primaries: -# - address: "1.1.1.1" -# fqdn: "a.com." -# type: "primary" -# state: present -# register: auth_nsg -# - name: Get Information about the Auth NSG -# infoblox.bloxone.dns_auth_nsg_info: -# filters: -# name: "{{ auth_nsg_name }}" -# register: auth_nsg_info -# - assert: -# that: -# - auth_nsg is not failed -# - auth_nsg_info.objects | length == 1 -# - auth_nsg_info.objects[0].external_primaries | length == 1 -# - auth_nsg_info.objects[0].external_primaries[0].address == "1.1.1.1" -# - auth_nsg_info.objects[0].external_primaries[0].fqdn == "a.com." -# - auth_nsg_info.objects[0].external_primaries[0].type == "primary" -# -# - name: Create an Auth NSG with tags -# infoblox.bloxone.dns_auth_nsg: -# name: "{{ auth_nsg_name }}" -# comment: "Test Comment" -# tags: -# location: "site-1" -# state: present -# register: auth_nsg -# - name: Get Information about the Auth NSG -# infoblox.bloxone.dns_auth_nsg_info: -# filters: -# name: "{{ auth_nsg_name }}" -# register: auth_nsg_info -# - assert: -# that: -# - auth_nsg_info is not failed -# - auth_nsg_info.objects | length == 1 -# - auth_nsg_info.objects[0].id == auth_nsg.id -# - auth_nsg_info.objects[0].tags.location == "site-1" + - name: Create an Auth NSG (check mode) + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + state: present + check_mode: true + register: auth_nsg + - name: Get Information about the Auth NSG + infoblox.bloxone.dns_auth_nsg_info: + filters: + name: "{{ auth_nsg_name }}" + register: auth_nsg_info + - assert: + that: + - auth_nsg is changed + - auth_nsg_info is not failed + - auth_nsg_info.objects | length == 0 + + - name: Create an Auth NSG + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + state: present + register: auth_nsg + - name: Get Information about the Auth NSG + infoblox.bloxone.dns_auth_nsg_info: + filters: + name: "{{ auth_nsg_name }}" + register: auth_nsg_info + - assert: + that: + - auth_nsg is changed + - auth_nsg_info is not failed + - auth_nsg_info.objects | length == 1 + + - name: Create an Auth NSG (idempotent) + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + state: present + register: auth_nsg + - assert: + that: + - auth_nsg is not changed + - auth_nsg is not failed + + - name: Delete the Auth NSG (check mode) + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + state: absent + check_mode: true + register: auth_nsg + - name: Get Information about the Auth NSG + infoblox.bloxone.dns_auth_nsg_info: + filters: + name: "{{ auth_nsg_name }}" + register: auth_nsg_info + - assert: + that: + - auth_nsg is changed + - auth_nsg_info is not failed + - auth_nsg_info.objects | length == 1 + + - name: Delete the Auth NSG + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + state: absent + register: auth_nsg + - name: Get Information about the Auth NSG + infoblox.bloxone.dns_auth_nsg_info: + filters: + name: "{{ auth_nsg_name }}" + register: auth_nsg_info + - assert: + that: + - auth_nsg is changed + - auth_nsg_info is not failed + - auth_nsg_info.objects | length == 0 + + - name: Delete the Auth NSG (idempotent) + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + state: absent + register: auth_nsg + - assert: + that: + - auth_nsg is not changed + - auth_nsg is not failed + + - name: Create an Auth NSG with a comment + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + comment: "Test Comment" + state: present + register: auth_nsg + - name: Get Information about the Auth NSG + infoblox.bloxone.dns_auth_nsg_info: + filters: + name: "{{ auth_nsg_name }}" + register: auth_nsg_info + - assert: + that: + - auth_nsg_info is not failed + - auth_nsg_info.objects | length == 1 + - auth_nsg_info.objects[0].id == auth_nsg.id + - auth_nsg_info.objects[0].comment == "Test Comment" + + - name: Create Auth NSG with external primary + infoblox.bloxone.dns_auth_nsg: + name: "{{ auth_nsg_name }}" + external_primaries: + - address: "1.1.1.1" + fqdn: "a.com." + type: "primary" + state: present + register: auth_nsg + - name: Get Information about the Auth NSG + infoblox.bloxone.dns_auth_nsg_info: + filters: + name: "{{ auth_nsg_name }}" + register: auth_nsg_info + - assert: + that: + - auth_nsg is not failed + - auth_nsg_info.objects | length == 1 + - auth_nsg_info.objects[0].external_primaries | length == 1 + - auth_nsg_info.objects[0].external_primaries[0].address == "1.1.1.1" + - auth_nsg_info.objects[0].external_primaries[0].fqdn == "a.com." + - auth_nsg_info.objects[0].external_primaries[0].type == "primary" - - name: Create the Primary Auth NSG + - name: Create an Auth NSG with tags infoblox.bloxone.dns_auth_nsg: name: "{{ auth_nsg_name }}" + comment: "Test Comment" + tags: + location: "site-1" state: present register: auth_nsg + - name: Get Information about the Auth NSG + infoblox.bloxone.dns_auth_nsg_info: + filters: + name: "{{ auth_nsg_name }}" + register: auth_nsg_info + - assert: + that: + - auth_nsg_info is not failed + - auth_nsg_info.objects | length == 1 + - auth_nsg_info.objects[0].id == auth_nsg.id + - auth_nsg_info.objects[0].tags.location == "site-1" + - name: Create the Secondary Auth NSG referencing Primary infoblox.bloxone.dns_auth_nsg: name: "{{ secondary_auth_nsg_name }}" @@ -185,31 +180,17 @@ - secondary_auth_nsg_info.objects | length == 1 - secondary_auth_nsg_info.objects[0].nsgs | length == 1 - secondary_auth_nsg_info.objects[0].nsgs[0] == auth_nsg.id - - block: # Unlinking block - - name: Unlink Primary auth NSG from Secondary - infoblox.bloxone.dns_auth_nsg: - id: "{{ secondary_auth_nsg.id }}" - name: "{{ secondary_auth_nsg_name }}" - nsgs: [ ] - state: present - rescue: - - name: Cleanup in case of failure (force unlink Secondary from Primary) - infoblox.bloxone.dns_auth_nsg: - id: "{{ secondary_auth_nsg.id | default('') }}" - nsgs: [ ] - state: present - when: secondary_auth_nsg is defined always: # Cleanup if the test fails - - name: Clean up Auth NSG + - name: Clean up Secondary Auth NSG infoblox.bloxone.dns_auth_nsg: - name: "{{ auth_nsg_name }}" + name: "{{ secondary_auth_nsg_name }}" state: absent ignore_errors: true - - name: Clean up Secondary Auth NSG + - name: Clean up Auth NSG infoblox.bloxone.dns_auth_nsg: - name: "{{ secondary_auth_nsg_name }}" - state: absent + name: "{{ auth_nsg_name }}" + state: absent ignore_errors: true