1#!/usr/local/bin/python3.8 2# -*- coding: utf-8 -*- 3# Copyright (c) 2018 Red Hat, Inc. 4# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt) 5 6from __future__ import absolute_import, division, print_function 7__metaclass__ = type 8 9DOCUMENTATION = ''' 10--- 11module: nios_network 12author: "Peter Sprygada (@privateip)" 13short_description: Configure Infoblox NIOS network object 14deprecated: 15 why: Please install the infoblox.nios_modules collection and use the corresponding module from it. 16 alternative: infoblox.nios_modules.nios_network 17 removed_in: 5.0.0 18description: 19 - Adds and/or removes instances of network objects from 20 Infoblox NIOS servers. This module manages NIOS C(network) objects 21 using the Infoblox WAPI interface over REST. 22 - Supports both IPV4 and IPV6 internet protocols 23requirements: 24 - infoblox-client 25extends_documentation_fragment: 26- community.general.nios 27 28options: 29 network: 30 description: 31 - Specifies the network to add or remove from the system. The value 32 should use CIDR notation. 33 required: true 34 aliases: 35 - name 36 - cidr 37 type: str 38 network_view: 39 description: 40 - Configures the name of the network view to associate with this 41 configured instance. 42 default: default 43 type: str 44 options: 45 description: 46 - Configures the set of DHCP options to be included as part of 47 the configured network instance. This argument accepts a list 48 of values (see suboptions). When configuring suboptions at 49 least one of C(name) or C(num) must be specified. 50 type: list 51 elements: dict 52 suboptions: 53 name: 54 description: 55 - The name of the DHCP option to configure. The standard options are 56 C(router), C(router-templates), C(domain-name-servers), C(domain-name), 57 C(broadcast-address), C(broadcast-address-offset), C(dhcp-lease-time), 58 and C(dhcp6.name-servers). 59 type: str 60 num: 61 description: 62 - The number of the DHCP option to configure 63 type: int 64 value: 65 description: 66 - The value of the DHCP option specified by C(name) 67 required: true 68 type: str 69 use_option: 70 description: 71 - Only applies to a subset of options (see NIOS API documentation) 72 type: bool 73 default: 'yes' 74 vendor_class: 75 description: 76 - The name of the space this DHCP option is associated to 77 default: DHCP 78 type: str 79 extattrs: 80 description: 81 - Allows for the configuration of Extensible Attributes on the 82 instance of the object. This argument accepts a set of key / value 83 pairs for configuration. 84 type: dict 85 comment: 86 description: 87 - Configures a text string comment to be associated with the instance 88 of this object. The provided text string will be configured on the 89 object instance. 90 type: str 91 container: 92 description: 93 - If set to true it'll create the network container to be added or removed 94 from the system. 95 type: bool 96 state: 97 description: 98 - Configures the intended state of the instance of the object on 99 the NIOS server. When this value is set to C(present), the object 100 is configured on the device and when this value is set to C(absent) 101 the value is removed (if necessary) from the device. 102 default: present 103 choices: 104 - present 105 - absent 106 type: str 107''' 108 109EXAMPLES = ''' 110- name: Configure a network ipv4 111 community.general.nios_network: 112 network: 192.168.10.0/24 113 comment: this is a test comment 114 state: present 115 provider: 116 host: "{{ inventory_hostname_short }}" 117 username: admin 118 password: admin 119 connection: local 120- name: Configure a network ipv6 121 community.general.nios_network: 122 network: fe80::/64 123 comment: this is a test comment 124 state: present 125 provider: 126 host: "{{ inventory_hostname_short }}" 127 username: admin 128 password: admin 129 connection: local 130- name: Set dhcp options for a network ipv4 131 community.general.nios_network: 132 network: 192.168.10.0/24 133 comment: this is a test comment 134 options: 135 - name: domain-name 136 value: ansible.com 137 state: present 138 provider: 139 host: "{{ inventory_hostname_short }}" 140 username: admin 141 password: admin 142 connection: local 143- name: Remove a network ipv4 144 community.general.nios_network: 145 network: 192.168.10.0/24 146 state: absent 147 provider: 148 host: "{{ inventory_hostname_short }}" 149 username: admin 150 password: admin 151 connection: local 152- name: Configure a ipv4 network container 153 community.general.nios_network: 154 network: 192.168.10.0/24 155 container: true 156 comment: test network container 157 state: present 158 provider: 159 host: "{{ inventory_hostname_short }}" 160 username: admin 161 password: admin 162 connection: local 163- name: Configure a ipv6 network container 164 community.general.nios_network: 165 network: fe80::/64 166 container: true 167 comment: test network container 168 state: present 169 provider: 170 host: "{{ inventory_hostname_short }}" 171 username: admin 172 password: admin 173 connection: local 174- name: Remove a ipv4 network container 175 community.general.nios_network: 176 networkr: 192.168.10.0/24 177 container: true 178 comment: test network container 179 state: absent 180 provider: 181 host: "{{ inventory_hostname_short }}" 182 username: admin 183 password: admin 184 connection: local 185''' 186 187RETURN = ''' # ''' 188 189import socket 190 191from ansible.module_utils.basic import AnsibleModule 192from ansible.module_utils.six import iteritems 193from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import WapiModule 194from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import NIOS_IPV4_NETWORK, NIOS_IPV6_NETWORK 195from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import NIOS_IPV4_NETWORK_CONTAINER, NIOS_IPV6_NETWORK_CONTAINER 196from ansible_collections.community.general.plugins.module_utils.net_tools.nios.api import normalize_ib_spec 197 198 199# The following function validate_ip_address has been taken from 200# https://github.com/ansible-collections/ansible.netcommon/blob/20124ecbb420daa0f5bb9cdaa865a952657aa0e7/plugins/module_utils/network/common/utils.py#L496 201# The code there is licensed under BSD 2-clause. 202# Copyright (c) 2016 Red Hat Inc. 203def validate_ip_address(address): 204 try: 205 socket.inet_aton(address) 206 except socket.error: 207 return False 208 return address.count(".") == 3 209 210 211# The following function validate_ip_v6_address has been taken from 212# https://github.com/ansible-collections/ansible.netcommon/blob/20124ecbb420daa0f5bb9cdaa865a952657aa0e7/plugins/module_utils/network/common/utils.py#L504 213# The code there is licensed under BSD 2-clause. 214# Copyright (c) 2016 Red Hat Inc. 215def validate_ip_v6_address(address): 216 try: 217 socket.inet_pton(socket.AF_INET6, address) 218 except socket.error: 219 return False 220 return True 221 222 223def options(module): 224 ''' Transforms the module argument into a valid WAPI struct 225 This function will transform the options argument into a structure that 226 is a valid WAPI structure in the format of: 227 { 228 name: <value>, 229 num: <value>, 230 value: <value>, 231 use_option: <value>, 232 vendor_class: <value> 233 } 234 It will remove any options that are set to None since WAPI will error on 235 that condition. It will also verify that either `name` or `num` is 236 set in the structure but does not validate the values are equal. 237 The remainder of the value validation is performed by WAPI 238 ''' 239 options = list() 240 for item in module.params['options']: 241 opt = dict([(k, v) for k, v in iteritems(item) if v is not None]) 242 if 'name' not in opt and 'num' not in opt: 243 module.fail_json(msg='one of `name` or `num` is required for option value') 244 options.append(opt) 245 return options 246 247 248def check_ip_addr_type(obj_filter, ib_spec): 249 '''This function will check if the argument ip is type v4/v6 and return appropriate infoblox 250 network/networkcontainer type 251 ''' 252 253 ip = obj_filter['network'] 254 if 'container' in obj_filter and obj_filter['container']: 255 check_ip = ip.split('/') 256 del ib_spec['container'] # removing the container key from post arguments 257 del ib_spec['options'] # removing option argument as for network container it's not supported 258 if validate_ip_address(check_ip[0]): 259 return NIOS_IPV4_NETWORK_CONTAINER, ib_spec 260 elif validate_ip_v6_address(check_ip[0]): 261 return NIOS_IPV6_NETWORK_CONTAINER, ib_spec 262 else: 263 check_ip = ip.split('/') 264 del ib_spec['container'] # removing the container key from post arguments 265 if validate_ip_address(check_ip[0]): 266 return NIOS_IPV4_NETWORK, ib_spec 267 elif validate_ip_v6_address(check_ip[0]): 268 return NIOS_IPV6_NETWORK, ib_spec 269 270 271def check_vendor_specific_dhcp_option(module, ib_spec): 272 '''This function will check if the argument dhcp option belongs to vendor-specific and if yes then will remove 273 use_options flag which is not supported with vendor-specific dhcp options. 274 ''' 275 for key, value in iteritems(ib_spec): 276 if isinstance(module.params[key], list): 277 temp_dict = module.params[key][0] 278 if 'num' in temp_dict: 279 if temp_dict['num'] in (43, 124, 125): 280 del module.params[key][0]['use_option'] 281 return ib_spec 282 283 284def main(): 285 ''' Main entry point for module execution 286 ''' 287 option_spec = dict( 288 # one of name or num is required; enforced by the function options() 289 name=dict(), 290 num=dict(type='int'), 291 292 value=dict(required=True), 293 294 use_option=dict(type='bool', default=True), 295 vendor_class=dict(default='DHCP') 296 ) 297 298 ib_spec = dict( 299 network=dict(required=True, aliases=['name', 'cidr'], ib_req=True), 300 network_view=dict(default='default', ib_req=True), 301 302 options=dict(type='list', elements='dict', options=option_spec, transform=options), 303 304 extattrs=dict(type='dict'), 305 comment=dict(), 306 container=dict(type='bool', ib_req=True) 307 ) 308 309 argument_spec = dict( 310 provider=dict(required=True), 311 state=dict(default='present', choices=['present', 'absent']) 312 ) 313 314 argument_spec.update(normalize_ib_spec(ib_spec)) 315 argument_spec.update(WapiModule.provider_spec) 316 317 module = AnsibleModule(argument_spec=argument_spec, 318 supports_check_mode=True) 319 320 # to get the argument ipaddr 321 obj_filter = dict([(k, module.params[k]) for k, v in iteritems(ib_spec) if v.get('ib_req')]) 322 network_type, ib_spec = check_ip_addr_type(obj_filter, ib_spec) 323 324 wapi = WapiModule(module) 325 # to check for vendor specific dhcp option 326 ib_spec = check_vendor_specific_dhcp_option(module, ib_spec) 327 328 result = wapi.run(network_type, ib_spec) 329 330 module.exit_json(**result) 331 332 333if __name__ == '__main__': 334 main() 335