diff --git a/lib/ansible/modules/network/f5/bigip_selfip.py b/lib/ansible/modules/network/f5/bigip_selfip.py index 3ee54eef01..744745585f 100644 --- a/lib/ansible/modules/network/f5/bigip_selfip.py +++ b/lib/ansible/modules/network/f5/bigip_selfip.py @@ -18,7 +18,7 @@ module: bigip_selfip short_description: Manage Self-IPs on a BIG-IP system description: - Manage Self-IPs on a BIG-IP system. -version_added: "2.2" +version_added: 2.2 options: address: description: @@ -190,27 +190,27 @@ allow_service: sample: ['igmp:0','tcp:22','udp:53'] address: description: The address for the Self IP - returned: created + returned: changed type: string sample: 192.0.2.10 name: description: The name of the Self IP - returned: created, changed and deleted + returned: created type: string sample: self1 netmask: description: The netmask of the Self IP - returned: changed and created + returned: changed type: string sample: 255.255.255.0 traffic_group: description: The traffic group that the Self IP is a member of - returned: changed and created + returned: changed type: string sample: traffic-group-local-only vlan: description: The VLAN set on the Self IP - returned: changed and created + returned: changed type: string sample: vlan1 ''' @@ -220,30 +220,25 @@ import re from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import env_fallback -HAS_DEVEL_IMPORTS = False - try: - # Sideband repository used for dev from library.module_utils.network.f5.bigip import HAS_F5SDK from library.module_utils.network.f5.bigip import F5Client from library.module_utils.network.f5.common import F5ModuleError from library.module_utils.network.f5.common import AnsibleF5Parameters from library.module_utils.network.f5.common import cleanup_tokens - from library.module_utils.network.f5.common import fqdn_name + from library.module_utils.network.f5.common import fq_name from library.module_utils.network.f5.common import f5_argument_spec try: from library.module_utils.network.f5.common import iControlUnexpectedHTTPError except ImportError: HAS_F5SDK = False - HAS_DEVEL_IMPORTS = True except ImportError: - # Upstream Ansible from ansible.module_utils.network.f5.bigip import HAS_F5SDK from ansible.module_utils.network.f5.bigip import F5Client from ansible.module_utils.network.f5.common import F5ModuleError from ansible.module_utils.network.f5.common import AnsibleF5Parameters from ansible.module_utils.network.f5.common import cleanup_tokens - from ansible.module_utils.network.f5.common import fqdn_name + from ansible.module_utils.network.f5.common import fq_name from ansible.module_utils.network.f5.common import f5_argument_spec try: from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError @@ -282,16 +277,11 @@ class Parameters(AnsibleF5Parameters): result = self._filter_params(result) return result - def _fqdn_name(self, value): - if value is not None and not value.startswith('/'): - return '/{0}/{1}'.format(self.partition, value) - return value - @property def vlan(self): if self._values['vlan'] is None: return None - return self._fqdn_name(self._values['vlan']) + return fq_name(self.partition, self._values['vlan']) class ModuleParameters(Parameters): @@ -318,7 +308,7 @@ class ModuleParameters(Parameters): def traffic_group(self): if self._values['traffic_group'] is None: return None - return self._fqdn_name(self._values['traffic_group']) + return fq_name(self.partition, self._values['traffic_group']) @property def route_domain(self): diff --git a/lib/ansible/modules/network/f5/bigip_snat_pool.py b/lib/ansible/modules/network/f5/bigip_snat_pool.py index e276e97809..9fb2c46fb2 100644 --- a/lib/ansible/modules/network/f5/bigip_snat_pool.py +++ b/lib/ansible/modules/network/f5/bigip_snat_pool.py @@ -18,7 +18,7 @@ module: bigip_snat_pool short_description: Manage SNAT pools on a BIG-IP description: - Manage SNAT pools on a BIG-IP. -version_added: "2.3" +version_added: 2.3 options: members: description: @@ -96,30 +96,23 @@ import os from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import env_fallback -HAS_DEVEL_IMPORTS = False - try: - # Sideband repository used for dev from library.module_utils.network.f5.bigip import HAS_F5SDK from library.module_utils.network.f5.bigip import F5Client from library.module_utils.network.f5.common import F5ModuleError from library.module_utils.network.f5.common import AnsibleF5Parameters from library.module_utils.network.f5.common import cleanup_tokens - from library.module_utils.network.f5.common import fqdn_name from library.module_utils.network.f5.common import f5_argument_spec try: from library.module_utils.network.f5.common import iControlUnexpectedHTTPError except ImportError: HAS_F5SDK = False - HAS_DEVEL_IMPORTS = True except ImportError: - # Upstream Ansible from ansible.module_utils.network.f5.bigip import HAS_F5SDK from ansible.module_utils.network.f5.bigip import F5Client from ansible.module_utils.network.f5.common import F5ModuleError from ansible.module_utils.network.f5.common import AnsibleF5Parameters from ansible.module_utils.network.f5.common import cleanup_tokens - from ansible.module_utils.network.f5.common import fqdn_name from ansible.module_utils.network.f5.common import f5_argument_spec try: from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError diff --git a/lib/ansible/modules/network/f5/bigip_snmp.py b/lib/ansible/modules/network/f5/bigip_snmp.py index df877aff40..c046e47e28 100644 --- a/lib/ansible/modules/network/f5/bigip_snmp.py +++ b/lib/ansible/modules/network/f5/bigip_snmp.py @@ -19,6 +19,16 @@ description: - Manipulate general SNMP settings on a BIG-IP. version_added: 2.4 options: + allowed_addresses: + description: + - Configures the IP addresses of the SNMP clients from which the snmpd + daemon accepts requests. + - This value can be hostnames, IP addresses, or IP networks. + - You may specify a single list item of C(default) to set the value back + to the system's default of C(127.0.0.0/8). + - You can remove all allowed addresses by either providing the word C(none), or + by providing the empty string C(""). + version_added: 2.6 contact: description: - Specifies the name of the person who administers the SNMP @@ -51,6 +61,11 @@ options: description: - Specifies the description of this system's physical location. extends_documentation_fragment: f5 +notes: + - Requires the netaddr Python package on the host. This is as easy as + C(pip install netaddr). +requirements: + - netaddr author: - Tim Rupp (@caphrim007) ''' @@ -101,40 +116,49 @@ location: returned: changed type: string sample: US West 1a +allowed_addresses: + description: The new allowed addresses for SNMP client connections. + returned: changed + type: list + sample: ['127.0.0.0/8', 'foo.bar.com', '10.10.10.10'] ''' from ansible.module_utils.basic import AnsibleModule - -HAS_DEVEL_IMPORTS = False +from ansible.module_utils.six import string_types try: - # Sideband repository used for dev from library.module_utils.network.f5.bigip import HAS_F5SDK from library.module_utils.network.f5.bigip import F5Client from library.module_utils.network.f5.common import F5ModuleError from library.module_utils.network.f5.common import AnsibleF5Parameters from library.module_utils.network.f5.common import cleanup_tokens - from library.module_utils.network.f5.common import fqdn_name + from library.module_utils.network.f5.common import is_valid_hostname from library.module_utils.network.f5.common import f5_argument_spec + try: from library.module_utils.network.f5.common import iControlUnexpectedHTTPError except ImportError: HAS_F5SDK = False - HAS_DEVEL_IMPORTS = True except ImportError: - # Upstream Ansible from ansible.module_utils.network.f5.bigip import HAS_F5SDK from ansible.module_utils.network.f5.bigip import F5Client from ansible.module_utils.network.f5.common import F5ModuleError from ansible.module_utils.network.f5.common import AnsibleF5Parameters from ansible.module_utils.network.f5.common import cleanup_tokens - from ansible.module_utils.network.f5.common import fqdn_name + from ansible.module_utils.network.f5.common import is_valid_hostname from ansible.module_utils.network.f5.common import f5_argument_spec + try: from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError except ImportError: HAS_F5SDK = False +try: + import netaddr + HAS_NETADDR = True +except ImportError: + HAS_NETADDR = False + class Parameters(AnsibleF5Parameters): api_map = { @@ -142,21 +166,23 @@ class Parameters(AnsibleF5Parameters): 'authTrap': 'agent_authentication_traps', 'bigipTraps': 'device_warning_traps', 'sysLocation': 'location', - 'sysContact': 'contact' + 'sysContact': 'contact', + 'allowedAddresses': 'allowed_addresses' } updatables = [ 'agent_status_traps', 'agent_authentication_traps', - 'device_warning_traps', 'location', 'contact' + 'device_warning_traps', 'location', 'contact', 'allowed_addresses' ] returnables = [ 'agent_status_traps', 'agent_authentication_traps', - 'device_warning_traps', 'location', 'contact' + 'device_warning_traps', 'location', 'contact', 'allowed_addresses' ] api_attributes = [ - 'agentTrap', 'authTrap', 'bigipTraps', 'sysLocation', 'sysContact' + 'agentTrap', 'authTrap', 'bigipTraps', 'sysLocation', 'sysContact', + 'allowedAddresses' ] def to_return(self): @@ -167,28 +193,121 @@ class Parameters(AnsibleF5Parameters): return result +class ApiParameters(Parameters): + @property + def allowed_addresses(self): + if self._values['allowed_addresses'] is None: + return None + result = list(set(self._values['allowed_addresses'])) + result.sort() + return result + + +class ModuleParameters(Parameters): + @property + def allowed_addresses(self): + if self._values['allowed_addresses'] is None: + return None + result = [] + addresses = self._values['allowed_addresses'] + if isinstance(addresses, string_types): + if addresses in ['', 'none']: + return [] + else: + addresses = [addresses] + if len(addresses) == 1 and addresses[0] in ['default', '']: + result = ['127.0.0.0/8'] + return result + for address in addresses: + try: + # Check for valid IPv4 or IPv6 entries + netaddr.IPNetwork(address) + result.append(address) + except netaddr.core.AddrFormatError: + # else fallback to checking reasonably well formatted hostnames + if is_valid_hostname(address): + result.append(str(address)) + continue + raise F5ModuleError( + "The provided 'allowed_address' value {0} is not a valid IP or hostname".format(address) + ) + result = list(set(result)) + result.sort() + return result + + class Changes(Parameters): pass +class UsableChanges(Changes): + pass + + +class ReportableChanges(Changes): + pass + + +class Difference(object): + def __init__(self, want, have=None): + self.want = want + self.have = have + + def compare(self, param): + try: + result = getattr(self, param) + return result + except AttributeError: + return self.__default(param) + + def __default(self, param): + attr1 = getattr(self.want, param) + try: + attr2 = getattr(self.have, param) + if attr1 != attr2: + return attr1 + except AttributeError: + return attr1 + + @property + def allowed_addresses(self): + if self.want.allowed_addresses is None: + return None + if self.have.allowed_addresses is None: + if self.want.allowed_addresses: + return self.want.allowed_addresses + return None + want = set(self.want.allowed_addresses) + have = set(self.have.allowed_addresses) + if want != have: + result = list(want) + result.sort() + return result + + class ModuleManager(object): def __init__(self, *args, **kwargs): self.module = kwargs.get('module', None) self.client = kwargs.get('client', None) - self.have = None - self.want = Parameters(params=self.module.params) - self.changes = Changes() + self.have = ApiParameters() + self.want = ModuleParameters(params=self.module.params) + self.changes = UsableChanges() def _update_changed_options(self): - changed = {} - for key in Parameters.updatables: - if getattr(self.want, key) is not None: - attr1 = getattr(self.want, key) - attr2 = getattr(self.have, key) - if attr1 != attr2: - changed[key] = attr1 + diff = Difference(self.want, self.have) + updatables = Parameters.updatables + changed = dict() + for k in updatables: + change = diff.compare(k) + if change is None: + continue + else: + if isinstance(change, dict): + changed.update(change) + else: + changed[k] = change if changed: - self.changes = Changes(params=changed) + self.changes = UsableChanges(params=changed) return True return False @@ -200,11 +319,21 @@ class ModuleManager(object): except iControlUnexpectedHTTPError as e: raise F5ModuleError(str(e)) - changes = self.changes.to_return() + reportable = ReportableChanges(params=self.changes.to_return()) + changes = reportable.to_return() result.update(**changes) result.update(dict(changed=changed)) + self._announce_deprecations(result) return result + def _announce_deprecations(self, result): + warnings = result.pop('__warnings', []) + for warning in warnings: + self.module.deprecate( + msg=warning['msg'], + version=warning['version'] + ) + def should_update(self): result = self._update_changed_options() if result: @@ -228,7 +357,7 @@ class ModuleManager(object): def read_current_from_device(self): resource = self.client.api.tm.sys.snmp.load() result = resource.attrs - return Parameters(params=result) + return ApiParameters(params=result) class ArgumentSpec(object): @@ -246,7 +375,8 @@ class ArgumentSpec(object): device_warning_traps=dict( choices=self.choices ), - location=dict() + location=dict(), + allowed_addresses=dict(type='raw') ) self.argument_spec = {} self.argument_spec.update(f5_argument_spec) @@ -262,6 +392,8 @@ def main(): ) if not HAS_F5SDK: module.fail_json(msg="The python f5-sdk module is required") + if not HAS_NETADDR: + module.fail_json(msg="The python netaddr module is required") try: client = F5Client(**module.params) diff --git a/lib/ansible/modules/network/f5/bigip_snmp_trap.py b/lib/ansible/modules/network/f5/bigip_snmp_trap.py index 1c683cb792..2fda7b697c 100644 --- a/lib/ansible/modules/network/f5/bigip_snmp_trap.py +++ b/lib/ansible/modules/network/f5/bigip_snmp_trap.py @@ -27,9 +27,7 @@ options: description: - Specifies to which Simple Network Management Protocol (SNMP) version the trap destination applies. - choices: - - 1 - - 2c + choices: ['1', '2c'] community: description: - Specifies the community name for the trap destination. @@ -45,14 +43,18 @@ options: - Specifies the name of the trap network. This option is not supported in versions of BIG-IP < 12.1.0. If used on versions < 12.1.0, it will simply be ignored. + - The value C(default) was removed in BIG-IP version 13.1.0. Specifying this + value when configuring a BIG-IP will cause the module to stop and report + an error. The usual remedy is to choose one of the other options, such as + C(management). choices: - other - management - default state: description: - - When C(present), ensures that the cloud connector exists. When - C(absent), ensures that the cloud connector does not exist. + - When C(present), ensures that the resource exists. + - When C(absent), ensures that the resource does not exist. default: present choices: - present @@ -132,30 +134,23 @@ from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import env_fallback from distutils.version import LooseVersion -HAS_DEVEL_IMPORTS = False - try: - # Sideband repository used for dev from library.module_utils.network.f5.bigip import HAS_F5SDK from library.module_utils.network.f5.bigip import F5Client from library.module_utils.network.f5.common import F5ModuleError from library.module_utils.network.f5.common import AnsibleF5Parameters from library.module_utils.network.f5.common import cleanup_tokens - from library.module_utils.network.f5.common import fqdn_name from library.module_utils.network.f5.common import f5_argument_spec try: from library.module_utils.network.f5.common import iControlUnexpectedHTTPError except ImportError: HAS_F5SDK = False - HAS_DEVEL_IMPORTS = True except ImportError: - # Upstream Ansible from ansible.module_utils.network.f5.bigip import HAS_F5SDK from ansible.module_utils.network.f5.bigip import F5Client from ansible.module_utils.network.f5.common import F5ModuleError from ansible.module_utils.network.f5.common import AnsibleF5Parameters from ansible.module_utils.network.f5.common import cleanup_tokens - from ansible.module_utils.network.f5.common import fqdn_name from ansible.module_utils.network.f5.common import f5_argument_spec try: from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError @@ -190,7 +185,36 @@ class Parameters(AnsibleF5Parameters): return result -class NetworkedParameters(Parameters): +class V3Parameters(Parameters): + updatables = [ + 'snmp_version', 'community', 'destination', 'port', 'network' + ] + + returnables = [ + 'snmp_version', 'community', 'destination', 'port', 'network' + ] + + api_attributes = [ + 'version', 'community', 'host', 'port', 'network' + ] + + @property + def network(self): + if self._values['network'] is None: + return None + network = str(self._values['network']) + if network == 'management': + return 'mgmt' + elif network == 'default': + raise F5ModuleError( + "'default' is not a valid option for this version of BIG-IP. " + "Use either 'management', 'or 'other' instead." + ) + else: + return network + + +class V2Parameters(Parameters): updatables = [ 'snmp_version', 'community', 'destination', 'port', 'network' ] @@ -216,7 +240,7 @@ class NetworkedParameters(Parameters): return network -class NonNetworkedParameters(Parameters): +class V1Parameters(Parameters): updatables = [ 'snmp_version', 'community', 'destination', 'port' ] @@ -241,20 +265,20 @@ class ModuleManager(object): self.kwargs = kwargs def exec_module(self): - if self.is_version_non_networked(): - manager = NonNetworkedManager(**self.kwargs) + if self.is_version_without_network(): + manager = V1Manager(**self.kwargs) + elif self.is_version_with_default_network(): + manager = V2Manager(**self.kwargs) else: - manager = NetworkedManager(**self.kwargs) + manager = V3Manager(**self.kwargs) return manager.exec_module() - def is_version_non_networked(self): - """Checks to see if the TMOS version is less than 13 + def is_version_without_network(self): + """Is current BIG-IP version missing "network" value support - Anything less than BIG-IP 13.x does not support users - on different partitions. - - :return: Bool + Returns: + bool: True when it is missing. False otherwise. """ version = self.client.api.tmos_version if LooseVersion(version) < LooseVersion('12.1.0'): @@ -262,6 +286,18 @@ class ModuleManager(object): else: return False + def is_version_with_default_network(self): + """Is current BIG-IP version missing "default" network value support + + Returns: + bool: True when it is missing. False otherwise. + """ + version = self.client.api.tmos_version + if LooseVersion(version) < LooseVersion('13.1.0'): + return True + else: + return False + class BaseManager(object): def __init__(self, *args, **kwargs): @@ -365,33 +401,72 @@ class BaseManager(object): result.delete() -class NetworkedManager(BaseManager): +class V3Manager(BaseManager): def __init__(self, *args, **kwargs): - super(NetworkedManager, self).__init__(**kwargs) + super(V3Manager, self).__init__(**kwargs) self.required_resources = [ 'version', 'community', 'destination', 'port', 'network' ] - self.want = NetworkedParameters(params=self.module.params) - self.changes = NetworkedParameters() + self.want = V3Parameters(params=self.module.params) + self.changes = V3Parameters() def _set_changed_options(self): changed = {} - for key in NetworkedParameters.returnables: + for key in V3Parameters.returnables: if getattr(self.want, key) is not None: changed[key] = getattr(self.want, key) if changed: - self.changes = NetworkedParameters(params=changed) + self.changes = V3Parameters(params=changed) def _update_changed_options(self): changed = {} - for key in NetworkedParameters.updatables: + for key in V3Parameters.updatables: if getattr(self.want, key) is not None: attr1 = getattr(self.want, key) attr2 = getattr(self.have, key) if attr1 != attr2: changed[key] = attr1 if changed: - self.changes = NetworkedParameters(params=changed) + self.changes = V3Parameters(params=changed) + return True + return False + + def read_current_from_device(self): + resource = self.client.api.tm.sys.snmp.traps_s.trap.load( + name=self.want.name, + partition=self.want.partition + ) + result = resource.attrs + return V3Parameters(params=result) + + +class V2Manager(BaseManager): + def __init__(self, *args, **kwargs): + super(V2Manager, self).__init__(**kwargs) + self.required_resources = [ + 'version', 'community', 'destination', 'port', 'network' + ] + self.want = V2Parameters(params=self.module.params) + self.changes = V2Parameters() + + def _set_changed_options(self): + changed = {} + for key in V2Parameters.returnables: + if getattr(self.want, key) is not None: + changed[key] = getattr(self.want, key) + if changed: + self.changes = V2Parameters(params=changed) + + def _update_changed_options(self): + changed = {} + for key in V2Parameters.updatables: + if getattr(self.want, key) is not None: + attr1 = getattr(self.want, key) + attr2 = getattr(self.have, key) + if attr1 != attr2: + changed[key] = attr1 + if changed: + self.changes = V2Parameters(params=changed) return True return False @@ -402,7 +477,7 @@ class NetworkedManager(BaseManager): ) result = resource.attrs self._ensure_network(result) - return NetworkedParameters(params=result) + return V2Parameters(params=result) def _ensure_network(self, result): # BIG-IP's value for "default" is that the key does not @@ -415,33 +490,33 @@ class NetworkedManager(BaseManager): result['network'] = 'default' -class NonNetworkedManager(BaseManager): +class V1Manager(BaseManager): def __init__(self, *args, **kwargs): - super(NonNetworkedManager, self).__init__(**kwargs) + super(V1Manager, self).__init__(**kwargs) self.required_resources = [ 'version', 'community', 'destination', 'port' ] - self.want = NonNetworkedParameters(params=self.module.params) - self.changes = NonNetworkedParameters() + self.want = V1Parameters(params=self.module.params) + self.changes = V1Parameters() def _set_changed_options(self): changed = {} - for key in NonNetworkedParameters.returnables: + for key in V1Parameters.returnables: if getattr(self.want, key) is not None: changed[key] = getattr(self.want, key) if changed: - self.changes = NonNetworkedParameters(params=changed) + self.changes = V1Parameters(params=changed) def _update_changed_options(self): changed = {} - for key in NonNetworkedParameters.updatables: + for key in V1Parameters.updatables: if getattr(self.want, key) is not None: attr1 = getattr(self.want, key) attr2 = getattr(self.have, key) if attr1 != attr2: changed[key] = attr1 if changed: - self.changes = NonNetworkedParameters(params=changed) + self.changes = V1Parameters(params=changed) return True return False @@ -451,7 +526,7 @@ class NonNetworkedManager(BaseManager): partition=self.want.partition ) result = resource.attrs - return NonNetworkedParameters(params=result) + return V1Parameters(params=result) class ArgumentSpec(object): @@ -464,7 +539,7 @@ class ArgumentSpec(object): snmp_version=dict( choices=['1', '2c'] ), - community=dict(), + community=dict(no_log=True), destination=dict(), port=dict(), network=dict( diff --git a/test/units/modules/network/f5/test_bigip_selfip.py b/test/units/modules/network/f5/test_bigip_selfip.py index d0256ea161..651fa13e3b 100644 --- a/test/units/modules/network/f5/test_bigip_selfip.py +++ b/test/units/modules/network/f5/test_bigip_selfip.py @@ -21,10 +21,10 @@ from ansible.compat.tests.mock import patch from ansible.module_utils.basic import AnsibleModule try: - from library.bigip_selfip import ApiParameters - from library.bigip_selfip import ModuleParameters - from library.bigip_selfip import ModuleManager - from library.bigip_selfip import ArgumentSpec + from library.modules.bigip_selfip import ApiParameters + from library.modules.bigip_selfip import ModuleParameters + from library.modules.bigip_selfip import ModuleManager + from library.modules.bigip_selfip import ArgumentSpec from library.module_utils.network.f5.common import F5ModuleError from library.module_utils.network.f5.common import iControlUnexpectedHTTPError from test.unit.modules.utils import set_module_args diff --git a/test/units/modules/network/f5/test_bigip_snat_pool.py b/test/units/modules/network/f5/test_bigip_snat_pool.py index d8f877b0b9..c254072781 100644 --- a/test/units/modules/network/f5/test_bigip_snat_pool.py +++ b/test/units/modules/network/f5/test_bigip_snat_pool.py @@ -20,9 +20,9 @@ from ansible.compat.tests.mock import patch from ansible.module_utils.basic import AnsibleModule try: - from library.bigip_snat_pool import Parameters - from library.bigip_snat_pool import ModuleManager - from library.bigip_snat_pool import ArgumentSpec + from library.modules.bigip_snat_pool import Parameters + from library.modules.bigip_snat_pool import ModuleManager + from library.modules.bigip_snat_pool import ArgumentSpec from library.module_utils.network.f5.common import F5ModuleError from library.module_utils.network.f5.common import iControlUnexpectedHTTPError from test.unit.modules.utils import set_module_args diff --git a/test/units/modules/network/f5/test_bigip_snmp.py b/test/units/modules/network/f5/test_bigip_snmp.py index d5aef44b4b..16277c379d 100644 --- a/test/units/modules/network/f5/test_bigip_snmp.py +++ b/test/units/modules/network/f5/test_bigip_snmp.py @@ -20,15 +20,17 @@ from ansible.compat.tests.mock import patch from ansible.module_utils.basic import AnsibleModule try: - from library.bigip_snmp import Parameters - from library.bigip_snmp import ModuleManager - from library.bigip_snmp import ArgumentSpec + from library.modules.bigip_snmp import ApiParameters + from library.modules.bigip_snmp import ModuleParameters + from library.modules.bigip_snmp import ModuleManager + from library.modules.bigip_snmp import ArgumentSpec from library.module_utils.network.f5.common import F5ModuleError from library.module_utils.network.f5.common import iControlUnexpectedHTTPError from test.unit.modules.utils import set_module_args except ImportError: try: - from ansible.modules.network.f5.bigip_snmp import Parameters + from ansible.modules.network.f5.bigip_snmp import ApiParameters + from ansible.modules.network.f5.bigip_snmp import ModuleParameters from ansible.modules.network.f5.bigip_snmp import ModuleManager from ansible.modules.network.f5.bigip_snmp import ArgumentSpec from ansible.module_utils.network.f5.common import F5ModuleError @@ -71,7 +73,7 @@ class TestParameters(unittest.TestCase): server='localhost', user='admin' ) - p = Parameters(params=args) + p = ModuleParameters(params=args) assert p.agent_status_traps == 'enabled' assert p.agent_authentication_traps == 'enabled' assert p.device_warning_traps == 'enabled' @@ -87,7 +89,7 @@ class TestParameters(unittest.TestCase): server='localhost', user='admin' ) - p = Parameters(params=args) + p = ModuleParameters(params=args) assert p.agent_status_traps == 'disabled' assert p.agent_authentication_traps == 'disabled' assert p.device_warning_traps == 'disabled' @@ -100,7 +102,7 @@ class TestParameters(unittest.TestCase): sysLocation='Lunar orbit', sysContact='Alice@foo.org', ) - p = Parameters(params=args) + p = ApiParameters(params=args) assert p.agent_status_traps == 'enabled' assert p.agent_authentication_traps == 'enabled' assert p.device_warning_traps == 'enabled' @@ -113,7 +115,7 @@ class TestParameters(unittest.TestCase): authTrap='disabled', bigipTraps='disabled', ) - p = Parameters(params=args) + p = ApiParameters(params=args) assert p.agent_status_traps == 'disabled' assert p.agent_authentication_traps == 'disabled' assert p.device_warning_traps == 'disabled' @@ -134,7 +136,7 @@ class TestManager(unittest.TestCase): # Configure the parameters that would be returned by querying the # remote device - current = Parameters( + current = ApiParameters( params=dict( agent_status_traps='disabled' ) @@ -154,3 +156,108 @@ class TestManager(unittest.TestCase): assert results['changed'] is True assert results['agent_status_traps'] == 'enabled' + + def test_update_allowed_addresses(self, *args): + set_module_args(dict( + allowed_addresses=[ + '127.0.0.0/8', + '10.10.10.10', + 'foo', + 'baz.foo.com' + ], + password='passsword', + server='localhost', + user='admin' + )) + + # Configure the parameters that would be returned by querying the + # remote device + current = ApiParameters( + params=dict( + allowed_addresses=['127.0.0.0/8'] + ) + ) + + module = AnsibleModule( + argument_spec=self.spec.argument_spec, + supports_check_mode=self.spec.supports_check_mode + ) + mm = ModuleManager(module=module) + + # Override methods to force specific logic in the module to happen + mm.update_on_device = Mock(return_value=True) + mm.read_current_from_device = Mock(return_value=current) + + results = mm.exec_module() + + assert results['changed'] is True + assert len(results['allowed_addresses']) == 4 + assert results['allowed_addresses'] == [ + '10.10.10.10', '127.0.0.0/8', 'baz.foo.com', 'foo' + ] + + def test_update_allowed_addresses_default(self, *args): + set_module_args(dict( + allowed_addresses=[ + 'default' + ], + password='passsword', + server='localhost', + user='admin' + )) + + # Configure the parameters that would be returned by querying the + # remote device + current = ApiParameters( + params=dict( + allowed_addresses=['10.0.0.0'] + ) + ) + + module = AnsibleModule( + argument_spec=self.spec.argument_spec, + supports_check_mode=self.spec.supports_check_mode + ) + mm = ModuleManager(module=module) + + # Override methods to force specific logic in the module to happen + mm.update_on_device = Mock(return_value=True) + mm.read_current_from_device = Mock(return_value=current) + + results = mm.exec_module() + + assert results['changed'] is True + assert len(results['allowed_addresses']) == 1 + assert results['allowed_addresses'] == ['127.0.0.0/8'] + + def test_update_allowed_addresses_empty(self, *args): + set_module_args(dict( + allowed_addresses=[''], + password='passsword', + server='localhost', + user='admin' + )) + + # Configure the parameters that would be returned by querying the + # remote device + current = ApiParameters( + params=dict( + allowed_addresses=['10.0.0.0'] + ) + ) + + module = AnsibleModule( + argument_spec=self.spec.argument_spec, + supports_check_mode=self.spec.supports_check_mode + ) + mm = ModuleManager(module=module) + + # Override methods to force specific logic in the module to happen + mm.update_on_device = Mock(return_value=True) + mm.read_current_from_device = Mock(return_value=current) + + results = mm.exec_module() + + assert results['changed'] is True + assert len(results['allowed_addresses']) == 1 + assert results['allowed_addresses'] == ['127.0.0.0/8'] diff --git a/test/units/modules/network/f5/test_bigip_snmp_trap.py b/test/units/modules/network/f5/test_bigip_snmp_trap.py index 3948d94443..eb34e95121 100644 --- a/test/units/modules/network/f5/test_bigip_snmp_trap.py +++ b/test/units/modules/network/f5/test_bigip_snmp_trap.py @@ -21,22 +21,22 @@ from ansible.compat.tests.mock import DEFAULT from ansible.module_utils.basic import AnsibleModule try: - from library.bigip_snmp_trap import NetworkedParameters - from library.bigip_snmp_trap import NonNetworkedParameters - from library.bigip_snmp_trap import ModuleManager - from library.bigip_snmp_trap import NetworkedManager - from library.bigip_snmp_trap import NonNetworkedManager - from library.bigip_snmp_trap import ArgumentSpec + from library.modules.bigip_snmp_trap import V2Parameters + from library.modules.bigip_snmp_trap import V1Parameters + from library.modules.bigip_snmp_trap import ModuleManager + from library.modules.bigip_snmp_trap import V2Manager + from library.modules.bigip_snmp_trap import V1Manager + from library.modules.bigip_snmp_trap import ArgumentSpec from library.module_utils.network.f5.common import F5ModuleError from library.module_utils.network.f5.common import iControlUnexpectedHTTPError from test.unit.modules.utils import set_module_args except ImportError: try: - from ansible.modules.network.f5.bigip_snmp_trap import NetworkedParameters - from ansible.modules.network.f5.bigip_snmp_trap import NonNetworkedParameters + from ansible.modules.network.f5.bigip_snmp_trap import V2Parameters + from ansible.modules.network.f5.bigip_snmp_trap import V1Parameters from ansible.modules.network.f5.bigip_snmp_trap import ModuleManager - from ansible.modules.network.f5.bigip_snmp_trap import NetworkedManager - from ansible.modules.network.f5.bigip_snmp_trap import NonNetworkedManager + from ansible.modules.network.f5.bigip_snmp_trap import V2Manager + from ansible.modules.network.f5.bigip_snmp_trap import V1Manager from ansible.modules.network.f5.bigip_snmp_trap import ArgumentSpec from ansible.module_utils.network.f5.common import F5ModuleError from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError @@ -79,7 +79,7 @@ class TestParameters(unittest.TestCase): server='localhost', user='admin' ) - p = NetworkedParameters(params=args) + p = V2Parameters(params=args) assert p.name == 'foo' assert p.snmp_version == '1' assert p.community == 'public' @@ -99,7 +99,7 @@ class TestParameters(unittest.TestCase): server='localhost', user='admin' ) - p = NonNetworkedParameters(params=args) + p = V1Parameters(params=args) assert p.name == 'foo' assert p.snmp_version == '1' assert p.community == 'public' @@ -116,7 +116,7 @@ class TestParameters(unittest.TestCase): version=1, port=1000 ) - p = NetworkedParameters(params=args) + p = V2Parameters(params=args) assert p.name == 'foo' assert p.snmp_version == '1' assert p.community == 'public' @@ -149,17 +149,18 @@ class TestManager(unittest.TestCase): ) # Override methods to force specific logic in the module to happen - mm = ModuleManager(module=module) - mm.is_version_non_networked = Mock(return_value=False) + m0 = ModuleManager(module=module) + m0.is_version_without_network = Mock(return_value=False) + m0.is_version_with_default_network = Mock(return_value=True) patches = dict( create_on_device=DEFAULT, exists=DEFAULT ) - with patch.multiple(NetworkedManager, **patches) as mo: + with patch.multiple(V2Manager, **patches) as mo: mo['create_on_device'].side_effect = Mock(return_value=True) mo['exists'].side_effect = Mock(return_value=False) - results = mm.exec_module() + results = m0.exec_module() assert results['changed'] is True assert results['port'] == 1000 @@ -183,17 +184,17 @@ class TestManager(unittest.TestCase): ) # Override methods to force specific logic in the module to happen - mm = ModuleManager(module=module) - mm.is_version_non_networked = Mock(return_value=True) + m0 = ModuleManager(module=module) + m0.is_version_without_network = Mock(return_value=True) patches = dict( create_on_device=DEFAULT, exists=DEFAULT ) - with patch.multiple(NonNetworkedManager, **patches) as mo: + with patch.multiple(V1Manager, **patches) as mo: mo['create_on_device'].side_effect = Mock(return_value=True) mo['exists'].side_effect = Mock(return_value=False) - results = mm.exec_module() + results = m0.exec_module() assert results['changed'] is True assert results['port'] == 1000