From 8e6c3b06b8a1dd99050dcf3ade0e7735d3f007b0 Mon Sep 17 00:00:00 2001 From: Tim Rupp Date: Mon, 19 Nov 2018 15:24:44 -0800 Subject: [PATCH] Adds the ip_intelligence_policy parameter to vs module (#48903) --- .../network/f5/bigip_virtual_server.py | 57 ++++++++++++++++++- .../network/f5/test_bigip_virtual_server.py | 34 +++++++---- 2 files changed, 76 insertions(+), 15 deletions(-) diff --git a/lib/ansible/modules/network/f5/bigip_virtual_server.py b/lib/ansible/modules/network/f5/bigip_virtual_server.py index 82097bd5c2..54ed7e59d6 100644 --- a/lib/ansible/modules/network/f5/bigip_virtual_server.py +++ b/lib/ansible/modules/network/f5/bigip_virtual_server.py @@ -298,10 +298,9 @@ options: description: - Specifies the destination address network mask. This parameter will work with IPv4 and IPv6 tye of addresses. - This is an optional parameter which can be specified when creating or updating virtual server. - - If C(destination) is provided in CIDR notation format and C(mask) is provided the mask parameter takes - precedence. + - If C(destination) is set in CIDR notation format and C(mask) is provided the C(mask) parameter takes precedence. - If catchall destination is specified, i.e. C(0.0.0.0) for IPv4 C(::) for IPv6, - mask parameter is set to C(any) or C(any6) respectively) + mask parameter is set to C(any) or C(any6) respectively. - When the C(destination) is provided not in CIDR notation and C(mask) is not specified, C(255.255.255.255) or C(ffff:ffff:ffff:ffff:ffff:ffff:ffff:ffff) is set for IPv4 and IPv6 addresses respectively. - When C(destination) is provided in CIDR notation format and C(mask) is not specified the mask parameter is @@ -389,6 +388,12 @@ options: - When specified, the route domain policy overrides the device policy, and is overridden by a virtual server policy. type: bool + ip_intelligence_policy: + description: + - Specifies the IP intelligence policy applied to the virtual server. + - This parameter requires that a valid BIG-IP security module such as ASM or AFM + be provisioned. + version_added: 2.8 extends_documentation_fragment: f5 author: - Tim Rupp (@caphrim007) @@ -667,6 +672,11 @@ security_log_profiles: returned: changed type: list sample: ['/Common/profile1', '/Common/profile2'] +ip_intelligence_policy: + description: The new IP Intelligence Policy assigned to the virtual. + returned: changed + type: string + sample: /Common/ip-intelligence ''' import os import re @@ -697,6 +707,7 @@ try: from library.module_utils.network.f5.ipaddress import validate_ip_v6_address from library.module_utils.network.f5.ipaddress import get_netmask from library.module_utils.network.f5.ipaddress import compress_address + from library.module_utils.network.f5.icontrol import modules_provisioned except ImportError: from ansible.module_utils.network.f5.bigip import F5RestClient from ansible.module_utils.network.f5.common import MANAGED_BY_ANNOTATION_VERSION @@ -718,6 +729,7 @@ except ImportError: from ansible.module_utils.network.f5.ipaddress import validate_ip_v6_address from ansible.module_utils.network.f5.ipaddress import get_netmask from ansible.module_utils.network.f5.ipaddress import compress_address + from ansible.module_utils.network.f5.icontrol import modules_provisioned class Parameters(AnsibleF5Parameters): @@ -738,6 +750,7 @@ class Parameters(AnsibleF5Parameters): 'securityLogProfiles': 'security_log_profiles', 'securityNatPolicy': 'security_nat_policy', 'sourcePort': 'source_port', + 'ipIntelligencePolicy': 'ip_intelligence_policy', } api_attributes = [ @@ -773,6 +786,7 @@ class Parameters(AnsibleF5Parameters): 'sourcePort', 'mirror', 'mask', + 'ipIntelligencePolicy', ] updatables = [ @@ -802,6 +816,7 @@ class Parameters(AnsibleF5Parameters): 'source_port', 'mirror', 'mask', + 'ip_intelligence_policy', ] returnables = [ @@ -835,6 +850,7 @@ class Parameters(AnsibleF5Parameters): 'source_port', 'mirror', 'mask', + 'ip_intelligence_policy', ] profiles_mutex = [ @@ -1738,6 +1754,14 @@ class ModuleParameters(Parameters): return None return fq_name(self.partition, self._values['firewall_staged_policy']) + @property + def ip_intelligence_policy(self): + if self._values['ip_intelligence_policy'] is None: + return None + if self._values['ip_intelligence_policy'] in ['', 'none']: + return '' + return fq_name(self.partition, self._values['ip_intelligence_policy']) + @property def security_log_profiles(self): if self._values['security_log_profiles'] is None: @@ -2756,6 +2780,17 @@ class Difference(object): default_persistence_profile=self.want.default_persistence_profile ) + @property + def ip_intelligence_policy(self): + if self.want.ip_intelligence_policy is None: + return None + if self.want.ip_intelligence_policy == '' and self.have.ip_intelligence_policy is not None: + return "" + if self.want.ip_intelligence_policy == '' and self.have.ip_intelligence_policy is None: + return None + if self.want.ip_intelligence_policy != self.have.ip_intelligence_policy: + return self.want.ip_intelligence_policy + @property def policies(self): if self.want.policies is None: @@ -2873,12 +2908,15 @@ class ModuleManager(object): self.have = ApiParameters(client=self.client) self.want = ModuleParameters(client=self.client, params=self.module.params) self.changes = UsableChanges() + self.provisioned_modules = [] def exec_module(self): changed = False result = dict() state = self.want.state + self.provisioned_modules = modules_provisioned(self.client) + if state in ['present', 'enabled', 'disabled']: changed = self.present() elif state == "absent": @@ -2908,6 +2946,12 @@ class ModuleManager(object): ) validator.check_update() + if self.want.ip_intelligence_policy is not None: + if not any(x for x in self.provisioned_modules if x in ['afm', 'asm']): + raise F5ModuleError( + "AFM must be provisioned to configure an IP Intelligence policy." + ) + if not self.should_update(): return False if self.module.check_mode: @@ -2980,6 +3024,12 @@ class ModuleManager(object): ) validator.check_create() + if self.want.ip_intelligence_policy is not None: + if not any(x for x in self.provisioned_modules if x in ['afm', 'asm']): + raise F5ModuleError( + "AFM must be provisioned to configure an IP Intelligence policy." + ) + self._set_changed_options() if self.module.check_mode: return True @@ -3139,6 +3189,7 @@ class ArgumentSpec(object): mask=dict(), firewall_staged_policy=dict(), firewall_enforced_policy=dict(), + ip_intelligence_policy=dict(), security_log_profiles=dict(type='list'), security_nat_policy=dict( type='dict', diff --git a/test/units/modules/network/f5/test_bigip_virtual_server.py b/test/units/modules/network/f5/test_bigip_virtual_server.py index 414e7cbbea..d10b58d265 100644 --- a/test/units/modules/network/f5/test_bigip_virtual_server.py +++ b/test/units/modules/network/f5/test_bigip_virtual_server.py @@ -29,20 +29,18 @@ try: from test.units.modules.utils import set_module_args except ImportError: - try: - from ansible.modules.network.f5.bigip_virtual_server import ApiParameters - from ansible.modules.network.f5.bigip_virtual_server import ModuleParameters - from ansible.modules.network.f5.bigip_virtual_server import ModuleManager - from ansible.modules.network.f5.bigip_virtual_server import ArgumentSpec + from ansible.modules.network.f5.bigip_virtual_server import ApiParameters + from ansible.modules.network.f5.bigip_virtual_server import ModuleParameters + from ansible.modules.network.f5.bigip_virtual_server import ModuleManager + from ansible.modules.network.f5.bigip_virtual_server import ArgumentSpec - # Ansible 2.8 imports - from units.compat import unittest - from units.compat.mock import Mock - from units.compat.mock import patch + # Ansible 2.8 imports + from units.compat import unittest + from units.compat.mock import Mock + from units.compat.mock import patch + + from units.modules.utils import set_module_args - from units.modules.utils import set_module_args - except ImportError: - raise SkipTest("F5 Ansible modules require the f5-sdk Python library") fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') fixture_data = {} @@ -357,6 +355,18 @@ class TestManager(unittest.TestCase): def setUp(self): self.spec = ArgumentSpec() + try: + self.p1 = patch('library.modules.bigip_virtual_server.modules_provisioned') + self.m1 = self.p1.start() + self.m1.return_value = ['ltm', 'gtm', 'asm'] + except Exception: + self.p1 = patch('ansible.modules.network.f5.bigip_virtual_server.modules_provisioned') + self.m1 = self.p1.start() + self.m1.return_value = ['ltm', 'gtm', 'asm'] + + def tearDown(self): + self.p1.stop() + def test_create_virtual_server(self, *args): set_module_args(dict( all_profiles=[