From f2071d3ee2d1ea9cd21d18433ad48bfbb7f7b8ba Mon Sep 17 00:00:00 2001 From: VishrutiBuddhadev Date: Tue, 10 Dec 2024 21:51:53 +0530 Subject: [PATCH 1/7] generated resources for ipam_host and added examples --- plugins/modules/ipam_host.py | 399 ++++++++++++++++++++++++++++++ plugins/modules/ipam_host_info.py | 307 +++++++++++++++++++++++ 2 files changed, 706 insertions(+) create mode 100644 plugins/modules/ipam_host.py create mode 100644 plugins/modules/ipam_host_info.py diff --git a/plugins/modules/ipam_host.py b/plugins/modules/ipam_host.py new file mode 100644 index 0000000..8c8e19d --- /dev/null +++ b/plugins/modules/ipam_host.py @@ -0,0 +1,399 @@ +#!/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: ipam_host +short_description: Manage IpamHost +description: + - Manage IpamHost +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 + addresses: + description: + - "The list of all addresses associated with the IPAM host, which may be in different IP spaces." + type: list + elements: dict + suboptions: + address: + description: + - "Field usage depends on the operation:" + - "* For read operation, I(address) of the I(Address) corresponding to the I(ref) resource." + - "* For write operation, I(address) to be created if the I(Address) does not exist. Required if I(ref) is not set on write:" + - "* If the I(Address) already exists and is already pointing to the right I(Host), the operation proceeds." + - "* If the I(Address) already exists and is pointing to a different _Host, the operation must abort." + - "* If the I(Address) already exists and is not pointing to any I(Host), it is linked to the I(Host)." + type: str + ref: + description: + - "The resource identifier." + type: str + space: + description: + - "The resource identifier." + type: str + auto_generate_records: + description: + - "This flag specifies if resource records have to be auto generated for the host." + type: bool + comment: + description: + - "The description for the IPAM host. May contain 0 to 1024 characters. Can include UTF-8." + type: str + host_names: + description: + - "The name records to be generated for the host." + - "This field is required if I(auto_generate_records) is true." + type: list + elements: dict + suboptions: + alias: + description: + - "When I(true), the name is treated as an alias." + type: bool + name: + description: + - "A name for the host." + type: str + primary_name: + description: + - "When I(true), the name field is treated as primary name. There must be one and only one primary name in the list of host names. The primary name will be treated as the canonical name for all the aliases. PTR record will be generated only for the primary name." + type: bool + zone: + description: + - "The resource identifier." + type: str + name: + description: + - "The name of the IPAM host. Must contain 1 to 256 characters. Can include UTF-8." + type: str + tags: + description: + - "The tags for the IPAM host in JSON format." + type: dict + +extends_documentation_fragment: + - infoblox.bloxone.common +""" # noqa: E501 + +EXAMPLES = r""" + - name: "Create a Host" + infoblox.bloxone.ipam_host: + name: "{{ name }}" + state: "present" + register: host + + - name: "Create an IP space" + infoblox.bloxone.ipam_ip_space: + name: "{{ name }}" + state: "present" + register: ip_space + + - name: "Create a Subnet" + infoblox.bloxone.ipam_subnet: + address: "10.0.0.0/24" + space: "{{ ip_space.id }}" + state: "present" + register: subnet + + - name: "Create a Host with Addresses" + infoblox.bloxone.ipam_host: + name: "{{ name }}" + addresses: + - address: "10.0.0.1" + space: "{{ ip_space.id }}" + state: "present" + register: host + + - name: "Delete a host" + infoblox.bloxone.ipam_host: + name: "{{ name }}" + state: "absent" + register: host +""" + +RETURN = r""" +id: + description: + - ID of the IpamHost object + type: str + returned: Always +item: + description: + - IpamHost object + type: complex + returned: Always + contains: + addresses: + description: + - "The list of all addresses associated with the IPAM host, which may be in different IP spaces." + type: list + returned: Always + elements: dict + contains: + address: + description: + - "Field usage depends on the operation:" + - "* For read operation, I(address) of the I(Address) corresponding to the I(ref) resource." + - "* For write operation, I(address) to be created if the I(Address) does not exist. Required if I(ref) is not set on write:" + - "* If the I(Address) already exists and is already pointing to the right I(Host), the operation proceeds." + - "* If the I(Address) already exists and is pointing to a different _Host, the operation must abort." + - "* If the I(Address) already exists and is not pointing to any I(Host), it is linked to the I(Host)." + type: str + returned: Always + ref: + description: + - "The resource identifier." + type: str + returned: Always + space: + description: + - "The resource identifier." + type: str + returned: Always + auto_generate_records: + description: + - "This flag specifies if resource records have to be auto generated for the host." + type: bool + returned: Always + comment: + description: + - "The description for the IPAM host. May contain 0 to 1024 characters. Can include UTF-8." + type: str + returned: Always + created_at: + description: + - "Time when the object has been created." + type: str + returned: Always + host_names: + description: + - "The name records to be generated for the host." + - "This field is required if I(auto_generate_records) is true." + type: list + returned: Always + elements: dict + contains: + alias: + description: + - "When I(true), the name is treated as an alias." + type: bool + returned: Always + name: + description: + - "A name for the host." + type: str + returned: Always + primary_name: + description: + - "When I(true), the name field is treated as primary name. There must be one and only one primary name in the list of host names. The primary name will be treated as the canonical name for all the aliases. PTR record will be generated only for the primary name." + type: bool + returned: Always + zone: + description: + - "The resource identifier." + type: str + returned: Always + id: + description: + - "The resource identifier." + type: str + returned: Always + name: + description: + - "The name of the IPAM host. Must contain 1 to 256 characters. Can include UTF-8." + type: str + returned: Always + tags: + description: + - "The tags for the IPAM host in JSON format." + type: dict + returned: Always + updated_at: + description: + - "Time when the object has been updated. Equals to I(created_at) if not updated after creation." + type: str + returned: Always +""" # noqa: E501 + +from ansible_collections.infoblox.bloxone.plugins.module_utils.modules import BloxoneAnsibleModule + +try: + from bloxone_client import ApiException, NotFoundException + from ipam import IpamHost, IpamHostApi +except ImportError: + pass # Handled by BloxoneAnsibleModule + + +class IpamHostModule(BloxoneAnsibleModule): + def __init__(self, *args, **kwargs): + super(IpamHostModule, 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 = IpamHost.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 = IpamHostApi(self.client).read(self.params["id"]) + return resp.result + except NotFoundException as e: + if self.params["state"] == "absent": + return None + raise e + else: + filter = f"name=='{self.params['name']}'" + resp = IpamHostApi(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 IpamHost: {resp.results}") + if len(resp.results) == 0: + return None + + def create(self): + if self.check_mode: + return None + + resp = IpamHostApi(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 = IpamHostApi(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 + + IpamHostApi(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"] = "IpamHost created" + elif self.params["state"] == "present" and self.existing is not None: + if self.payload_changed(): + item = self.update() + result["changed"] = True + result["msg"] = "IpamHost updated" + elif self.params["state"] == "absent" and self.existing is not None: + self.delete() + result["changed"] = True + result["msg"] = "IpamHost 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"), + addresses=dict( + type="list", + elements="dict", + options=dict( + address=dict(type="str"), + ref=dict(type="str"), + space=dict(type="str"), + ), + ), + auto_generate_records=dict(type="bool"), + comment=dict(type="str"), + host_names=dict( + type="list", + elements="dict", + options=dict( + alias=dict(type="bool"), + name=dict(type="str"), + primary_name=dict(type="bool"), + zone=dict(type="str"), + ), + ), + name=dict(type="str"), + tags=dict(type="dict"), + ) + + module = IpamHostModule( + 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/ipam_host_info.py b/plugins/modules/ipam_host_info.py new file mode 100644 index 0000000..ef25249 --- /dev/null +++ b/plugins/modules/ipam_host_info.py @@ -0,0 +1,307 @@ +#!/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: ipam_host_info +short_description: Manage IpamHost +description: + - Manage IpamHost +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: "Create a Host" + infoblox.bloxone.ipam_host: + name: "{{ name }}" + tags: + tag1: "{{ tag1_value }}" + tag2: "{{ tag1_value }}" + state: "present" + register: host + + - name: Get Host information by ID + infoblox.bloxone.ipam_host_info: + id: "{{ host.id }}" + register: host_info + - assert: + that: + - host_info.objects | length == 1 + + - name: Get Host information by filters + infoblox.bloxone.ipam_host_info: + filters: + name: "{{ name }}" + register: host_info + - assert: + that: + - host_info.objects | length == 1 + + - name: Get IPAM Host information by filter query + infoblox.bloxone.ipam_host_info: + filter_query: "name=='{{ name }}'" + - assert: + that: + - host_info.objects | length == 1 + - host_info.objects[0].id == host.id + + - name: Get IPAM Host information by tag filters + infoblox.bloxone.ipam_host_info: + tag_filters: + tag1: "{ { tag1_value } }" + tag2: "{ { tag2_value } }" + - assert: + that: + - host_info.objects | length == 1 + - host_info.objects[0].id == host.id + +""" + +RETURN = r""" +id: + description: + - ID of the IpamHost object + type: str + returned: Always +objects: + description: + - IpamHost object + type: list + elements: dict + returned: Always + contains: + addresses: + description: + - "The list of all addresses associated with the IPAM host, which may be in different IP spaces." + type: list + returned: Always + elements: dict + contains: + address: + description: + - "Field usage depends on the operation:" + - "* For read operation, I(address) of the I(Address) corresponding to the I(ref) resource." + - "* For write operation, I(address) to be created if the I(Address) does not exist. Required if I(ref) is not set on write:" + - "* If the I(Address) already exists and is already pointing to the right I(Host), the operation proceeds." + - "* If the I(Address) already exists and is pointing to a different _Host, the operation must abort." + - "* If the I(Address) already exists and is not pointing to any I(Host), it is linked to the I(Host)." + type: str + returned: Always + ref: + description: + - "The resource identifier." + type: str + returned: Always + space: + description: + - "The resource identifier." + type: str + returned: Always + auto_generate_records: + description: + - "This flag specifies if resource records have to be auto generated for the host." + type: bool + returned: Always + comment: + description: + - "The description for the IPAM host. May contain 0 to 1024 characters. Can include UTF-8." + type: str + returned: Always + created_at: + description: + - "Time when the object has been created." + type: str + returned: Always + host_names: + description: + - "The name records to be generated for the host." + - "This field is required if I(auto_generate_records) is true." + type: list + returned: Always + elements: dict + contains: + alias: + description: + - "When I(true), the name is treated as an alias." + type: bool + returned: Always + name: + description: + - "A name for the host." + type: str + returned: Always + primary_name: + description: + - "When I(true), the name field is treated as primary name. There must be one and only one primary name in the list of host names. The primary name will be treated as the canonical name for all the aliases. PTR record will be generated only for the primary name." + type: bool + returned: Always + zone: + description: + - "The resource identifier." + type: str + returned: Always + id: + description: + - "The resource identifier." + type: str + returned: Always + name: + description: + - "The name of the IPAM host. Must contain 1 to 256 characters. Can include UTF-8." + type: str + returned: Always + tags: + description: + - "The tags for the IPAM host in JSON format." + type: dict + returned: Always + updated_at: + description: + - "Time when the object has been updated. Equals to I(created_at) if not updated after creation." + type: str + returned: Always +""" # noqa: E501 + +from ansible_collections.infoblox.bloxone.plugins.module_utils.modules import BloxoneAnsibleModule + +try: + from bloxone_client import ApiException, NotFoundException + from ipam import IpamHostApi +except ImportError: + pass # Handled by BloxoneAnsibleModule + + +class IpamHostInfoModule(BloxoneAnsibleModule): + def __init__(self, *args, **kwargs): + super(IpamHostInfoModule, self).__init__(*args, **kwargs) + self._existing = None + self._limit = 1000 + + def find_by_id(self): + try: + resp = IpamHostApi(self.client).read(self.params["id"]) + 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 = IpamHostApi(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 = IpamHostInfoModule( + 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() From 36236b0c6172ffe1826386f732d44544a762d6c9 Mon Sep 17 00:00:00 2001 From: VishrutiBuddhadev Date: Tue, 10 Dec 2024 21:52:41 +0530 Subject: [PATCH 2/7] written integration tests for ipam_host --- .../targets/ipam_host/tasks/main.yml | 173 ++++++++++++++++++ .../targets/ipam_host_info/tasks/main.yml | 63 +++++++ 2 files changed, 236 insertions(+) create mode 100644 tests/integration/targets/ipam_host/tasks/main.yml create mode 100644 tests/integration/targets/ipam_host_info/tasks/main.yml diff --git a/tests/integration/targets/ipam_host/tasks/main.yml b/tests/integration/targets/ipam_host/tasks/main.yml new file mode 100644 index 0000000..900b0c3 --- /dev/null +++ b/tests/integration/targets/ipam_host/tasks/main.yml @@ -0,0 +1,173 @@ +--- +#TODO: add tests +# The following test require next_available_id to be supported. +# - Create IPAM Host with next available ip + +- module_defaults: + group/infoblox.bloxone.all: + csp_url: "{{ csp_url }}" + api_key: "{{ api_key }}" + block: + # Create an random Host name to avoid conflicts + - ansible.builtin.set_fact: + name: "test-host-{{ 999999 | random | string }}" + + # Basic tests for Ipam Host + - name: "Create a Host (check mode)" + infoblox.bloxone.ipam_host: + name: "{{ name }}" + state: "present" + check_mode: true + register: host + + - name: "Create a Host" + infoblox.bloxone.ipam_host: + name: "{{ name }}" + state: "present" + register: host + - name: Get information about the host + infoblox.bloxone.ipam_host_info: + filters: + name: "{{ name }}" + register: host_info + - assert: + that: + - host is not failed + - host_info.objects | length == 1 + - host_info.objects[0].id == host.id + + - name: "Create a Host (idempotent)" + infoblox.bloxone.ipam_host: + name: "{{ name }}" + state: "present" + register: host + - assert: + that: + - host is not changed + - host is not failed + + - name: "Delete a Host (check mode)" + infoblox.bloxone.ipam_host: + name: "{{ name }}" + state: "absent" + check_mode: true + register: host + + - name: Get information about the Host + infoblox.bloxone.ipam_host_info: + filters: + name: "{{ name }}" + register: host_info + - assert: + that: + - host is changed + - host is not failed + - host_info.objects | length == 1 + + - name: "Delete a host" + infoblox.bloxone.ipam_host: + name: "{{ name }}" + state: "absent" + register: host + - name: Get information about the host + infoblox.bloxone.ipam_host_info: + filters: + name: "{{ name }}" + register: host_info + - assert: + that: + - host is changed + - host is not failed + - host_info.objects | length == 0 + + - name: "Delete a host (idempotent)" + infoblox.bloxone.ipam_host: + name: "{{ name }}" + state: "absent" + register: host + - assert: + that: + - host is not changed + - host is not failed + + - name: "Create a Host with comment" + infoblox.bloxone.ipam_host: + name: "{{ name }}" + comment: "test comment" + state: "present" + register: host + - name: Get information about the Host + infoblox.bloxone.ipam_host_info: + filters: + name: "{{ name }}" + register: host_info + - assert: + that: + - host is not failed + - host_info.objects | length == 1 + - host_info.objects[0].id == host.id + - host_info.objects[0].comment == "test comment" + + - name: "Create a Host with tags" + infoblox.bloxone.ipam_host: + name: "{{ name }}" + tags: + tag1: "value1" + tag2: "value2" + state: "present" + register: host + + - name: Get information about the Host + infoblox.bloxone.ipam_host_info: + filters: + name: "{{ name }}" + register: host_info + - assert: + that: + - host is not failed + - host_info.objects | length == 1 + - host_info.objects[0].id == host.id + - host_info.objects[0].tags.tag1 == "value1" + - host_info.objects[0].tags.tag2 == "value2" + + - name: "Create an IP space" + infoblox.bloxone.ipam_ip_space: + name: "{{ name }}" + state: "present" + register: ip_space + + - name: "Create a Subnet" + infoblox.bloxone.ipam_subnet: + address: "10.0.0.0/24" + space: "{{ ip_space.id }}" + state: "present" + register: subnet + + - name: "Create a Host with Addresses" + infoblox.bloxone.ipam_host: + name: "{{ name }}" + addresses: + - address: "10.0.0.1" + space: "{{ ip_space.id }}" + state: "present" + register: host + + - name: Get information about the Host + infoblox.bloxone.ipam_host_info: + filters: + name: "{{ name }}" + register: host_info + - assert: + that: + - host is not failed + - host_info.objects | length == 1 + - host_info.objects[0].id == host.id + - host_info.objects[0].addresses[0].address == "10.0.0.1" + + always: + # Cleanup if the test fails + - name: "Delete IPAM Host" + infoblox.bloxone.ipam_host: + name: "{{ name }}" + state: "absent" + ignore_errors: true \ No newline at end of file diff --git a/tests/integration/targets/ipam_host_info/tasks/main.yml b/tests/integration/targets/ipam_host_info/tasks/main.yml new file mode 100644 index 0000000..da415f3 --- /dev/null +++ b/tests/integration/targets/ipam_host_info/tasks/main.yml @@ -0,0 +1,63 @@ +--- +- module_defaults: + group/infoblox.bloxone.all: + csp_url: "{{ csp_url }}" + api_key: "{{ api_key }}" + block: + - ansible.builtin.set_fact: + name: "test-host-{{ 999999 | random | string }}" + tag1_value: "site-{{ 999999 | random | string }}" + tag2_value: "site-{{ 999999 | random | string }}" + + + - name: "Create a Host" + infoblox.bloxone.ipam_host: + name: "{{ name }}" + tags: + tag1: "{{ tag1_value }}" + tag2: "{{ tag1_value }}" + state: "present" + register: host + + - name: Get Host information by ID + infoblox.bloxone.ipam_host_info: + id: "{{ host.id }}" + register: host_info + - assert: + that: + - host_info.objects | length == 1 + + - name: Get Host information by filters + infoblox.bloxone.ipam_host_info: + filters: + name: "{{ name }}" + register: host_info + - assert: + that: + - host_info.objects | length == 1 + + - name: Get IPAM Host information by filter query + infoblox.bloxone.ipam_host_info: + filter_query: "name=='{{ name }}'" + - assert: + that: + - host_info.objects | length == 1 + - host_info.objects[0].id == host.id + + - name: Get IPAM Host information by tag filters + infoblox.bloxone.ipam_host_info: + tag_filters: + tag1: "{ { tag1_value } }" + tag2: "{ { tag2_value } }" + - assert: + that: + - host_info.objects | length == 1 + - host_info.objects[0].id == host.id + + always: + # Cleanup if the test fails + - name: "Delete IPAM Host" + infoblox.bloxone.ipam_host: + name: "{{ name }}" + state: "absent" + ignore_errors: true \ No newline at end of file From 4124d2ee2bc75348ba471f1489f09575ef2d981e Mon Sep 17 00:00:00 2001 From: VishrutiBuddhadev Date: Tue, 10 Dec 2024 21:59:38 +0530 Subject: [PATCH 3/7] deprecate b1_ipam_host and b1_ipam_host_gather --- changelogs/fragments/52-ipam-host.yml | 3 +++ meta/runtime.yml | 11 +++++++++++ plugins/modules/b1_ipam_host.py | 4 ++++ plugins/modules/b1_ipam_host_gather.py | 4 ++++ 4 files changed, 22 insertions(+) create mode 100644 changelogs/fragments/52-ipam-host.yml diff --git a/changelogs/fragments/52-ipam-host.yml b/changelogs/fragments/52-ipam-host.yml new file mode 100644 index 0000000..892081c --- /dev/null +++ b/changelogs/fragments/52-ipam-host.yml @@ -0,0 +1,3 @@ +deprecated_features: + - b1_ipam_host - is deprecated in favor of 'ipam_host'. + - b1_ipam_host_gather - is deprecated in favor of 'ipam_host_info'. \ No newline at end of file diff --git a/meta/runtime.yml b/meta/runtime.yml index 55f479e..6070f7e 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -18,6 +18,8 @@ action_groups: - ipam_subnet_info - ipam_address_block - ipam_address_block_info + - ipam_host + - ipam_host_info plugin_routing: modules: @@ -65,3 +67,12 @@ plugin_routing: deprecation: removal_version: 3.0.0 warning_text: Use infoblox.bloxone.dns_auth_zone_info instead. + + b1_ipam_host: + deprecation: + removal_version: 3.0.0 + warning_text: Use infoblox.bloxone.ipam_host instead. + b1_ipam_host_gather: + deprecation: + removal_version: 3.0.0 + warning_text: Use infoblox.bloxone.ipam_host_info instead. \ No newline at end of file diff --git a/plugins/modules/b1_ipam_host.py b/plugins/modules/b1_ipam_host.py index 540304c..7721c6a 100644 --- a/plugins/modules/b1_ipam_host.py +++ b/plugins/modules/b1_ipam_host.py @@ -13,6 +13,10 @@ author: "Akhilesh Kabade (@akhilesh-kabade-infoblox), Sriram Kannan(@kannans)" short_description: Configure Host on Infoblox BloxOne DDI version_added: "1.0.1" +deprecated: + removed_in: 3.0.0 + why: This module is deprecated and will be removed in version 3.0.0. Use M(ipam_host) instead. + alternative: Use M(ipam_host) instead. description: - Create, Update and Delete Hosts on Infoblox BloxOne DDI. This module manages the IPAM Host object using BloxOne REST APIs. requirements: diff --git a/plugins/modules/b1_ipam_host_gather.py b/plugins/modules/b1_ipam_host_gather.py index be5c484..2e3a828 100644 --- a/plugins/modules/b1_ipam_host_gather.py +++ b/plugins/modules/b1_ipam_host_gather.py @@ -10,6 +10,10 @@ module: b1_ipam_ip_space author: "Akhilesh Kabade (@akhilesh-kabade-infoblox)" short_description: Gather IPAM host facts +deprecated: + removed_in: 3.0.0 + why: This module is deprecated and will be removed in version 3.0.0. Use M(ipam_host_info) instead. + alternative: Use M(ipam_host_info) instead. description: - Gather facts about IPAM hosts in Infoblox BloxOne DDI. This module gathers facts of IPAM Hosts object using BloxOne REST APIs. requirements: From cf5cfd2316af3ca11d7ed3281f26d03322085e31 Mon Sep 17 00:00:00 2001 From: VishrutiBuddhadev Date: Wed, 11 Dec 2024 14:54:53 +0530 Subject: [PATCH 4/7] fixed sanity issues and added empty line at the end --- changelogs/fragments/52-ipam-host.yml | 3 ++- plugins/modules/ipam_host.py | 8 ++++---- tests/integration/targets/ipam_host/tasks/main.yml | 2 +- tests/integration/targets/ipam_host_info/tasks/main.yml | 2 +- 4 files changed, 8 insertions(+), 7 deletions(-) diff --git a/changelogs/fragments/52-ipam-host.yml b/changelogs/fragments/52-ipam-host.yml index 892081c..dcc5526 100644 --- a/changelogs/fragments/52-ipam-host.yml +++ b/changelogs/fragments/52-ipam-host.yml @@ -1,3 +1,4 @@ deprecated_features: - b1_ipam_host - is deprecated in favor of 'ipam_host'. - - b1_ipam_host_gather - is deprecated in favor of 'ipam_host_info'. \ No newline at end of file + - b1_ipam_host_gather - is deprecated in favor of 'ipam_host_info'. + \ No newline at end of file diff --git a/plugins/modules/ipam_host.py b/plugins/modules/ipam_host.py index 8c8e19d..16f0733 100644 --- a/plugins/modules/ipam_host.py +++ b/plugins/modules/ipam_host.py @@ -103,20 +103,20 @@ name: "{{ name }}" state: "present" register: host - + - name: "Create an IP space" infoblox.bloxone.ipam_ip_space: name: "{{ name }}" state: "present" register: ip_space - + - name: "Create a Subnet" infoblox.bloxone.ipam_subnet: address: "10.0.0.0/24" space: "{{ ip_space.id }}" state: "present" register: subnet - + - name: "Create a Host with Addresses" infoblox.bloxone.ipam_host: name: "{{ name }}" @@ -125,7 +125,7 @@ space: "{{ ip_space.id }}" state: "present" register: host - + - name: "Delete a host" infoblox.bloxone.ipam_host: name: "{{ name }}" diff --git a/tests/integration/targets/ipam_host/tasks/main.yml b/tests/integration/targets/ipam_host/tasks/main.yml index 900b0c3..24a0d7d 100644 --- a/tests/integration/targets/ipam_host/tasks/main.yml +++ b/tests/integration/targets/ipam_host/tasks/main.yml @@ -170,4 +170,4 @@ infoblox.bloxone.ipam_host: name: "{{ name }}" state: "absent" - ignore_errors: true \ No newline at end of file + ignore_errors: true diff --git a/tests/integration/targets/ipam_host_info/tasks/main.yml b/tests/integration/targets/ipam_host_info/tasks/main.yml index da415f3..e917655 100644 --- a/tests/integration/targets/ipam_host_info/tasks/main.yml +++ b/tests/integration/targets/ipam_host_info/tasks/main.yml @@ -60,4 +60,4 @@ infoblox.bloxone.ipam_host: name: "{{ name }}" state: "absent" - ignore_errors: true \ No newline at end of file + ignore_errors: true From 00d9e16248fb7f70546319753d3c91a15335dd8d Mon Sep 17 00:00:00 2001 From: VishrutiBuddhadev Date: Wed, 11 Dec 2024 14:55:50 +0530 Subject: [PATCH 5/7] removed instances of inherit --- plugins/modules/ipam_host_info.py | 1 - 1 file changed, 1 deletion(-) diff --git a/plugins/modules/ipam_host_info.py b/plugins/modules/ipam_host_info.py index ef25249..6cfc79e 100644 --- a/plugins/modules/ipam_host_info.py +++ b/plugins/modules/ipam_host_info.py @@ -287,7 +287,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), ) From b15c0b2cd0965c174a828285009fb451da34856a Mon Sep 17 00:00:00 2001 From: VishrutiBuddhadev Date: Wed, 11 Dec 2024 15:07:32 +0530 Subject: [PATCH 6/7] fixed documentation and added empty line at the end of file --- changelogs/fragments/52-ipam-host.yml | 1 - meta/runtime.yml | 2 +- plugins/modules/ipam_host_info.py | 10 ---------- 3 files changed, 1 insertion(+), 12 deletions(-) diff --git a/changelogs/fragments/52-ipam-host.yml b/changelogs/fragments/52-ipam-host.yml index dcc5526..3388f32 100644 --- a/changelogs/fragments/52-ipam-host.yml +++ b/changelogs/fragments/52-ipam-host.yml @@ -1,4 +1,3 @@ deprecated_features: - b1_ipam_host - is deprecated in favor of 'ipam_host'. - b1_ipam_host_gather - is deprecated in favor of 'ipam_host_info'. - \ No newline at end of file diff --git a/meta/runtime.yml b/meta/runtime.yml index 950d4d9..3b513b4 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -77,4 +77,4 @@ plugin_routing: b1_ipam_host_gather: deprecation: removal_version: 3.0.0 - warning_text: Use infoblox.bloxone.ipam_host_info instead. \ No newline at end of file + warning_text: Use infoblox.bloxone.ipam_host_info instead. diff --git a/plugins/modules/ipam_host_info.py b/plugins/modules/ipam_host_info.py index 6cfc79e..dbf8084 100644 --- a/plugins/modules/ipam_host_info.py +++ b/plugins/modules/ipam_host_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 From ca9c709c85ad77951ac6c4be71110e6aa0a37fcf Mon Sep 17 00:00:00 2001 From: VishrutiBuddhadev Date: Thu, 12 Dec 2024 10:57:11 +0530 Subject: [PATCH 7/7] refactored integration tests --- .../targets/ipam_host/tasks/main.yml | 23 +++++++++---------- .../targets/ipam_host_info/tasks/main.yml | 7 +++--- 2 files changed, 14 insertions(+), 16 deletions(-) diff --git a/tests/integration/targets/ipam_host/tasks/main.yml b/tests/integration/targets/ipam_host/tasks/main.yml index 24a0d7d..16da6b7 100644 --- a/tests/integration/targets/ipam_host/tasks/main.yml +++ b/tests/integration/targets/ipam_host/tasks/main.yml @@ -13,14 +13,14 @@ name: "test-host-{{ 999999 | random | string }}" # Basic tests for Ipam Host - - name: "Create a Host (check mode)" + - name: Create a Host (check mode) infoblox.bloxone.ipam_host: name: "{{ name }}" state: "present" check_mode: true register: host - - name: "Create a Host" + - name: Create a Host infoblox.bloxone.ipam_host: name: "{{ name }}" state: "present" @@ -36,7 +36,7 @@ - host_info.objects | length == 1 - host_info.objects[0].id == host.id - - name: "Create a Host (idempotent)" + - name: Create a Host (idempotent) infoblox.bloxone.ipam_host: name: "{{ name }}" state: "present" @@ -46,13 +46,12 @@ - host is not changed - host is not failed - - name: "Delete a Host (check mode)" + - name: Delete a Host (check mode) infoblox.bloxone.ipam_host: name: "{{ name }}" state: "absent" check_mode: true register: host - - name: Get information about the Host infoblox.bloxone.ipam_host_info: filters: @@ -64,7 +63,7 @@ - host is not failed - host_info.objects | length == 1 - - name: "Delete a host" + - name: Delete a host infoblox.bloxone.ipam_host: name: "{{ name }}" state: "absent" @@ -80,7 +79,7 @@ - host is not failed - host_info.objects | length == 0 - - name: "Delete a host (idempotent)" + - name: Delete a host (idempotent) infoblox.bloxone.ipam_host: name: "{{ name }}" state: "absent" @@ -90,7 +89,7 @@ - host is not changed - host is not failed - - name: "Create a Host with comment" + - name: Create a Host with comment infoblox.bloxone.ipam_host: name: "{{ name }}" comment: "test comment" @@ -108,7 +107,7 @@ - host_info.objects[0].id == host.id - host_info.objects[0].comment == "test comment" - - name: "Create a Host with tags" + - name: Create a Host with tags infoblox.bloxone.ipam_host: name: "{{ name }}" tags: @@ -130,20 +129,20 @@ - host_info.objects[0].tags.tag1 == "value1" - host_info.objects[0].tags.tag2 == "value2" - - name: "Create an IP space" + - name: Create an IP space infoblox.bloxone.ipam_ip_space: name: "{{ name }}" state: "present" register: ip_space - - name: "Create a Subnet" + - name: Create a Subnet infoblox.bloxone.ipam_subnet: address: "10.0.0.0/24" space: "{{ ip_space.id }}" state: "present" register: subnet - - name: "Create a Host with Addresses" + - name: Create a Host with Addresses infoblox.bloxone.ipam_host: name: "{{ name }}" addresses: diff --git a/tests/integration/targets/ipam_host_info/tasks/main.yml b/tests/integration/targets/ipam_host_info/tasks/main.yml index e917655..29999d8 100644 --- a/tests/integration/targets/ipam_host_info/tasks/main.yml +++ b/tests/integration/targets/ipam_host_info/tasks/main.yml @@ -9,8 +9,7 @@ tag1_value: "site-{{ 999999 | random | string }}" tag2_value: "site-{{ 999999 | random | string }}" - - - name: "Create a Host" + - name: Create a Host infoblox.bloxone.ipam_host: name: "{{ name }}" tags: @@ -36,7 +35,7 @@ that: - host_info.objects | length == 1 - - name: Get IPAM Host information by filter query + - name: Get Host information by filter query infoblox.bloxone.ipam_host_info: filter_query: "name=='{{ name }}'" - assert: @@ -44,7 +43,7 @@ - host_info.objects | length == 1 - host_info.objects[0].id == host.id - - name: Get IPAM Host information by tag filters + - name: Get Host information by tag filters infoblox.bloxone.ipam_host_info: tag_filters: tag1: "{ { tag1_value } }"