summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorWojciech Wypior <w.wypior@f5.com>2018-12-19 03:38:19 +0100
committerTim Rupp <caphrim007@gmail.com>2018-12-18 18:38:19 -0800
commitf761cc4077d2feed1950af74d88f6ec1c4fd1503 (patch)
treeb787c56cfc933cac7d1c9e35036c8dae1ce1a1af
parentbd072fe83a932598d5d86f9548d8f2ba0ec07371 (diff)
downloadansible-f761cc4077d2feed1950af74d88f6ec1c4fd1503.tar.gz
added ASM policy server technology module (#50116)
* added ASM policy server technology module * Update bigip_asm_policy_server_technology.py
-rw-r--r--lib/ansible/modules/network/f5/bigip_asm_policy_server_technology.py488
-rw-r--r--test/units/modules/network/f5/test_bigip_asm_policy_server_technology.py122
2 files changed, 610 insertions, 0 deletions
diff --git a/lib/ansible/modules/network/f5/bigip_asm_policy_server_technology.py b/lib/ansible/modules/network/f5/bigip_asm_policy_server_technology.py
new file mode 100644
index 0000000000..0a32d5117d
--- /dev/null
+++ b/lib/ansible/modules/network/f5/bigip_asm_policy_server_technology.py
@@ -0,0 +1,488 @@
+#!/usr/bin/python
+# -*- coding: utf-8 -*-
+#
+# Copyright: (c) 2018, F5 Networks 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
+
+
+ANSIBLE_METADATA = {'metadata_version': '1.1',
+ 'status': ['preview'],
+ 'supported_by': 'certified'}
+
+DOCUMENTATION = r'''
+---
+module: bigip_asm_policy_server_technology
+short_description: Manages Server Technology on ASM policy
+description:
+ - Manages Server Technology on ASM policy.
+version_added: 2.8
+options:
+ name:
+ description:
+ - Specifies the name of the server technology to apply/remove to the ASM policy.
+ required: True
+ choices:
+ - jQuery
+ - Java Servlets/JSP
+ - ASP
+ - WebDAV
+ - IIS
+ - Front Page Server Extensions (FPSE)
+ - ASP.NET
+ - Microsoft Windows
+ - Unix/Linux
+ - Macromedia ColdFusion
+ - WordPress
+ - Apache Tomcat
+ - Apache/NCSA HTTP Server
+ - Outlook Web Access
+ - PHP
+ - Microsoft SQL Server
+ - Oracle
+ - MySQL
+ - Lotus Domino
+ - BEA Systems WebLogic Server
+ - Macromedia JRun
+ - Novell
+ - Cisco
+ - SSI (Server Side Includes)
+ - Proxy Servers
+ - CGI
+ - Sybase/ASE
+ - IBM DB2
+ - PostgreSQL
+ - XML
+ - Apache Struts
+ - Elasticsearch
+ - JBoss
+ - Citrix
+ - Node.js
+ - Django
+ - MongoDB
+ - Ruby
+ - JavaServer Faces (JSF)
+ - Joomla
+ - Jetty
+ policy_name:
+ description:
+ - Specifies the name of an existing ASM policy to add or remove server technology.
+ required: True
+ state:
+ description:
+ - When C(present), ensures that the resource exists.
+ - When C(absent), ensures the resource is removed.
+ default: present
+ choices:
+ - present
+ - absent
+ partition:
+ description:
+ - This parameter is only used when identifying ASM policy.
+ default: Common
+notes:
+ - This module is primarily used as a component of configuring ASM policy in Ansible Galaxy ASM Policy Role.
+ - Requires BIG-IP >= 13.0.0
+extends_documentation_fragment: f5
+author:
+ - Wojciech Wypior (@wojtek0806)
+'''
+
+EXAMPLES = r'''
+- name: Add Server Technology to ASM Policy
+ bigip_asm_policy_server_technology:
+ name: Joomla
+ policy_name: FooPolicy
+ provider:
+ password: secret
+ server: lb.mydomain.com
+ user: admin
+ delegate_to: localhost
+- name: Remove Server Technology from ASM Policy
+ bigip_asm_policy_server_technology:
+ name: Joomla
+ policy_name: FooPolicy
+ state: absent
+ provider:
+ password: secret
+ server: lb.mydomain.com
+ user: admin
+ delegate_to: localhost
+'''
+
+RETURN = r'''
+policy_name:
+ description: The name of the ASM policy
+ returned: changed
+ type: str
+ sample: FooPolicy
+name:
+ description: The name of Server Technology added/removed on ASM policy
+ returned: changed
+ type: str
+ sample: Joomla
+'''
+
+from ansible.module_utils.basic import AnsibleModule
+from ansible.module_utils.basic import env_fallback
+from distutils.version import LooseVersion
+
+try:
+ from library.module_utils.network.f5.bigip import F5RestClient
+ 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 fq_name
+ from library.module_utils.network.f5.common import transform_name
+ from library.module_utils.network.f5.common import f5_argument_spec
+ from library.module_utils.network.f5.common import exit_json
+ from library.module_utils.network.f5.common import fail_json
+ from library.module_utils.network.f5.icontrol import tmos_version
+ from library.module_utils.network.f5.icontrol import module_provisioned
+except ImportError:
+ from ansible.module_utils.network.f5.bigip import F5RestClient
+ 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 fq_name
+ from ansible.module_utils.network.f5.common import transform_name
+ from ansible.module_utils.network.f5.common import f5_argument_spec
+ from ansible.module_utils.network.f5.common import exit_json
+ from ansible.module_utils.network.f5.common import fail_json
+ from ansible.module_utils.network.f5.icontrol import tmos_version
+ from ansible.module_utils.network.f5.icontrol import module_provisioned
+
+
+class Parameters(AnsibleF5Parameters):
+ api_map = {
+
+ }
+
+ api_attributes = [
+
+ ]
+
+ returnables = [
+ 'policy_name',
+ 'name'
+
+ ]
+
+ updatables = [
+
+ ]
+
+
+class ApiParameters(Parameters):
+ pass
+
+
+class ModuleParameters(Parameters):
+ pass
+
+
+class Changes(Parameters):
+ def to_return(self):
+ result = {}
+ try:
+ for returnable in self.returnables:
+ result[returnable] = getattr(self, returnable)
+ result = self._filter_params(result)
+ except Exception:
+ pass
+ return result
+
+
+class UsableChanges(Changes):
+ pass
+
+
+class ReportableChanges(Changes):
+ pass
+
+
+class ModuleManager(object):
+ def __init__(self, *args, **kwargs):
+ self.module = kwargs.get('module', None)
+ self.client = kwargs.get('client', None)
+ self.want = ModuleParameters(params=self.module.params)
+ self.have = ApiParameters()
+ self.changes = UsableChanges()
+
+ def _announce_deprecations(self, result):
+ warnings = result.pop('__warnings', [])
+ for warning in warnings:
+ self.client.module.deprecate(
+ msg=warning['msg'],
+ version=warning['version']
+ )
+
+ def _set_changed_options(self):
+ changed = {}
+ for key in Parameters.returnables:
+ if getattr(self.want, key) is not None:
+ changed[key] = getattr(self.want, key)
+ if changed:
+ self.changes = Changes(params=changed)
+
+ def exec_module(self):
+ if not module_provisioned(self.client, 'asm'):
+ raise F5ModuleError(
+ "ASM must be provisioned to use this module."
+ )
+ if self.version_is_less_than_13():
+ raise F5ModuleError(
+ "This module requires TMOS version 13.x and above."
+ )
+
+ changed = False
+ result = dict()
+ state = self.want.state
+
+ if state == "present":
+ changed = self.present()
+ elif state == "absent":
+ changed = self.absent()
+
+ 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 version_is_less_than_13(self):
+ version = tmos_version(self.client)
+ if LooseVersion(version) < LooseVersion('13.0.0'):
+ return True
+ else:
+ return False
+
+ def present(self):
+ if self.exists():
+ return False
+ else:
+ return self.create()
+
+ def absent(self):
+ if self.exists():
+ return self.remove()
+ return False
+
+ def remove(self):
+ if self.module.check_mode:
+ return True
+ self.remove_from_device()
+ if self.exists():
+ raise F5ModuleError("Failed to delete the resource.")
+ return True
+
+ def create(self):
+ self._set_changed_options()
+ if self.module.check_mode:
+ return True
+ self.create_on_device()
+ return True
+
+ def exists(self):
+ policy_id = self._get_policy_id()
+ server_link = self._get_server_tech_link()
+ uri = 'https://{0}:{1}/mgmt/tm/asm/policies/{2}/server-technologies/'.format(
+ self.client.provider['server'],
+ self.client.provider['server_port'],
+ policy_id,
+ )
+ resp = self.client.api.get(uri)
+
+ try:
+ response = resp.json()
+ except ValueError as ex:
+ raise F5ModuleError(str(ex))
+ if 'items' in response and response['items'] != []:
+ for st in response['items']:
+ if st['serverTechnologyReference']['link'] == server_link:
+ self.want.tech_id = st['id']
+ return True
+ return False
+
+ def _get_policy_id(self):
+ policy_id = None
+ uri = "https://{0}:{1}/mgmt/tm/asm/policies/".format(
+ self.client.provider['server'],
+ self.client.provider['server_port'],
+ )
+ query = "?$filter=contains(name,'{0}')+and+contains(partition,'{1}')&$select=name,id".format(
+ self.want.policy_name, self.want.partition
+ )
+ resp = self.client.api.get(uri + query)
+
+ try:
+ response = resp.json()
+ except ValueError as ex:
+ raise F5ModuleError(str(ex))
+
+ if 'items' in response and response['items'] != []:
+ policy_id = response['items'][0]['id']
+
+ if not policy_id:
+ raise F5ModuleError(
+ "The policy with the name {0} does not exist".format(self.want.policy_name)
+ )
+ return policy_id
+
+ def _get_server_tech_link(self):
+ link = None
+ uri = "https://{0}:{1}/mgmt/tm/asm/server-technologies/".format(
+ self.client.provider['server'],
+ self.client.provider['server_port'],
+ )
+ query = "?$filter=contains(serverTechnologyName,'{0}')".format(self.want.name)
+ resp = self.client.api.get(uri + query)
+ try:
+ response = resp.json()
+ except ValueError as ex:
+ raise F5ModuleError(str(ex))
+
+ if 'code' in response and response['code'] in [400, 409, 404]:
+ if 'message' in response:
+ raise F5ModuleError(response['message'])
+ else:
+ raise F5ModuleError(resp.content)
+
+ if 'items' in response:
+ link = response['items'][0]['selfLink']
+ return link
+ return link
+
+ def create_on_device(self):
+ policy_id = self._get_policy_id()
+
+ uri = "https://{0}:{1}/mgmt/tm/asm/policies/{2}/server-technologies/".format(
+ self.client.provider['server'],
+ self.client.provider['server_port'],
+ policy_id
+ )
+
+ params = dict(serverTechnologyReference={'link': self._get_server_tech_link()})
+ resp = self.client.api.post(uri, json=params)
+
+ try:
+ response = resp.json()
+ except ValueError as ex:
+ raise F5ModuleError(str(ex))
+
+ if 'code' in response and response['code'] in [400, 409]:
+ if 'message' in response:
+ raise F5ModuleError(response['message'])
+ else:
+ raise F5ModuleError(resp.content)
+ return True
+
+ def remove_from_device(self):
+ policy_id = self._get_policy_id()
+ tech_id = self.want.tech_id
+ uri = 'https://{0}:{1}/mgmt/tm/asm/policies/{2}/server-technologies/{3}'.format(
+ self.client.provider['server'],
+ self.client.provider['server_port'],
+ policy_id,
+ tech_id,
+ )
+ response = self.client.api.delete(uri)
+ if response.status in [200, 201]:
+ return True
+ raise F5ModuleError(response.content)
+
+
+class ArgumentSpec(object):
+ def __init__(self):
+ self.supports_check_mode = True
+ self.tech = [
+ 'jQuery',
+ 'Java Servlets/JSP',
+ 'ASP',
+ 'WebDAV',
+ 'IIS',
+ 'Front Page Server Extensions (FPSE)',
+ 'ASP.NET',
+ 'Microsoft Windows',
+ 'Unix/Linux',
+ 'Macromedia ColdFusion',
+ 'WordPress',
+ 'Apache Tomcat',
+ 'Apache/NCSA HTTP Server',
+ 'Outlook Web Access',
+ 'PHP',
+ 'Microsoft SQL Server',
+ 'Oracle',
+ 'MySQL',
+ 'Lotus Domino',
+ 'BEA Systems WebLogic Server',
+ 'Macromedia JRun',
+ 'Novell',
+ 'Cisco',
+ 'SSI (Server Side Includes)',
+ 'Proxy Servers',
+ 'CGI',
+ 'Sybase/ASE',
+ 'IBM DB2',
+ 'PostgreSQL',
+ 'XML',
+ 'Apache Struts',
+ 'Elasticsearch',
+ 'JBoss',
+ 'Citrix',
+ 'Node.js',
+ 'Django',
+ 'MongoDB',
+ 'Ruby',
+ 'JavaServer Faces (JSF)',
+ 'Joomla',
+ 'Jetty'
+ ]
+ argument_spec = dict(
+ policy_name=dict(
+ required=True
+ ),
+ name=dict(
+ choices=self.tech,
+ required=True
+ ),
+ state=dict(
+ default='present',
+ choices=['present', 'absent']
+ ),
+ partition=dict(
+ default='Common',
+ fallback=(env_fallback, ['F5_PARTITION'])
+ )
+
+ )
+ self.argument_spec = {}
+ self.argument_spec.update(f5_argument_spec)
+ self.argument_spec.update(argument_spec)
+
+
+def main():
+ spec = ArgumentSpec()
+
+ module = AnsibleModule(
+ argument_spec=spec.argument_spec,
+ supports_check_mode=spec.supports_check_mode,
+ )
+
+ client = F5RestClient(**module.params)
+
+ try:
+ mm = ModuleManager(module=module, client=client)
+ results = mm.exec_module()
+ cleanup_tokens(client)
+ exit_json(module, results, client)
+ except F5ModuleError as ex:
+ cleanup_tokens(client)
+ fail_json(module, ex, client)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/test/units/modules/network/f5/test_bigip_asm_policy_server_technology.py b/test/units/modules/network/f5/test_bigip_asm_policy_server_technology.py
new file mode 100644
index 0000000000..4724765967
--- /dev/null
+++ b/test/units/modules/network/f5/test_bigip_asm_policy_server_technology.py
@@ -0,0 +1,122 @@
+# -*- coding: utf-8 -*-
+#
+# Copyright: (c) 2018, F5 Networks 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
+
+import os
+import json
+import pytest
+import sys
+
+if sys.version_info < (2, 7):
+ pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
+
+from ansible.module_utils.basic import AnsibleModule
+
+try:
+ from library.modules.bigip_asm_policy_server_technology import ApiParameters
+ from library.modules.bigip_asm_policy_server_technology import ModuleParameters
+ from library.modules.bigip_asm_policy_server_technology import ModuleManager
+ from library.modules.bigip_asm_policy_server_technology import ArgumentSpec
+
+ # In Ansible 2.8, Ansible changed import paths.
+ from test.units.compat import unittest
+ from test.units.compat.mock import Mock
+ from test.units.compat.mock import patch
+
+ from test.units.modules.utils import set_module_args
+except ImportError:
+ from ansible.modules.network.f5.bigip_asm_policy_server_technology import ApiParameters
+ from ansible.modules.network.f5.bigip_asm_policy_server_technology import ModuleParameters
+ from ansible.modules.network.f5.bigip_asm_policy_server_technology import ModuleManager
+ from ansible.modules.network.f5.bigip_asm_policy_server_technology import ArgumentSpec
+
+ # 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
+
+
+fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
+fixture_data = {}
+
+
+def load_fixture(name):
+ path = os.path.join(fixture_path, name)
+
+ if path in fixture_data:
+ return fixture_data[path]
+
+ with open(path) as f:
+ data = f.read()
+
+ try:
+ data = json.loads(data)
+ except Exception:
+ pass
+
+ fixture_data[path] = data
+ return data
+
+
+class TestParameters(unittest.TestCase):
+ def test_module_parameters(self):
+ args = dict(
+ name='ASP',
+ state='present',
+ policy_name='fake_policy'
+ )
+
+ p = ModuleParameters(params=args)
+ assert p.name == 'ASP'
+ assert p.state == 'present'
+ assert p.policy_name == 'fake_policy'
+
+
+class TestManager(unittest.TestCase):
+ def setUp(self):
+ self.spec = ArgumentSpec()
+
+ try:
+ self.p1 = patch('library.modules.bigip_asm_policy_server_technology.module_provisioned')
+ self.m1 = self.p1.start()
+ self.m1.return_value = True
+ except Exception:
+ self.p1 = patch('ansible.modules.network.f5.bigip_asm_policy_server_technology.module_provisioned')
+ self.m1 = self.p1.start()
+ self.m1.return_value = True
+
+ def tearDown(self):
+ self.p1.stop()
+
+ def test_add_server_technology(self, *args):
+ set_module_args(dict(
+ policy_name='fake_policy',
+ state='present',
+ name='IIS',
+ server='localhost',
+ password='password',
+ user='admin',
+ ))
+
+ module = AnsibleModule(
+ argument_spec=self.spec.argument_spec,
+ supports_check_mode=self.spec.supports_check_mode
+ )
+
+ # Override methods to force specific logic in the module to happen
+ mm = ModuleManager(module=module)
+ mm.version_is_less_than_13 = Mock(return_value=False)
+ mm.exists = Mock(return_value=False)
+ mm.create_on_device = Mock(return_value=True)
+
+ results = mm.exec_module()
+
+ assert results['changed'] is True
+ assert results['name'] == 'IIS'
+ assert results['policy_name'] == 'fake_policy'