From 5428b6faf3a377021e6d803c462b3b83a3186026 Mon Sep 17 00:00:00 2001 From: VishrutiBuddhadev Date: Tue, 7 Jan 2025 15:22:15 +0530 Subject: [PATCH 01/10] added code for next_available_address_block --- plugins/modules/ipam_address_block.py | 40 +- .../ipam_next_available_address_block_info.py | 1678 +++++++++++++++++ .../targets/ipam_address_block/meta/main.yml | 2 + .../ipam_address_block_info/meta/main.yml | 2 + .../meta/main.yml | 2 + .../tasks/main.yml | 49 + .../targets/setup_ip_space/tasks/cleanup.yml | 0 .../targets/setup_ip_space/tasks/main.yml | 0 .../targets/setup_subnet/meta/main.yml | 0 .../targets/setup_subnet/tasks/main.yml | 0 10 files changed, 1765 insertions(+), 8 deletions(-) create mode 100644 plugins/modules/ipam_next_available_address_block_info.py create mode 100644 tests/integration/targets/ipam_address_block/meta/main.yml create mode 100644 tests/integration/targets/ipam_address_block_info/meta/main.yml create mode 100644 tests/integration/targets/ipam_next_available_address_block_info/meta/main.yml create mode 100644 tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml create mode 100644 tests/integration/targets/setup_ip_space/tasks/cleanup.yml create mode 100644 tests/integration/targets/setup_ip_space/tasks/main.yml create mode 100644 tests/integration/targets/setup_subnet/meta/main.yml create mode 100644 tests/integration/targets/setup_subnet/tasks/main.yml diff --git a/plugins/modules/ipam_address_block.py b/plugins/modules/ipam_address_block.py index 58d0bf20..debe0669 100644 --- a/plugins/modules/ipam_address_block.py +++ b/plugins/modules/ipam_address_block.py @@ -727,17 +727,20 @@ description: - "The low threshold value for the percentage of used IP addresses relative to the total IP addresses available in the scope of the object. Thresholds are inclusive in the comparison test." type: int + next_available_id: + description: + - "The resource identifier for the address block where the next available address block should be generated." + type: str extends_documentation_fragment: - infoblox.bloxone.common """ # noqa: E501 EXAMPLES = r""" - - name: "Create an ip space" + - name: "Create an ip space (required as parent)" infoblox.bloxone.ipam_ip_space: name: "my-ip-space" state: "present" - register: ip_space - name: "Create an address block" infoblox.bloxone.ipam_address_block: @@ -745,6 +748,13 @@ space: "{{ ip_space.id }}" state: "present" + - name: "Create Next Available Address Block" + infoblox.bloxone.ipam_address_block: + space: "{{ ip_space.id }}" + cidr: 20 + next_available_id: "{{ address_block.id }}" + state: "present" + - name: "Delete an Address Block" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" @@ -2349,12 +2359,15 @@ class AddressBlockModule(BloxoneAnsibleModule): def __init__(self, *args, **kwargs): super(AddressBlockModule, self).__init__(*args, **kwargs) + self.next_available_id = self.params.get("next_available_id") - if "/" in self.params["address"]: - self.params["address"], netmask = self.params["address"].split("/") - self.params["cidr"] = int(netmask) + # If address is None, next_available_id will be utilized along with a separately provided CIDR value + if self.params["address"] is not None: + if "/" in self.params["address"]: + self.params["address"], netmask = self.params["address"].split("/") + self.params["cidr"] = int(netmask) - exclude = ["state", "csp_url", "api_key", "id"] + exclude = ["state", "csp_url", "api_key", "id", "next_available_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 = AddressBlock.from_dict(self._payload_params) @@ -2399,6 +2412,9 @@ def find(self): return None raise e else: + # If address is None, return None, indicating next_available_address block should be created and not updated + if self.params["address"] is None: + return None filter = f"address=='{self.params['address']}' and space=='{self.params['space']}' and cidr=={self.params['cidr']}" resp = AddressBlockApi(self.client).list(filter=filter, inherit="full") if len(resp.results) == 1: @@ -2412,6 +2428,11 @@ def create(self): if self.check_mode: return None + # If next_available_id is not None, set the address to the next available ID. + if self.next_available_id is not None: + naId = f"{self.next_available_id}/nextavailableaddressblock" + self._payload.address = naId + resp = AddressBlockApi(self.client).create(body=self.payload, inherit="full") return resp.result.model_dump(by_alias=True, exclude_none=True) @@ -2475,7 +2496,8 @@ def main(): module_args = dict( id=dict(type="str", required=False), state=dict(type="str", required=False, choices=["present", "absent"], default="present"), - address=dict(type="str"), + address=dict(type="str", required=False), + next_available_id=dict(type="str", required=False), asm_config=dict( type="dict", options=dict( @@ -2766,7 +2788,9 @@ def main(): module = AddressBlockModule( argument_spec=module_args, supports_check_mode=True, - required_if=[("state", "present", ["address", "space"])], + mutually_exclusive=[["address", "next_available_id"]], + required_if=[("state", "present", ["space"])], + required_one_of=[["address", "next_available_id"]], ) module.run_command() diff --git a/plugins/modules/ipam_next_available_address_block_info.py b/plugins/modules/ipam_next_available_address_block_info.py new file mode 100644 index 00000000..1159aaa2 --- /dev/null +++ b/plugins/modules/ipam_next_available_address_block_info.py @@ -0,0 +1,1678 @@ +#!/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_next_available_address_block_info +short_description: Manage NextAvailableAddressBlock +description: + - Manage NextAvailableAddressBlock +version_added: 2.0.0 +author: Infoblox Inc. (@infobloxopen) +options: + id: + description: + - ID of the object + type: str + required: true + cidr: + description: + - The CIDR value of the object + type: int + required: false + count: + description: + - Number of objects to generate. Default 1 if not set + type: int + required: false +extends_documentation_fragment: + - infoblox.bloxone.common +""" # noqa: E501 + +EXAMPLES = r""" + - name: "Create Next Available Address Block" + infoblox.bloxone.ipam_address_block: + space: "{{ ip_space.id }}" + cidr: 20 + next_available_id: "{{ address_block.id }}" + state: "present" + + - name: Get Next Available Address Block Information by ID + infoblox.bloxone.ipam_next_available_address_block_info: + id: "{{ next_available_address_block.id }}" + cidr: 20 + + - name: Get Next Available Address Block Information by ID and Count + infoblox.bloxone.ipam_next_available_address_block_info: + id: "{{ next_available_address_block.id }}" + cidr: 24 + count: 5 +""" + +RETURN = r""" +id: + description: + - ID of the AddressBlock object + type: str + returned: Always +objects: + description: + - AddressBlock object + type: list + elements: dict + returned: Always + contains: + address: + description: + - "The address field in form \"a.b.c.d/n\" where the \"/n\" may be omitted. In this case, the CIDR value must be defined in the I(cidr) field. When reading, the I(address) field is always in the form \"a.b.c.d\"." + type: str + returned: Always + asm_config: + description: + - "The Automated Scope Management configuration for the address block." + type: dict + returned: Always + contains: + asm_threshold: + description: + - "ASM shows the number of addresses forecast to be used I(forecast_period) days in the future, if it is greater than I(asm_threshold) percent * I(dhcp_total) (see I(dhcp_utilization)) then the subnet is flagged." + type: int + returned: Always + enable: + description: + - "Indicates if Automated Scope Management is enabled." + type: bool + returned: Always + enable_notification: + description: + - "Indicates if ASM should send notifications to the user." + type: bool + returned: Always + forecast_period: + description: + - "The forecast period in days." + type: int + returned: Always + growth_factor: + description: + - "Indicates the growth in the number or percentage of IP addresses." + type: int + returned: Always + growth_type: + description: + - "The type of factor to use: I(percent) or I(count)." + type: str + returned: Always + history: + description: + - "The minimum amount of history needed before ASM can run on this subnet." + type: int + returned: Always + min_total: + description: + - "The minimum size of range needed for ASM to run on this subnet." + type: int + returned: Always + min_unused: + description: + - "The minimum percentage of addresses that must be available outside of the DHCP ranges and fixed addresses when making a suggested change.." + type: int + returned: Always + reenable_date: + description: "" + type: str + returned: Always + asm_scope_flag: + description: + - "Incremented by 1 if the IP address usage limits for automated scope management are exceeded for any subnets in the address block." + type: int + returned: Always + cidr: + description: + - "The CIDR of the address block. This is required, if I(address) does not specify it in its input." + type: int + returned: Always + comment: + description: + - "The description for the address block. 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 + ddns_client_update: + description: + - "Controls who does the DDNS updates." + - "Valid values are:" + - "* I(client): DHCP server updates DNS if requested by client." + - "* I(server): DHCP server always updates DNS, overriding an update request from the client, unless the client requests no updates." + - "* I(ignore): DHCP server always updates DNS, even if the client says not to." + - "* I(over_client_update): Same as I(server). DHCP server always updates DNS, overriding an update request from the client, unless the client requests no updates." + - "* I(over_no_update): DHCP server updates DNS even if the client requests that no updates be done. If the client requests to do the update, DHCP server allows it." + - "Defaults to I(client)." + type: str + returned: Always + ddns_conflict_resolution_mode: + description: + - "The mode used for resolving conflicts while performing DDNS updates." + - "Valid values are:" + - "* I(check_with_dhcid): It includes adding a DHCID record and checking that record via conflict detection as per RFC 4703." + - "* I(no_check_with_dhcid): This will ignore conflict detection but add a DHCID record when creating/updating an entry." + - "* I(check_exists_with_dhcid): This will check if there is an existing DHCID record but does not verify the value of the record matches the update. This will also update the DHCID record for the entry." + - "* I(no_check_without_dhcid): This ignores conflict detection and will not add a DHCID record when creating/updating a DDNS entry." + - "Defaults to I(check_with_dhcid)." + type: str + returned: Always + ddns_domain: + description: + - "The domain suffix for DDNS updates. FQDN, may be empty." + - "Defaults to empty." + type: str + returned: Always + ddns_generate_name: + description: + - "Indicates if DDNS needs to generate a hostname when not supplied by the client." + - "Defaults to I(false)." + type: bool + returned: Always + ddns_generated_prefix: + description: + - "The prefix used in the generation of an FQDN." + - "When generating a name, DHCP server will construct the name in the format: [ddns-generated-prefix]-[address-text].[ddns-qualifying-suffix]. where address-text is simply the lease IP address converted to a hyphenated string." + - "Defaults to \"myhost\"." + type: str + returned: Always + ddns_send_updates: + description: + - "Determines if DDNS updates are enabled at the address block level. Defaults to I(true)." + type: bool + returned: Always + ddns_ttl_percent: + description: + - "DDNS TTL value - to be calculated as a simple percentage of the lease's lifetime, using the parameter's value as the percentage. It is specified as a percentage (e.g. 25, 75). Defaults to unspecified." + type: float + returned: Always + ddns_update_on_renew: + description: + - "Instructs the DHCP server to always update the DNS information when a lease is renewed even if its DNS information has not changed." + - "Defaults to I(false)." + type: bool + returned: Always + ddns_use_conflict_resolution: + description: + - "When true, DHCP server will apply conflict resolution, as described in RFC 4703, when attempting to fulfill the update request." + - "When false, DHCP server will simply attempt to update the DNS entries per the request, regardless of whether or not they conflict with existing entries owned by other DHCP4 clients." + - "Defaults to I(true)." + type: bool + returned: Always + dhcp_config: + description: + - "The shared DHCP configuration that controls how leases are issued for the address block." + type: dict + returned: Always + contains: + abandoned_reclaim_time: + description: + - "The abandoned reclaim time in seconds for IPV4 clients." + type: int + returned: Always + abandoned_reclaim_time_v6: + description: + - "The abandoned reclaim time in seconds for IPV6 clients." + type: int + returned: Always + allow_unknown: + description: + - "Disable to allow leases only for known IPv4 clients, those for which a fixed address is configured." + type: bool + returned: Always + allow_unknown_v6: + description: + - "Disable to allow leases only for known IPV6 clients, those for which a fixed address is configured." + type: bool + returned: Always + echo_client_id: + description: + - "Enable/disable to include/exclude the client id when responding to discover or request." + type: bool + returned: Always + filters: + description: + - "The resource identifier." + type: list + returned: Always + filters_v6: + description: + - "The resource identifier." + type: list + returned: Always + ignore_client_uid: + description: + - "Enable to ignore the client UID when issuing a DHCP lease. Use this option to prevent assigning two IP addresses for a client which does not have a UID during one phase of PXE boot but acquires one for the other phase." + type: bool + returned: Always + ignore_list: + description: + - "The list of clients to ignore requests from." + type: list + returned: Always + elements: dict + contains: + type: + description: + - "Type of ignore matching: client to ignore by client identifier (client hex or client text) or hardware to ignore by hardware identifier (MAC address). It can have one of the following values:" + - "* I(client_hex)," + - "* I(client_text)," + - "* I(hardware)." + type: str + returned: Always + value: + description: + - "Value to match." + type: str + returned: Always + lease_time: + description: + - "The lease duration in seconds." + type: int + returned: Always + lease_time_v6: + description: + - "The lease duration in seconds for IPV6 clients." + type: int + returned: Always + dhcp_options: + description: + - "The list of DHCP options for the address block. May be either a specific option or a group of options." + type: list + returned: Always + elements: dict + contains: + group: + description: + - "The resource identifier." + type: str + returned: Always + option_code: + description: + - "The resource identifier." + type: str + returned: Always + option_value: + description: + - "The option value." + type: str + returned: Always + type: + description: + - "The type of item." + - "Valid values are:" + - "* I(group)" + - "* I(option)" + type: str + returned: Always + dhcp_utilization: + description: + - "The utilization of IP addresses within the DHCP ranges of the address block." + type: dict + returned: Always + contains: + dhcp_free: + description: + - "The total free IP addresses in the DHCP ranges in the scope of this object. It can be computed as I(dhcp_total) - I(dhcp_used)." + type: str + returned: Always + dhcp_total: + description: + - "The total IP addresses available in the DHCP ranges in the scope of this object." + type: str + returned: Always + dhcp_used: + description: + - "The total IP addresses marked as used in the DHCP ranges in the scope of this object." + type: str + returned: Always + dhcp_utilization: + description: + - "The percentage of used IP addresses relative to the total IP addresses available in the DHCP ranges in the scope of this object." + type: int + returned: Always + discovery_attrs: + description: + - "The discovery attributes for this address block in JSON format." + type: dict + returned: Always + discovery_metadata: + description: + - "The discovery metadata for this address block in JSON format." + type: dict + returned: Always + header_option_filename: + description: + - "The configuration for header option filename field." + type: str + returned: Always + header_option_server_address: + description: + - "The configuration for header option server address field." + type: str + returned: Always + header_option_server_name: + description: + - "The configuration for header option server name field." + type: str + returned: Always + hostname_rewrite_char: + description: + - "The character to replace non-matching characters with, when hostname rewrite is enabled." + - "Any single ASCII character or no character if the invalid characters should be removed without replacement." + - "Defaults to \"-\"." + type: str + returned: Always + hostname_rewrite_enabled: + description: + - "Indicates if client supplied hostnames will be rewritten prior to DDNS update by replacing every character that does not match I(hostname_rewrite_regex) by I(hostname_rewrite_char)." + - "Defaults to I(false)." + type: bool + returned: Always + hostname_rewrite_regex: + description: + - "The regex bracket expression to match valid characters." + - "Must begin with \"[\" and end with \"]\" and be a compilable POSIX regex." + - "Defaults to \"[^a-zA-Z0-9_.]\"." + type: str + returned: Always + id: + description: + - "The resource identifier." + type: str + returned: Always + inheritance_parent: + description: + - "The resource identifier." + type: str + returned: Always + inheritance_sources: + description: + - "The DHCP inheritance configuration for the address block." + type: dict + returned: Always + contains: + asm_config: + description: + - "The inheritance configuration for I(asm_config) field." + type: dict + returned: Always + contains: + asm_enable_block: + description: + - "The block of ASM fields: I(enable), I(enable_notification), I(reenable_date)." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: dict + returned: Always + contains: + enable: + description: + - "Indicates whether Automated Scope Management is enabled or not." + type: bool + returned: Always + enable_notification: + description: + - "Indicates whether sending notifications to the users is enabled or not." + type: bool + returned: Always + reenable_date: + description: + - "The date at which notifications will be re-enabled automatically." + type: str + returned: Always + asm_growth_block: + description: + - "The block of ASM fields: I(growth_factor), I(growth_type)." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: dict + returned: Always + contains: + growth_factor: + description: + - "Either the number or percentage of addresses to grow by." + type: int + returned: Always + growth_type: + description: + - "The type of factor to use: I(percent) or I(count)." + type: str + returned: Always + asm_threshold: + description: + - "ASM shows the number of addresses forecast to be used I(forecast_period) days in the future, if it is greater than I(asm_threshold_percent) * I(dhcp_total) (see I(dhcp_utilization)) then the subnet is flagged." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: int + returned: Always + forecast_period: + description: + - "The forecast period in days." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: int + returned: Always + history: + description: + - "The minimum amount of history needed before ASM can run on this subnet." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: int + returned: Always + min_total: + description: + - "The minimum size of range needed for ASM to run on this subnet." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: int + returned: Always + min_unused: + description: + - "The minimum percentage of addresses that must be available outside of the DHCP ranges and fixed addresses when making a suggested change." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: int + returned: Always + ddns_client_update: + description: + - "The inheritance configuration for I(ddns_client_update) field." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: str + returned: Always + ddns_conflict_resolution_mode: + description: + - "The inheritance configuration for I(ddns_conflict_resolution_mode) field." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: str + returned: Always + ddns_enabled: + description: + - "The inheritance configuration for I(ddns_enabled) field. Only action allowed is 'inherit'." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: bool + returned: Always + ddns_hostname_block: + description: + - "The inheritance configuration for I(ddns_generate_name) and I(ddns_generated_prefix) fields." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: dict + returned: Always + contains: + ddns_generate_name: + description: + - "Indicates if DDNS should generate a hostname when not supplied by the client." + type: bool + returned: Always + ddns_generated_prefix: + description: + - "The prefix used in the generation of an FQDN." + type: str + returned: Always + ddns_ttl_percent: + description: + - "The inheritance configuration for I(ddns_ttl_percent) field." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: float + returned: Always + ddns_update_block: + description: + - "The inheritance configuration for I(ddns_send_updates) and I(ddns_domain) fields." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: dict + returned: Always + contains: + ddns_domain: + description: + - "The domain name for DDNS." + type: str + returned: Always + ddns_send_updates: + description: + - "Determines if DDNS updates are enabled at this level." + type: bool + returned: Always + ddns_update_on_renew: + description: + - "The inheritance configuration for I(ddns_update_on_renew) field." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: bool + returned: Always + ddns_use_conflict_resolution: + description: + - "The inheritance configuration for I(ddns_use_conflict_resolution) field." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: bool + returned: Always + dhcp_config: + description: + - "The inheritance configuration for I(dhcp_config) field." + type: dict + returned: Always + contains: + abandoned_reclaim_time: + description: + - "The inheritance configuration for I(abandoned_reclaim_time) field from I(DHCPConfig) object." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: int + returned: Always + abandoned_reclaim_time_v6: + description: + - "The inheritance configuration for I(abandoned_reclaim_time_v6) field from I(DHCPConfig) object." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: int + returned: Always + allow_unknown: + description: + - "The inheritance configuration for I(allow_unknown) field from I(DHCPConfig) object." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: bool + returned: Always + allow_unknown_v6: + description: + - "The inheritance configuration for I(allow_unknown_v6) field from I(DHCPConfig) object." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: bool + returned: Always + echo_client_id: + description: + - "The inheritance configuration for I(echo_client_id) field from I(DHCPConfig) object." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: bool + returned: Always + filters: + description: + - "The inheritance configuration for filters field from I(DHCPConfig) object." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The resource identifier." + type: list + returned: Always + filters_v6: + description: + - "The inheritance configuration for I(filters_v6) field from I(DHCPConfig) object." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The resource identifier." + type: list + returned: Always + ignore_client_uid: + description: + - "The inheritance configuration for I(ignore_client_uid) field from I(DHCPConfig) object." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: bool + returned: Always + ignore_list: + description: + - "The inheritance configuration for I(ignore_list) field from I(DHCPConfig) object." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: list + returned: Always + elements: dict + contains: + type: + description: + - "Type of ignore matching: client to ignore by client identifier (client hex or client text) or hardware to ignore by hardware identifier (MAC address). It can have one of the following values:" + - "* I(client_hex)," + - "* I(client_text)," + - "* I(hardware)." + type: str + returned: Always + value: + description: + - "Value to match." + type: str + returned: Always + lease_time: + description: + - "The inheritance configuration for I(lease_time) field from I(DHCPConfig) object." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: int + returned: Always + lease_time_v6: + description: + - "The inheritance configuration for I(lease_time_v6) field from I(DHCPConfig) object." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: int + returned: Always + dhcp_options: + description: + - "The inheritance configuration for I(dhcp_options) field." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(block): Don't use the inherited value." + - "Defaults to I(inherit)." + type: str + returned: Always + value: + description: + - "The inherited DHCP option values." + type: list + returned: Always + elements: dict + contains: + action: + description: + - "The inheritance setting." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(block): Don't use the inherited value." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value for the DHCP option." + type: dict + returned: Always + contains: + option: + description: + - "Option inherited from the ancestor." + type: dict + returned: Always + contains: + group: + description: + - "The resource identifier." + type: str + returned: Always + option_code: + description: + - "The resource identifier." + type: str + returned: Always + option_value: + description: + - "The option value." + type: str + returned: Always + type: + description: + - "The type of item." + - "Valid values are:" + - "* I(group)" + - "* I(option)" + type: str + returned: Always + overriding_group: + description: + - "The resource identifier." + type: str + returned: Always + header_option_filename: + description: + - "The inheritance configuration for I(header_option_filename) field." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: str + returned: Always + header_option_server_address: + description: + - "The inheritance configuration for I(header_option_server_address) field." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: str + returned: Always + header_option_server_name: + description: + - "The inheritance configuration for I(header_option_server_name) field." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting for a field." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: str + returned: Always + hostname_rewrite_block: + description: + - "The inheritance configuration for I(hostname_rewrite_enabled), I(hostname_rewrite_regex), and I(hostname_rewrite_char) fields." + type: dict + returned: Always + contains: + action: + description: + - "The inheritance setting." + - "Valid values are:" + - "* I(inherit): Use the inherited value." + - "* I(override): Use the value set in the object." + - "Defaults to I(inherit)." + type: str + returned: Always + display_name: + description: + - "The human-readable display name for the object referred to by I(source)." + type: str + returned: Always + source: + description: + - "The resource identifier." + type: str + returned: Always + value: + description: + - "The inherited value." + type: dict + returned: Always + contains: + hostname_rewrite_char: + description: + - "The inheritance configuration for I(hostname_rewrite_char) field." + type: str + returned: Always + hostname_rewrite_enabled: + description: + - "The inheritance configuration for I(hostname_rewrite_enabled) field." + type: bool + returned: Always + hostname_rewrite_regex: + description: + - "The inheritance configuration for I(hostname_rewrite_regex) field." + type: str + returned: Always + name: + description: + - "The name of the address block. May contain 1 to 256 characters. Can include UTF-8." + type: str + returned: Always + parent: + description: + - "The resource identifier." + type: str + returned: Always + protocol: + description: + - "The type of protocol of address block (I(ip4) or I(ip6))." + type: str + returned: Always + space: + description: + - "The resource identifier." + type: str + returned: Always + tags: + description: + - "The tags for the address block in JSON format." + type: dict + returned: Always + threshold: + description: + - "The IP address utilization thresholds for the address block." + type: dict + returned: Always + contains: + enabled: + description: + - "Indicates whether the utilization threshold for IP addresses is enabled or not." + type: bool + returned: Always + high: + description: + - "The high threshold value for the percentage of used IP addresses relative to the total IP addresses available in the scope of the object. Thresholds are inclusive in the comparison test." + type: int + returned: Always + low: + description: + - "The low threshold value for the percentage of used IP addresses relative to the total IP addresses available in the scope of the object. Thresholds are inclusive in the comparison test." + type: int + 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 + usage: + description: + - "The usage is a combination of indicators, each tracking a specific associated use. Listed below are usage indicators with their meaning: usage indicator | description ---------------------- | -------------------------------- I(IPAM) | AddressBlock is managed in BloxOne DDI. I(DISCOVERED) | AddressBlock is discovered by some network discovery probe like Network Insight or NetMRI in NIOS." + type: list + returned: Always + utilization: + description: + - "The IPV4 address utilization statistics for the address block." + type: dict + returned: Always + contains: + abandon_utilization: + description: + - "The percentage of abandoned IP addresses relative to the total IP addresses available in the scope of the object." + type: int + returned: Always + abandoned: + description: + - "The number of IP addresses in the scope of the object which are in the abandoned state (issued by a DHCP server and then declined by the client)." + type: str + returned: Always + dynamic: + description: + - "The number of IP addresses handed out by DHCP in the scope of the object. This includes all leased addresses, fixed addresses that are defined but not currently leased and abandoned leases." + type: str + returned: Always + free: + description: + - "The number of IP addresses available in the scope of the object." + type: str + returned: Always + static: + description: + - "The number of defined IP addresses such as reservations or DNS records. It can be computed as I(static) = I(used) - I(dynamic)." + type: str + returned: Always + total: + description: + - "The total number of IP addresses available in the scope of the object." + type: str + returned: Always + used: + description: + - "The number of IP addresses used in the scope of the object." + type: str + returned: Always + utilization: + description: + - "The percentage of used IP addresses relative to the total IP addresses available in the scope of the object." + type: int + returned: Always + utilization_v6: + description: + - "The utilization of IPV6 addresses in the Address block." + type: dict + returned: Always + contains: + abandoned: + description: "" + type: str + returned: Always + dynamic: + description: "" + type: str + returned: Always + static: + description: "" + type: str + returned: Always + total: + description: "" + type: str + returned: Always + used: + description: "" + type: str + returned: Always +""" # noqa: E501 + +from ansible_collections.infoblox.bloxone.plugins.module_utils.modules import BloxoneAnsibleModule + +try: + from bloxone_client import ApiException + from ipam import AddressBlockApi +except ImportError: + pass # Handled by BloxoneAnsibleModule + + +class NextAvailableAddressBlockInfoModule(BloxoneAnsibleModule): + def __init__(self, *args, **kwargs): + super(NextAvailableAddressBlockInfoModule, self).__init__(*args, **kwargs) + self._existing = None + self._limit = 1000 + + def find(self): + all_results = [] + offset = 0 + while True: + try: + resp = AddressBlockApi(self.client).list_next_available_ab( + id=self.params["id"], cidr=self.params["cidr"], count=self.params["count"] + ) + 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=True), + cidr=dict(type="int", required=False), + count=dict(type="int", required=False), + ) + + module = NextAvailableAddressBlockInfoModule( + argument_spec=module_args, + supports_check_mode=True, + ) + module.run_command() + + +if __name__ == "__main__": + main() diff --git a/tests/integration/targets/ipam_address_block/meta/main.yml b/tests/integration/targets/ipam_address_block/meta/main.yml new file mode 100644 index 00000000..32c7cbc6 --- /dev/null +++ b/tests/integration/targets/ipam_address_block/meta/main.yml @@ -0,0 +1,2 @@ +--- +dependencies: [setup_ip_space] diff --git a/tests/integration/targets/ipam_address_block_info/meta/main.yml b/tests/integration/targets/ipam_address_block_info/meta/main.yml new file mode 100644 index 00000000..32c7cbc6 --- /dev/null +++ b/tests/integration/targets/ipam_address_block_info/meta/main.yml @@ -0,0 +1,2 @@ +--- +dependencies: [setup_ip_space] diff --git a/tests/integration/targets/ipam_next_available_address_block_info/meta/main.yml b/tests/integration/targets/ipam_next_available_address_block_info/meta/main.yml new file mode 100644 index 00000000..32c7cbc6 --- /dev/null +++ b/tests/integration/targets/ipam_next_available_address_block_info/meta/main.yml @@ -0,0 +1,2 @@ +--- +dependencies: [setup_ip_space] diff --git a/tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml b/tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml new file mode 100644 index 00000000..f12be292 --- /dev/null +++ b/tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml @@ -0,0 +1,49 @@ +--- +- module_defaults: + group/infoblox.bloxone.all: + csp_url: "{{ csp_url }}" + api_key: "{{ api_key }}" + block: + # Create a random IP space name to avoid conflicts + - ansible.builtin.set_fact: + name: "test-ip-space-{{ 999999 | random | string }}" + tag_value: "site-{{ 999999 | random | string }}" + + - name: "Create an Address Block" + infoblox.bloxone.ipam_address_block: + address: "10.0.0.0/16" + space: "{{ _ip_space.id }}" + state: "present" + register: address_block + - name: Get information about the Address Block + infoblox.bloxone.ipam_address_block_info: + filters: + address: "10.0.0.0" + space: "{{ _ip_space.id }}" + cidr: 16 + register: address_block_info + - assert: + that: + - address_block is changed + - address_block is not failed + - address_block_info.objects | length == 1 + + - name: "Create Next Available Address Block" + infoblox.bloxone.ipam_address_block: + space: "{{ _ip_space.id }}" + cidr: 20 + next_available_id: "{{ address_block.id }}" + state: "present" + register: next_available_address_block + + - name: Get Next Available Address Block Information by ID + infoblox.bloxone.ipam_next_available_address_block_info: + id: "{{ next_available_address_block.id }}" + cidr: 20 + register: next_available_address_block_info + + - name: Get Next Available Address Block Information by ID and Count + infoblox.bloxone.ipam_next_available_address_block_info: + id: "{{ next_available_address_block.id }}" + cidr: 24 + count: 5 diff --git a/tests/integration/targets/setup_ip_space/tasks/cleanup.yml b/tests/integration/targets/setup_ip_space/tasks/cleanup.yml new file mode 100644 index 00000000..e69de29b diff --git a/tests/integration/targets/setup_ip_space/tasks/main.yml b/tests/integration/targets/setup_ip_space/tasks/main.yml new file mode 100644 index 00000000..e69de29b diff --git a/tests/integration/targets/setup_subnet/meta/main.yml b/tests/integration/targets/setup_subnet/meta/main.yml new file mode 100644 index 00000000..e69de29b diff --git a/tests/integration/targets/setup_subnet/tasks/main.yml b/tests/integration/targets/setup_subnet/tasks/main.yml new file mode 100644 index 00000000..e69de29b From f8b1b4056e088905aa94d815f7f04f30c9be4248 Mon Sep 17 00:00:00 2001 From: VishrutiBuddhadev Date: Tue, 7 Jan 2025 15:23:02 +0530 Subject: [PATCH 02/10] added test cases for next_available_address_block --- .../targets/ipam_address_block/tasks/main.yml | 109 +++++++++++------- .../ipam_address_block_info/tasks/main.yml | 12 +- .../targets/setup_ip_space/tasks/cleanup.yml | 15 +++ .../targets/setup_ip_space/tasks/main.yml | 15 +++ .../targets/setup_subnet/meta/main.yml | 2 + .../targets/setup_subnet/tasks/main.yml | 16 +++ 6 files changed, 121 insertions(+), 48 deletions(-) diff --git a/tests/integration/targets/ipam_address_block/tasks/main.yml b/tests/integration/targets/ipam_address_block/tasks/main.yml index d4ad00cc..8db3beb0 100644 --- a/tests/integration/targets/ipam_address_block/tasks/main.yml +++ b/tests/integration/targets/ipam_address_block/tasks/main.yml @@ -6,20 +6,12 @@ block: # Create a random IP space name to avoid conflicts - ansible.builtin.set_fact: - name: "test-ip-space-{{ 999999 | random | string }}" tag_value: "site-{{ 999999 | random | string }}" - # Basic tests for Address Block - - name: "Create an IP space" - infoblox.bloxone.ipam_ip_space: - name: "{{ name }}" - state: "present" - register: ip_space - - name: "Create an Address Block (check mode)" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" state: "present" check_mode: true register: address_block @@ -27,7 +19,7 @@ infoblox.bloxone.ipam_address_block_info: filters: address: "10.0.0.0" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" cidr: 16 register: address_block_info - assert: @@ -39,14 +31,14 @@ - name: "Create an Address Block" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" state: "present" register: address_block - name: Get information about the Address Block infoblox.bloxone.ipam_address_block_info: filters: address: "10.0.0.0" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" cidr: 16 register: address_block_info - assert: @@ -58,7 +50,7 @@ - name: "Create an Address Block (idempotent)" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" state: "present" register: address_block - assert: @@ -66,10 +58,51 @@ - address_block is not changed - address_block is not failed + - name: "Create Next Available Address Block" + infoblox.bloxone.ipam_address_block: + space: "{{ _ip_space.id }}" + cidr: 20 + next_available_id: "{{ address_block.id }}" + state: "present" + register: next_available_address_block +# Get information about the created Address Block using Next Available ID + - name: Get Address Block Information by ID + infoblox.bloxone.ipam_address_block_info: + id: "{{ next_available_address_block.id }}" + register: next_available_address_block_info + - assert: + that: + - next_available_address_block is changed + - next_available_address_block is not failed + - next_available_address_block_info.objects | length == 1 + + - name: Get Next Available Address Block Information by ID + infoblox.bloxone.ipam_next_available_address_block_info: + id: "{{ next_available_address_block.id }}" + cidr: 20 + register: next_available_address_block_info + - assert: + that: + - next_available_address_block is changed + - next_available_address_block is not failed + - next_available_address_block_info.objects | length == 1 + + - name: Get Next Available Address Block Information by ID and Count + infoblox.bloxone.ipam_next_available_address_block_info: + id: "{{ next_available_address_block.id }}" + cidr: 24 + count: 5 + register: next_available_address_block_info + - assert: + that: + - next_available_address_block is changed + - next_available_address_block is not failed + - next_available_address_block_info.objects | length == 5 + - name: "Delete an Address Block (check mode)" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" state: "absent" check_mode: true register: address_block @@ -77,7 +110,7 @@ infoblox.bloxone.ipam_address_block_info: filters: address: "10.0.0.0" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" cidr: 16 register: address_block_info - assert: @@ -89,14 +122,14 @@ - name: "Delete an Address Block" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" state: "absent" register: address_block - name: Get information about the Address Block infoblox.bloxone.ipam_address_block_info: filters: address: "10.0.0.0" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" cidr: 16 register: address_block_info - assert: @@ -108,7 +141,7 @@ - name: "Delete an Address Block (idempotent)" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" state: "absent" register: address_block - assert: @@ -120,14 +153,14 @@ infoblox.bloxone.ipam_address_block: address: "10.0.0.0" cidr: 16 - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" state: "present" register: address_block - name: Get information about the Address Block infoblox.bloxone.ipam_address_block_info: filters: address: "10.0.0.0" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" cidr: 16 register: address_block_info - assert: @@ -139,7 +172,7 @@ - name: "Create an Address Block with ASM config overridden" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" asm_config: asm_threshold: 70 enable: true @@ -172,7 +205,7 @@ infoblox.bloxone.ipam_address_block_info: filters: address: "10.0.0.0" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" cidr: 16 register: address_block_info - assert: @@ -188,7 +221,7 @@ - name: "Create an Address Block with comment" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" state: "present" comment: "Comment." register: address_block @@ -196,7 +229,7 @@ infoblox.bloxone.ipam_address_block_info: filters: address: "10.0.0.0" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" cidr: 16 register: address_block_info - assert: @@ -208,7 +241,7 @@ - name: "Create an Address Block with ddns_client_update set to server" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" state: "present" ddns_client_update: "server" register: address_block @@ -216,7 +249,7 @@ infoblox.bloxone.ipam_address_block_info: filters: address: "10.0.0.0" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" cidr: 16 register: address_block_info - assert: @@ -228,7 +261,7 @@ - name: "Create an Address Block with ddns_use_conflict_resolution set to false" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" state: "present" ddns_use_conflict_resolution: "false" register: address_block @@ -236,7 +269,7 @@ infoblox.bloxone.ipam_address_block_info: filters: address: "10.0.0.0" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" cidr: 16 register: address_block_info - assert: @@ -248,7 +281,7 @@ - name: "Create an Address Block with DHCP config overridden" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" dhcp_config: lease_time: 3600 inheritance_sources: @@ -281,7 +314,7 @@ infoblox.bloxone.ipam_address_block_info: filters: address: "10.0.0.0" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" cidr: 16 register: address_block_info - assert: @@ -294,7 +327,7 @@ - name: "Create an Address Block with hostname_rewrite_enabled set to true" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" state: "present" hostname_rewrite_enabled: "true" register: address_block @@ -302,7 +335,7 @@ infoblox.bloxone.ipam_address_block_info: filters: address: "10.0.0.0" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" cidr: 16 register: address_block_info - assert: @@ -314,7 +347,7 @@ - name: "Create an Address Block with tags" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" tags: location: "{{ tag_value }}" state: "present" @@ -323,7 +356,7 @@ infoblox.bloxone.ipam_address_block_info: filters: address: "10.0.0.0" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" cidr: 16 register: address_block_info - assert: @@ -334,8 +367,6 @@ always: # Cleanup if the test fails - - name: "Delete IP Space" - infoblox.bloxone.ipam_ip_space: - name: "{{ name }}" - state: "absent" - ignore_errors: true + - ansible.builtin.include_role: + name: setup_ip_space + tasks_from: cleanup.yml diff --git a/tests/integration/targets/ipam_address_block_info/tasks/main.yml b/tests/integration/targets/ipam_address_block_info/tasks/main.yml index ad4b1570..8c5c9417 100644 --- a/tests/integration/targets/ipam_address_block_info/tasks/main.yml +++ b/tests/integration/targets/ipam_address_block_info/tasks/main.yml @@ -9,16 +9,10 @@ name: "test-ip-space-{{ 999999 | random | string }}" tag_value: "site-{{ 999999 | random | string }}" - - name: "Create an IP space" - infoblox.bloxone.ipam_ip_space: - name: "{{ name }}" - state: "present" - register: ip_space - - name: "Create an Address Block" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" tags: location: "{{ tag_value }}" state: "present" @@ -37,7 +31,7 @@ infoblox.bloxone.ipam_address_block_info: filters: address: "10.0.0.0" - space: "{{ ip_space.id }}" + space: "{{ _ip_space.id }}" cidr: 16 register: address_block_info - assert: @@ -47,7 +41,7 @@ - name: Get Address Block information by filter query infoblox.bloxone.ipam_address_block_info: - filter_query: "address=='10.0.0.0' and space=='{{ ip_space.id }}' and cidr==16" + filter_query: "address=='10.0.0.0' and space=='{{ _ip_space.id }}' and cidr==16" register: address_block_info - assert: that: diff --git a/tests/integration/targets/setup_ip_space/tasks/cleanup.yml b/tests/integration/targets/setup_ip_space/tasks/cleanup.yml index e69de29b..ebc8497d 100644 --- a/tests/integration/targets/setup_ip_space/tasks/cleanup.yml +++ b/tests/integration/targets/setup_ip_space/tasks/cleanup.yml @@ -0,0 +1,15 @@ +--- +- module_defaults: + group/infoblox.bloxone.all: + csp_url: "{{ csp_url }}" + api_key: "{{ api_key }}" + block: + # Create a random IP space name to avoid conflicts + - ansible.builtin.set_fact: + ip_space_name: "ip-space-{{ 999999 | random | string }}" + + - name: "Create an IP space" + infoblox.bloxone.ipam_ip_space: + name: "{{ ip_space_name }}" + state: "present" + register: _ip_space diff --git a/tests/integration/targets/setup_ip_space/tasks/main.yml b/tests/integration/targets/setup_ip_space/tasks/main.yml index e69de29b..ebc8497d 100644 --- a/tests/integration/targets/setup_ip_space/tasks/main.yml +++ b/tests/integration/targets/setup_ip_space/tasks/main.yml @@ -0,0 +1,15 @@ +--- +- module_defaults: + group/infoblox.bloxone.all: + csp_url: "{{ csp_url }}" + api_key: "{{ api_key }}" + block: + # Create a random IP space name to avoid conflicts + - ansible.builtin.set_fact: + ip_space_name: "ip-space-{{ 999999 | random | string }}" + + - name: "Create an IP space" + infoblox.bloxone.ipam_ip_space: + name: "{{ ip_space_name }}" + state: "present" + register: _ip_space diff --git a/tests/integration/targets/setup_subnet/meta/main.yml b/tests/integration/targets/setup_subnet/meta/main.yml index e69de29b..32c7cbc6 100644 --- a/tests/integration/targets/setup_subnet/meta/main.yml +++ b/tests/integration/targets/setup_subnet/meta/main.yml @@ -0,0 +1,2 @@ +--- +dependencies: [setup_ip_space] diff --git a/tests/integration/targets/setup_subnet/tasks/main.yml b/tests/integration/targets/setup_subnet/tasks/main.yml index e69de29b..02c2c375 100644 --- a/tests/integration/targets/setup_subnet/tasks/main.yml +++ b/tests/integration/targets/setup_subnet/tasks/main.yml @@ -0,0 +1,16 @@ +--- +- module_defaults: + group/infoblox.bloxone.all: + csp_url: "{{ csp_url }}" + api_key: "{{ api_key }}" + block: + # Create a random Subnet name to avoid conflicts + - ansible.builtin.set_fact: + name: "subnet-{{ 999999 | random | string }}" + + - name: "Create a Subnet" + infoblox.bloxone.ipam_subnet: + address: "10.0.0.0/24" + space: "{{ _ip_space.id }}" + state: "present" + register: _subnet From c5f20bd86711e54c31ea7130fa83ebf97980625e Mon Sep 17 00:00:00 2001 From: VishrutiBuddhadev Date: Tue, 7 Jan 2025 15:23:34 +0530 Subject: [PATCH 03/10] modified examples --- plugins/modules/ipam_address_block_info.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/plugins/modules/ipam_address_block_info.py b/plugins/modules/ipam_address_block_info.py index 26cc459c..a871283f 100644 --- a/plugins/modules/ipam_address_block_info.py +++ b/plugins/modules/ipam_address_block_info.py @@ -62,9 +62,8 @@ address: "10.0.0.0/16" space: "{{ ip_space.id }}" tags: - location: "{{ tag_value }}" + location: "site-1" state: "present" - register: address_block - name: Get Address Block information by ID infoblox.bloxone.ipam_address_block_info: @@ -83,7 +82,7 @@ - name: Get Address Block information by tag filters infoblox.bloxone.ipam_address_block_info: tag_filters: - location: "{{ tag_value }}" + location: "site-1" """ RETURN = r""" From 1f98e6f25ce47dc0d533d0b83a89326dda48083b Mon Sep 17 00:00:00 2001 From: VishrutiBuddhadev Date: Tue, 7 Jan 2025 15:24:36 +0530 Subject: [PATCH 04/10] added ipam_next_available_address_block.py to runtime.yml --- meta/runtime.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/meta/runtime.yml b/meta/runtime.yml index f70cc610..8b088a3d 100644 --- a/meta/runtime.yml +++ b/meta/runtime.yml @@ -21,6 +21,7 @@ action_groups: - ipam_subnet_info - ipam_address_block - ipam_address_block_info + - ipam_next_available_address_block_info infra: - infra_join_token From 72650f28a3e0af005029c4d4e4b54cf5fd624885 Mon Sep 17 00:00:00 2001 From: VishrutiBuddhadev Date: Tue, 7 Jan 2025 15:41:57 +0530 Subject: [PATCH 05/10] modified cleanup.yml --- .../targets/setup_ip_space/tasks/cleanup.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/tests/integration/targets/setup_ip_space/tasks/cleanup.yml b/tests/integration/targets/setup_ip_space/tasks/cleanup.yml index ebc8497d..e9706626 100644 --- a/tests/integration/targets/setup_ip_space/tasks/cleanup.yml +++ b/tests/integration/targets/setup_ip_space/tasks/cleanup.yml @@ -4,12 +4,8 @@ csp_url: "{{ csp_url }}" api_key: "{{ api_key }}" block: - # Create a random IP space name to avoid conflicts - - ansible.builtin.set_fact: - ip_space_name: "ip-space-{{ 999999 | random | string }}" - - - name: "Create an IP space" + - name: "Delete IP space" infoblox.bloxone.ipam_ip_space: name: "{{ ip_space_name }}" - state: "present" - register: _ip_space + state: "absent" + ignore_errors: true From ba80dcd7e10538ce3023063fb33f81d5b499ddb5 Mon Sep 17 00:00:00 2001 From: VishrutiBuddhadev Date: Thu, 9 Jan 2025 11:40:06 +0530 Subject: [PATCH 06/10] addressed review comment --- plugins/modules/ipam_address_block.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/modules/ipam_address_block.py b/plugins/modules/ipam_address_block.py index debe0669..056183fe 100644 --- a/plugins/modules/ipam_address_block.py +++ b/plugins/modules/ipam_address_block.py @@ -744,7 +744,7 @@ - name: "Create an address block" infoblox.bloxone.ipam_address_block: - address: "10.0.0.0/24" + address: "10.0.0.0/16" space: "{{ ip_space.id }}" state: "present" From b0ed28b0603f557867b482d2815cb091fcebc99e Mon Sep 17 00:00:00 2001 From: VishrutiBuddhadev Date: Thu, 9 Jan 2025 15:06:03 +0530 Subject: [PATCH 07/10] modified examples --- .../ipam_next_available_address_block_info.py | 11 +++-- .../targets/ipam_address_block/tasks/main.yml | 24 ----------- .../tasks/main.yml | 40 ++++++------------- 3 files changed, 18 insertions(+), 57 deletions(-) diff --git a/plugins/modules/ipam_next_available_address_block_info.py b/plugins/modules/ipam_next_available_address_block_info.py index 1159aaa2..de0f16f3 100644 --- a/plugins/modules/ipam_next_available_address_block_info.py +++ b/plugins/modules/ipam_next_available_address_block_info.py @@ -36,21 +36,20 @@ """ # noqa: E501 EXAMPLES = r""" - - name: "Create Next Available Address Block" + - name: "Create an Address Block" infoblox.bloxone.ipam_address_block: - space: "{{ ip_space.id }}" - cidr: 20 - next_available_id: "{{ address_block.id }}" + address: "10.0.0.0/16" + space: "{{ _ip_space.id }}" state: "present" - name: Get Next Available Address Block Information by ID infoblox.bloxone.ipam_next_available_address_block_info: - id: "{{ next_available_address_block.id }}" + id: "{{ address_block.id }}" cidr: 20 - name: Get Next Available Address Block Information by ID and Count infoblox.bloxone.ipam_next_available_address_block_info: - id: "{{ next_available_address_block.id }}" + id: "{{ address_block.id }}" cidr: 24 count: 5 """ diff --git a/tests/integration/targets/ipam_address_block/tasks/main.yml b/tests/integration/targets/ipam_address_block/tasks/main.yml index 8db3beb0..4fc24274 100644 --- a/tests/integration/targets/ipam_address_block/tasks/main.yml +++ b/tests/integration/targets/ipam_address_block/tasks/main.yml @@ -65,7 +65,6 @@ next_available_id: "{{ address_block.id }}" state: "present" register: next_available_address_block -# Get information about the created Address Block using Next Available ID - name: Get Address Block Information by ID infoblox.bloxone.ipam_address_block_info: id: "{{ next_available_address_block.id }}" @@ -76,29 +75,6 @@ - next_available_address_block is not failed - next_available_address_block_info.objects | length == 1 - - name: Get Next Available Address Block Information by ID - infoblox.bloxone.ipam_next_available_address_block_info: - id: "{{ next_available_address_block.id }}" - cidr: 20 - register: next_available_address_block_info - - assert: - that: - - next_available_address_block is changed - - next_available_address_block is not failed - - next_available_address_block_info.objects | length == 1 - - - name: Get Next Available Address Block Information by ID and Count - infoblox.bloxone.ipam_next_available_address_block_info: - id: "{{ next_available_address_block.id }}" - cidr: 24 - count: 5 - register: next_available_address_block_info - - assert: - that: - - next_available_address_block is changed - - next_available_address_block is not failed - - next_available_address_block_info.objects | length == 5 - - name: "Delete an Address Block (check mode)" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" diff --git a/tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml b/tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml index f12be292..a4faf0ca 100644 --- a/tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml +++ b/tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml @@ -4,46 +4,32 @@ csp_url: "{{ csp_url }}" api_key: "{{ api_key }}" block: - # Create a random IP space name to avoid conflicts - - ansible.builtin.set_fact: - name: "test-ip-space-{{ 999999 | random | string }}" - tag_value: "site-{{ 999999 | random | string }}" - - name: "Create an Address Block" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" space: "{{ _ip_space.id }}" state: "present" register: address_block - - name: Get information about the Address Block - infoblox.bloxone.ipam_address_block_info: - filters: - address: "10.0.0.0" - space: "{{ _ip_space.id }}" - cidr: 16 - register: address_block_info - - assert: - that: - - address_block is changed - - address_block is not failed - - address_block_info.objects | length == 1 - - - name: "Create Next Available Address Block" - infoblox.bloxone.ipam_address_block: - space: "{{ _ip_space.id }}" - cidr: 20 - next_available_id: "{{ address_block.id }}" - state: "present" - register: next_available_address_block - name: Get Next Available Address Block Information by ID infoblox.bloxone.ipam_next_available_address_block_info: - id: "{{ next_available_address_block.id }}" + id: "{{ address_block.id }}" cidr: 20 register: next_available_address_block_info + - assert: + that: + - address_block is changed + - address_block is not failed + - next_available_address_block_info.objects | length == 1 - name: Get Next Available Address Block Information by ID and Count infoblox.bloxone.ipam_next_available_address_block_info: - id: "{{ next_available_address_block.id }}" + id: "{{ address_block.id }}" cidr: 24 count: 5 + register: next_available_address_block_info + - assert: + that: + - address_block is changed + - address_block is not failed + - next_available_address_block_info.objects | length == 5 From 4cff777f272bedbf70e560b3f1b8eee2abc8ee5b Mon Sep 17 00:00:00 2001 From: VishrutiBuddhadev Date: Thu, 9 Jan 2025 17:47:36 +0530 Subject: [PATCH 08/10] modified examples --- .../ipam_next_available_address_block_info/tasks/main.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml b/tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml index a4faf0ca..8d4545e5 100644 --- a/tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml +++ b/tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml @@ -18,8 +18,7 @@ register: next_available_address_block_info - assert: that: - - address_block is changed - - address_block is not failed + - next_available_address_block_info is not failed - next_available_address_block_info.objects | length == 1 - name: Get Next Available Address Block Information by ID and Count @@ -30,6 +29,5 @@ register: next_available_address_block_info - assert: that: - - address_block is changed - - address_block is not failed + - next_available_address_block_info is not failed - next_available_address_block_info.objects | length == 5 From 8d464398d65d5b51312cf7888dacbe6aa3c8c7da Mon Sep 17 00:00:00 2001 From: VishrutiBuddhadev Date: Mon, 13 Jan 2025 14:14:10 +0530 Subject: [PATCH 09/10] addressed review comments --- plugins/modules/ipam_address_block.py | 40 +++++++------------ plugins/modules/ipam_address_block_info.py | 12 +++--- .../ipam_next_available_address_block_info.py | 16 ++++---- .../ipam_address_block_info/tasks/main.yml | 7 +++- .../tasks/main.yml | 6 +++ 5 files changed, 40 insertions(+), 41 deletions(-) diff --git a/plugins/modules/ipam_address_block.py b/plugins/modules/ipam_address_block.py index 056183fe..c75c4845 100644 --- a/plugins/modules/ipam_address_block.py +++ b/plugins/modules/ipam_address_block.py @@ -76,7 +76,7 @@ - "The minimum percentage of addresses that must be available outside of the DHCP ranges and fixed addresses when making a suggested change.." type: int reenable_date: - description: "" + description: "The date at which notifications will be re-enabled automatically." type: str cidr: description: @@ -737,7 +737,7 @@ """ # noqa: E501 EXAMPLES = r""" - - name: "Create an ip space (required as parent)" + - name: "Create an IP space (required as parent)" infoblox.bloxone.ipam_ip_space: name: "my-ip-space" state: "present" @@ -755,24 +755,12 @@ next_available_id: "{{ address_block.id }}" state: "present" - - name: "Delete an Address Block" - infoblox.bloxone.ipam_address_block: - address: "10.0.0.0/16" - space: "{{ ip_space.id }}" - state: "absent" - - - name: "Create an Address Block with separate cidr" + - name: "Create an Address Block with Additional Fields" infoblox.bloxone.ipam_address_block: address: "10.0.0.0" cidr: 16 space: "{{ ip_space.id }}" state: "present" - - - name: "Create an Address Block with DHCP config overridden" - infoblox.bloxone.ipam_address_block: - address: "10.0.0.0/16" - space: "{{ ip_space.id }}" - state: "present" dhcp_config: lease_time: 3600 inheritance_sources: @@ -799,14 +787,14 @@ action: inherit lease_time_v6: action: inherit + tags: + location: "site-1" - - name: "Create an Address Block with tags" + - name: "Delete an Address Block" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" space: "{{ ip_space.id }}" - state: "present" - tags: - location: "site-1" + state: "absent" """ RETURN = r""" @@ -878,7 +866,7 @@ type: int returned: Always reenable_date: - description: "" + description: "The date at which notifications will be re-enabled automatically." type: str returned: Always asm_scope_flag: @@ -2326,23 +2314,23 @@ returned: Always contains: abandoned: - description: "" + description: "The number of IP addresses in the scope of the object which are in the abandoned state (issued by a DHCP server and then declined by the client)." type: str returned: Always dynamic: - description: "" + description: "The number of IP addresses handed out by DHCP in the scope of the object. This includes all leased addresses, fixed addresses that are defined but not currently leased and abandoned leases." type: str returned: Always static: - description: "" + description: "The number of defined IP addresses such as reservations or DNS records. It can be computed as _static_ = _used_ - _dynamic_." type: str returned: Always total: - description: "" + description: "The total number of IP addresses available in the scope of the object." type: str returned: Always used: - description: "" + description: "The number of IP addresses used in the scope of the object." type: str returned: Always """ # noqa: E501 @@ -2412,7 +2400,7 @@ def find(self): return None raise e else: - # If address is None, return None, indicating next_available_address block should be created and not updated + # If address is None, return None, indicating next_available_address block should be created if self.params["address"] is None: return None filter = f"address=='{self.params['address']}' and space=='{self.params['space']}' and cidr=={self.params['cidr']}" diff --git a/plugins/modules/ipam_address_block_info.py b/plugins/modules/ipam_address_block_info.py index a871283f..a03e9d92 100644 --- a/plugins/modules/ipam_address_block_info.py +++ b/plugins/modules/ipam_address_block_info.py @@ -155,7 +155,7 @@ type: int returned: Always reenable_date: - description: "" + description: "The date at which notifications will be re-enabled automatically." type: str returned: Always asm_scope_flag: @@ -1618,23 +1618,23 @@ returned: Always contains: abandoned: - description: "" + description: "The number of IP addresses in the scope of the object which are in the abandoned state (issued by a DHCP server and then declined by the client)." type: str returned: Always dynamic: - description: "" + description: "The number of IP addresses handed out by DHCP in the scope of the object. This includes all leased addresses, fixed addresses that are defined but not currently leased and abandoned leases." type: str returned: Always static: - description: "" + description: "The number of defined IP addresses such as reservations or DNS records. It can be computed as _static_ = _used_ - _dynamic_." type: str returned: Always total: - description: "" + description: "The total number of IP addresses available in the scope of the object." type: str returned: Always used: - description: "" + description: "The number of IP addresses used in the scope of the object." type: str returned: Always """ # noqa: E501 diff --git a/plugins/modules/ipam_next_available_address_block_info.py b/plugins/modules/ipam_next_available_address_block_info.py index de0f16f3..c706cdbf 100644 --- a/plugins/modules/ipam_next_available_address_block_info.py +++ b/plugins/modules/ipam_next_available_address_block_info.py @@ -25,7 +25,7 @@ description: - The CIDR value of the object type: int - required: false + required: true count: description: - Number of objects to generate. Default 1 if not set @@ -124,7 +124,7 @@ type: int returned: Always reenable_date: - description: "" + description: "The date at which notifications will be re-enabled automatically." type: str returned: Always asm_scope_flag: @@ -1587,23 +1587,23 @@ returned: Always contains: abandoned: - description: "" + description: "The number of IP addresses in the scope of the object which are in the abandoned state (issued by a DHCP server and then declined by the client)." type: str returned: Always dynamic: - description: "" + description: "The number of IP addresses handed out by DHCP in the scope of the object. This includes all leased addresses, fixed addresses that are defined but not currently leased and abandoned leases." type: str returned: Always static: - description: "" + description: "The number of defined IP addresses such as reservations or DNS records. It can be computed as _static_ = _used_ - _dynamic_." type: str returned: Always total: - description: "" + description: "The total number of IP addresses available in the scope of the object." type: str returned: Always used: - description: "" + description: "The number of IP addresses used in the scope of the object." type: str returned: Always """ # noqa: E501 @@ -1662,7 +1662,7 @@ def main(): # define available arguments/parameters a user can pass to the module module_args = dict( id=dict(type="str", required=True), - cidr=dict(type="int", required=False), + cidr=dict(type="int", required=True), count=dict(type="int", required=False), ) diff --git a/tests/integration/targets/ipam_address_block_info/tasks/main.yml b/tests/integration/targets/ipam_address_block_info/tasks/main.yml index 8c5c9417..28a88003 100644 --- a/tests/integration/targets/ipam_address_block_info/tasks/main.yml +++ b/tests/integration/targets/ipam_address_block_info/tasks/main.yml @@ -56,4 +56,9 @@ - assert: that: - address_block_info.objects | length == 1 - - address_block_info.objects[0].id == address_block.id \ No newline at end of file + - address_block_info.objects[0].id == address_block.id + always: + # Cleanup if the test fails + - ansible.builtin.include_role: + name: setup_ip_space + tasks_from: cleanup.yml diff --git a/tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml b/tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml index 8d4545e5..a3cada49 100644 --- a/tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml +++ b/tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml @@ -31,3 +31,9 @@ that: - next_available_address_block_info is not failed - next_available_address_block_info.objects | length == 5 + + always: + # Cleanup if the test fails + - ansible.builtin.include_role: + name: setup_ip_space + tasks_from: cleanup.yml From 58bb73c4be19c10ec5730fd804bf01c5ac4b7a4b Mon Sep 17 00:00:00 2001 From: VishrutiBuddhadev Date: Wed, 15 Jan 2025 23:00:15 +0530 Subject: [PATCH 10/10] addressed review comments --- changelogs/fragments/48-address-block.yml | 2 + plugins/modules/ipam_address_block.py | 3 + .../ipam_next_available_address_block_info.py | 1554 +---------------- .../tasks/main.yml | 2 +- 4 files changed, 14 insertions(+), 1547 deletions(-) create mode 100644 changelogs/fragments/48-address-block.yml diff --git a/changelogs/fragments/48-address-block.yml b/changelogs/fragments/48-address-block.yml new file mode 100644 index 00000000..a15bac58 --- /dev/null +++ b/changelogs/fragments/48-address-block.yml @@ -0,0 +1,2 @@ +major_changes: + - added support for creating and retrieving next available address blocks. \ No newline at end of file diff --git a/plugins/modules/ipam_address_block.py b/plugins/modules/ipam_address_block.py index c75c4845..08a6a8d0 100644 --- a/plugins/modules/ipam_address_block.py +++ b/plugins/modules/ipam_address_block.py @@ -741,12 +741,14 @@ infoblox.bloxone.ipam_ip_space: name: "my-ip-space" state: "present" + register: ip_space - name: "Create an address block" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" space: "{{ ip_space.id }}" state: "present" + register: address_block - name: "Create Next Available Address Block" infoblox.bloxone.ipam_address_block: @@ -2779,6 +2781,7 @@ def main(): mutually_exclusive=[["address", "next_available_id"]], required_if=[("state", "present", ["space"])], required_one_of=[["address", "next_available_id"]], + required_together=[["cidr", "next_available_id"]], ) module.run_command() diff --git a/plugins/modules/ipam_next_available_address_block_info.py b/plugins/modules/ipam_next_available_address_block_info.py index c706cdbf..014f25da 100644 --- a/plugins/modules/ipam_next_available_address_block_info.py +++ b/plugins/modules/ipam_next_available_address_block_info.py @@ -39,7 +39,7 @@ - name: "Create an Address Block" infoblox.bloxone.ipam_address_block: address: "10.0.0.0/16" - space: "{{ _ip_space.id }}" + space: "{{ ip_space.id }}" state: "present" - name: Get Next Available Address Block Information by ID @@ -57,1556 +57,16 @@ RETURN = r""" id: description: - - ID of the AddressBlock object + - ID of the AddressBlock object. type: str returned: Always objects: description: - - AddressBlock object + - List of next available address block's addresses. type: list - elements: dict + elements: str returned: Always - contains: - address: - description: - - "The address field in form \"a.b.c.d/n\" where the \"/n\" may be omitted. In this case, the CIDR value must be defined in the I(cidr) field. When reading, the I(address) field is always in the form \"a.b.c.d\"." - type: str - returned: Always - asm_config: - description: - - "The Automated Scope Management configuration for the address block." - type: dict - returned: Always - contains: - asm_threshold: - description: - - "ASM shows the number of addresses forecast to be used I(forecast_period) days in the future, if it is greater than I(asm_threshold) percent * I(dhcp_total) (see I(dhcp_utilization)) then the subnet is flagged." - type: int - returned: Always - enable: - description: - - "Indicates if Automated Scope Management is enabled." - type: bool - returned: Always - enable_notification: - description: - - "Indicates if ASM should send notifications to the user." - type: bool - returned: Always - forecast_period: - description: - - "The forecast period in days." - type: int - returned: Always - growth_factor: - description: - - "Indicates the growth in the number or percentage of IP addresses." - type: int - returned: Always - growth_type: - description: - - "The type of factor to use: I(percent) or I(count)." - type: str - returned: Always - history: - description: - - "The minimum amount of history needed before ASM can run on this subnet." - type: int - returned: Always - min_total: - description: - - "The minimum size of range needed for ASM to run on this subnet." - type: int - returned: Always - min_unused: - description: - - "The minimum percentage of addresses that must be available outside of the DHCP ranges and fixed addresses when making a suggested change.." - type: int - returned: Always - reenable_date: - description: "The date at which notifications will be re-enabled automatically." - type: str - returned: Always - asm_scope_flag: - description: - - "Incremented by 1 if the IP address usage limits for automated scope management are exceeded for any subnets in the address block." - type: int - returned: Always - cidr: - description: - - "The CIDR of the address block. This is required, if I(address) does not specify it in its input." - type: int - returned: Always - comment: - description: - - "The description for the address block. 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 - ddns_client_update: - description: - - "Controls who does the DDNS updates." - - "Valid values are:" - - "* I(client): DHCP server updates DNS if requested by client." - - "* I(server): DHCP server always updates DNS, overriding an update request from the client, unless the client requests no updates." - - "* I(ignore): DHCP server always updates DNS, even if the client says not to." - - "* I(over_client_update): Same as I(server). DHCP server always updates DNS, overriding an update request from the client, unless the client requests no updates." - - "* I(over_no_update): DHCP server updates DNS even if the client requests that no updates be done. If the client requests to do the update, DHCP server allows it." - - "Defaults to I(client)." - type: str - returned: Always - ddns_conflict_resolution_mode: - description: - - "The mode used for resolving conflicts while performing DDNS updates." - - "Valid values are:" - - "* I(check_with_dhcid): It includes adding a DHCID record and checking that record via conflict detection as per RFC 4703." - - "* I(no_check_with_dhcid): This will ignore conflict detection but add a DHCID record when creating/updating an entry." - - "* I(check_exists_with_dhcid): This will check if there is an existing DHCID record but does not verify the value of the record matches the update. This will also update the DHCID record for the entry." - - "* I(no_check_without_dhcid): This ignores conflict detection and will not add a DHCID record when creating/updating a DDNS entry." - - "Defaults to I(check_with_dhcid)." - type: str - returned: Always - ddns_domain: - description: - - "The domain suffix for DDNS updates. FQDN, may be empty." - - "Defaults to empty." - type: str - returned: Always - ddns_generate_name: - description: - - "Indicates if DDNS needs to generate a hostname when not supplied by the client." - - "Defaults to I(false)." - type: bool - returned: Always - ddns_generated_prefix: - description: - - "The prefix used in the generation of an FQDN." - - "When generating a name, DHCP server will construct the name in the format: [ddns-generated-prefix]-[address-text].[ddns-qualifying-suffix]. where address-text is simply the lease IP address converted to a hyphenated string." - - "Defaults to \"myhost\"." - type: str - returned: Always - ddns_send_updates: - description: - - "Determines if DDNS updates are enabled at the address block level. Defaults to I(true)." - type: bool - returned: Always - ddns_ttl_percent: - description: - - "DDNS TTL value - to be calculated as a simple percentage of the lease's lifetime, using the parameter's value as the percentage. It is specified as a percentage (e.g. 25, 75). Defaults to unspecified." - type: float - returned: Always - ddns_update_on_renew: - description: - - "Instructs the DHCP server to always update the DNS information when a lease is renewed even if its DNS information has not changed." - - "Defaults to I(false)." - type: bool - returned: Always - ddns_use_conflict_resolution: - description: - - "When true, DHCP server will apply conflict resolution, as described in RFC 4703, when attempting to fulfill the update request." - - "When false, DHCP server will simply attempt to update the DNS entries per the request, regardless of whether or not they conflict with existing entries owned by other DHCP4 clients." - - "Defaults to I(true)." - type: bool - returned: Always - dhcp_config: - description: - - "The shared DHCP configuration that controls how leases are issued for the address block." - type: dict - returned: Always - contains: - abandoned_reclaim_time: - description: - - "The abandoned reclaim time in seconds for IPV4 clients." - type: int - returned: Always - abandoned_reclaim_time_v6: - description: - - "The abandoned reclaim time in seconds for IPV6 clients." - type: int - returned: Always - allow_unknown: - description: - - "Disable to allow leases only for known IPv4 clients, those for which a fixed address is configured." - type: bool - returned: Always - allow_unknown_v6: - description: - - "Disable to allow leases only for known IPV6 clients, those for which a fixed address is configured." - type: bool - returned: Always - echo_client_id: - description: - - "Enable/disable to include/exclude the client id when responding to discover or request." - type: bool - returned: Always - filters: - description: - - "The resource identifier." - type: list - returned: Always - filters_v6: - description: - - "The resource identifier." - type: list - returned: Always - ignore_client_uid: - description: - - "Enable to ignore the client UID when issuing a DHCP lease. Use this option to prevent assigning two IP addresses for a client which does not have a UID during one phase of PXE boot but acquires one for the other phase." - type: bool - returned: Always - ignore_list: - description: - - "The list of clients to ignore requests from." - type: list - returned: Always - elements: dict - contains: - type: - description: - - "Type of ignore matching: client to ignore by client identifier (client hex or client text) or hardware to ignore by hardware identifier (MAC address). It can have one of the following values:" - - "* I(client_hex)," - - "* I(client_text)," - - "* I(hardware)." - type: str - returned: Always - value: - description: - - "Value to match." - type: str - returned: Always - lease_time: - description: - - "The lease duration in seconds." - type: int - returned: Always - lease_time_v6: - description: - - "The lease duration in seconds for IPV6 clients." - type: int - returned: Always - dhcp_options: - description: - - "The list of DHCP options for the address block. May be either a specific option or a group of options." - type: list - returned: Always - elements: dict - contains: - group: - description: - - "The resource identifier." - type: str - returned: Always - option_code: - description: - - "The resource identifier." - type: str - returned: Always - option_value: - description: - - "The option value." - type: str - returned: Always - type: - description: - - "The type of item." - - "Valid values are:" - - "* I(group)" - - "* I(option)" - type: str - returned: Always - dhcp_utilization: - description: - - "The utilization of IP addresses within the DHCP ranges of the address block." - type: dict - returned: Always - contains: - dhcp_free: - description: - - "The total free IP addresses in the DHCP ranges in the scope of this object. It can be computed as I(dhcp_total) - I(dhcp_used)." - type: str - returned: Always - dhcp_total: - description: - - "The total IP addresses available in the DHCP ranges in the scope of this object." - type: str - returned: Always - dhcp_used: - description: - - "The total IP addresses marked as used in the DHCP ranges in the scope of this object." - type: str - returned: Always - dhcp_utilization: - description: - - "The percentage of used IP addresses relative to the total IP addresses available in the DHCP ranges in the scope of this object." - type: int - returned: Always - discovery_attrs: - description: - - "The discovery attributes for this address block in JSON format." - type: dict - returned: Always - discovery_metadata: - description: - - "The discovery metadata for this address block in JSON format." - type: dict - returned: Always - header_option_filename: - description: - - "The configuration for header option filename field." - type: str - returned: Always - header_option_server_address: - description: - - "The configuration for header option server address field." - type: str - returned: Always - header_option_server_name: - description: - - "The configuration for header option server name field." - type: str - returned: Always - hostname_rewrite_char: - description: - - "The character to replace non-matching characters with, when hostname rewrite is enabled." - - "Any single ASCII character or no character if the invalid characters should be removed without replacement." - - "Defaults to \"-\"." - type: str - returned: Always - hostname_rewrite_enabled: - description: - - "Indicates if client supplied hostnames will be rewritten prior to DDNS update by replacing every character that does not match I(hostname_rewrite_regex) by I(hostname_rewrite_char)." - - "Defaults to I(false)." - type: bool - returned: Always - hostname_rewrite_regex: - description: - - "The regex bracket expression to match valid characters." - - "Must begin with \"[\" and end with \"]\" and be a compilable POSIX regex." - - "Defaults to \"[^a-zA-Z0-9_.]\"." - type: str - returned: Always - id: - description: - - "The resource identifier." - type: str - returned: Always - inheritance_parent: - description: - - "The resource identifier." - type: str - returned: Always - inheritance_sources: - description: - - "The DHCP inheritance configuration for the address block." - type: dict - returned: Always - contains: - asm_config: - description: - - "The inheritance configuration for I(asm_config) field." - type: dict - returned: Always - contains: - asm_enable_block: - description: - - "The block of ASM fields: I(enable), I(enable_notification), I(reenable_date)." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: dict - returned: Always - contains: - enable: - description: - - "Indicates whether Automated Scope Management is enabled or not." - type: bool - returned: Always - enable_notification: - description: - - "Indicates whether sending notifications to the users is enabled or not." - type: bool - returned: Always - reenable_date: - description: - - "The date at which notifications will be re-enabled automatically." - type: str - returned: Always - asm_growth_block: - description: - - "The block of ASM fields: I(growth_factor), I(growth_type)." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: dict - returned: Always - contains: - growth_factor: - description: - - "Either the number or percentage of addresses to grow by." - type: int - returned: Always - growth_type: - description: - - "The type of factor to use: I(percent) or I(count)." - type: str - returned: Always - asm_threshold: - description: - - "ASM shows the number of addresses forecast to be used I(forecast_period) days in the future, if it is greater than I(asm_threshold_percent) * I(dhcp_total) (see I(dhcp_utilization)) then the subnet is flagged." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: int - returned: Always - forecast_period: - description: - - "The forecast period in days." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: int - returned: Always - history: - description: - - "The minimum amount of history needed before ASM can run on this subnet." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: int - returned: Always - min_total: - description: - - "The minimum size of range needed for ASM to run on this subnet." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: int - returned: Always - min_unused: - description: - - "The minimum percentage of addresses that must be available outside of the DHCP ranges and fixed addresses when making a suggested change." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: int - returned: Always - ddns_client_update: - description: - - "The inheritance configuration for I(ddns_client_update) field." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: str - returned: Always - ddns_conflict_resolution_mode: - description: - - "The inheritance configuration for I(ddns_conflict_resolution_mode) field." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: str - returned: Always - ddns_enabled: - description: - - "The inheritance configuration for I(ddns_enabled) field. Only action allowed is 'inherit'." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: bool - returned: Always - ddns_hostname_block: - description: - - "The inheritance configuration for I(ddns_generate_name) and I(ddns_generated_prefix) fields." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: dict - returned: Always - contains: - ddns_generate_name: - description: - - "Indicates if DDNS should generate a hostname when not supplied by the client." - type: bool - returned: Always - ddns_generated_prefix: - description: - - "The prefix used in the generation of an FQDN." - type: str - returned: Always - ddns_ttl_percent: - description: - - "The inheritance configuration for I(ddns_ttl_percent) field." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: float - returned: Always - ddns_update_block: - description: - - "The inheritance configuration for I(ddns_send_updates) and I(ddns_domain) fields." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: dict - returned: Always - contains: - ddns_domain: - description: - - "The domain name for DDNS." - type: str - returned: Always - ddns_send_updates: - description: - - "Determines if DDNS updates are enabled at this level." - type: bool - returned: Always - ddns_update_on_renew: - description: - - "The inheritance configuration for I(ddns_update_on_renew) field." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: bool - returned: Always - ddns_use_conflict_resolution: - description: - - "The inheritance configuration for I(ddns_use_conflict_resolution) field." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: bool - returned: Always - dhcp_config: - description: - - "The inheritance configuration for I(dhcp_config) field." - type: dict - returned: Always - contains: - abandoned_reclaim_time: - description: - - "The inheritance configuration for I(abandoned_reclaim_time) field from I(DHCPConfig) object." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: int - returned: Always - abandoned_reclaim_time_v6: - description: - - "The inheritance configuration for I(abandoned_reclaim_time_v6) field from I(DHCPConfig) object." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: int - returned: Always - allow_unknown: - description: - - "The inheritance configuration for I(allow_unknown) field from I(DHCPConfig) object." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: bool - returned: Always - allow_unknown_v6: - description: - - "The inheritance configuration for I(allow_unknown_v6) field from I(DHCPConfig) object." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: bool - returned: Always - echo_client_id: - description: - - "The inheritance configuration for I(echo_client_id) field from I(DHCPConfig) object." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: bool - returned: Always - filters: - description: - - "The inheritance configuration for filters field from I(DHCPConfig) object." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The resource identifier." - type: list - returned: Always - filters_v6: - description: - - "The inheritance configuration for I(filters_v6) field from I(DHCPConfig) object." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The resource identifier." - type: list - returned: Always - ignore_client_uid: - description: - - "The inheritance configuration for I(ignore_client_uid) field from I(DHCPConfig) object." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: bool - returned: Always - ignore_list: - description: - - "The inheritance configuration for I(ignore_list) field from I(DHCPConfig) object." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: list - returned: Always - elements: dict - contains: - type: - description: - - "Type of ignore matching: client to ignore by client identifier (client hex or client text) or hardware to ignore by hardware identifier (MAC address). It can have one of the following values:" - - "* I(client_hex)," - - "* I(client_text)," - - "* I(hardware)." - type: str - returned: Always - value: - description: - - "Value to match." - type: str - returned: Always - lease_time: - description: - - "The inheritance configuration for I(lease_time) field from I(DHCPConfig) object." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: int - returned: Always - lease_time_v6: - description: - - "The inheritance configuration for I(lease_time_v6) field from I(DHCPConfig) object." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: int - returned: Always - dhcp_options: - description: - - "The inheritance configuration for I(dhcp_options) field." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(block): Don't use the inherited value." - - "Defaults to I(inherit)." - type: str - returned: Always - value: - description: - - "The inherited DHCP option values." - type: list - returned: Always - elements: dict - contains: - action: - description: - - "The inheritance setting." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(block): Don't use the inherited value." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value for the DHCP option." - type: dict - returned: Always - contains: - option: - description: - - "Option inherited from the ancestor." - type: dict - returned: Always - contains: - group: - description: - - "The resource identifier." - type: str - returned: Always - option_code: - description: - - "The resource identifier." - type: str - returned: Always - option_value: - description: - - "The option value." - type: str - returned: Always - type: - description: - - "The type of item." - - "Valid values are:" - - "* I(group)" - - "* I(option)" - type: str - returned: Always - overriding_group: - description: - - "The resource identifier." - type: str - returned: Always - header_option_filename: - description: - - "The inheritance configuration for I(header_option_filename) field." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: str - returned: Always - header_option_server_address: - description: - - "The inheritance configuration for I(header_option_server_address) field." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: str - returned: Always - header_option_server_name: - description: - - "The inheritance configuration for I(header_option_server_name) field." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting for a field." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: str - returned: Always - hostname_rewrite_block: - description: - - "The inheritance configuration for I(hostname_rewrite_enabled), I(hostname_rewrite_regex), and I(hostname_rewrite_char) fields." - type: dict - returned: Always - contains: - action: - description: - - "The inheritance setting." - - "Valid values are:" - - "* I(inherit): Use the inherited value." - - "* I(override): Use the value set in the object." - - "Defaults to I(inherit)." - type: str - returned: Always - display_name: - description: - - "The human-readable display name for the object referred to by I(source)." - type: str - returned: Always - source: - description: - - "The resource identifier." - type: str - returned: Always - value: - description: - - "The inherited value." - type: dict - returned: Always - contains: - hostname_rewrite_char: - description: - - "The inheritance configuration for I(hostname_rewrite_char) field." - type: str - returned: Always - hostname_rewrite_enabled: - description: - - "The inheritance configuration for I(hostname_rewrite_enabled) field." - type: bool - returned: Always - hostname_rewrite_regex: - description: - - "The inheritance configuration for I(hostname_rewrite_regex) field." - type: str - returned: Always - name: - description: - - "The name of the address block. May contain 1 to 256 characters. Can include UTF-8." - type: str - returned: Always - parent: - description: - - "The resource identifier." - type: str - returned: Always - protocol: - description: - - "The type of protocol of address block (I(ip4) or I(ip6))." - type: str - returned: Always - space: - description: - - "The resource identifier." - type: str - returned: Always - tags: - description: - - "The tags for the address block in JSON format." - type: dict - returned: Always - threshold: - description: - - "The IP address utilization thresholds for the address block." - type: dict - returned: Always - contains: - enabled: - description: - - "Indicates whether the utilization threshold for IP addresses is enabled or not." - type: bool - returned: Always - high: - description: - - "The high threshold value for the percentage of used IP addresses relative to the total IP addresses available in the scope of the object. Thresholds are inclusive in the comparison test." - type: int - returned: Always - low: - description: - - "The low threshold value for the percentage of used IP addresses relative to the total IP addresses available in the scope of the object. Thresholds are inclusive in the comparison test." - type: int - 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 - usage: - description: - - "The usage is a combination of indicators, each tracking a specific associated use. Listed below are usage indicators with their meaning: usage indicator | description ---------------------- | -------------------------------- I(IPAM) | AddressBlock is managed in BloxOne DDI. I(DISCOVERED) | AddressBlock is discovered by some network discovery probe like Network Insight or NetMRI in NIOS." - type: list - returned: Always - utilization: - description: - - "The IPV4 address utilization statistics for the address block." - type: dict - returned: Always - contains: - abandon_utilization: - description: - - "The percentage of abandoned IP addresses relative to the total IP addresses available in the scope of the object." - type: int - returned: Always - abandoned: - description: - - "The number of IP addresses in the scope of the object which are in the abandoned state (issued by a DHCP server and then declined by the client)." - type: str - returned: Always - dynamic: - description: - - "The number of IP addresses handed out by DHCP in the scope of the object. This includes all leased addresses, fixed addresses that are defined but not currently leased and abandoned leases." - type: str - returned: Always - free: - description: - - "The number of IP addresses available in the scope of the object." - type: str - returned: Always - static: - description: - - "The number of defined IP addresses such as reservations or DNS records. It can be computed as I(static) = I(used) - I(dynamic)." - type: str - returned: Always - total: - description: - - "The total number of IP addresses available in the scope of the object." - type: str - returned: Always - used: - description: - - "The number of IP addresses used in the scope of the object." - type: str - returned: Always - utilization: - description: - - "The percentage of used IP addresses relative to the total IP addresses available in the scope of the object." - type: int - returned: Always - utilization_v6: - description: - - "The utilization of IPV6 addresses in the Address block." - type: dict - returned: Always - contains: - abandoned: - description: "The number of IP addresses in the scope of the object which are in the abandoned state (issued by a DHCP server and then declined by the client)." - type: str - returned: Always - dynamic: - description: "The number of IP addresses handed out by DHCP in the scope of the object. This includes all leased addresses, fixed addresses that are defined but not currently leased and abandoned leases." - type: str - returned: Always - static: - description: "The number of defined IP addresses such as reservations or DNS records. It can be computed as _static_ = _used_ - _dynamic_." - type: str - returned: Always - total: - description: "The total number of IP addresses available in the scope of the object." - type: str - returned: Always - used: - description: "The number of IP addresses used in the scope of the object." - type: str - returned: Always -""" # noqa: E501 +""" from ansible_collections.infoblox.bloxone.plugins.module_utils.modules import BloxoneAnsibleModule @@ -1652,7 +112,9 @@ def run_command(self): all_results = [] for r in find_results: - all_results.append(r.model_dump(by_alias=True, exclude_none=True)) + # The expected output is a list of addresses as strings. + # Therefore, we extract only the 'address' field from each object in the results. + all_results.append(r.address) result["objects"] = all_results self.exit_json(**result) diff --git a/tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml b/tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml index a3cada49..92e4a06e 100644 --- a/tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml +++ b/tests/integration/targets/ipam_next_available_address_block_info/tasks/main.yml @@ -11,7 +11,7 @@ state: "present" register: address_block - - name: Get Next Available Address Block Information by ID + - name: Get Next Available Address Block Information by ID and default Count infoblox.bloxone.ipam_next_available_address_block_info: id: "{{ address_block.id }}" cidr: 20