From 8085c38e054b543fc233efae3f3391c13ecffbe0 Mon Sep 17 00:00:00 2001 From: Tim Rupp Date: Fri, 20 Oct 2017 18:05:45 -0700 Subject: Refactors the bigip_gtm_facts module (#31917) Includes pep fixes and inlining code with current conventions --- .../f5/fixtures/load_gtm_pool_a_collection.json | 44 ++++++ .../f5/fixtures/load_gtm_pool_a_example_stats.json | 48 +++++++ .../modules/network/f5/test_bigip_gtm_facts.py | 157 +++++++++++++++++++++ 3 files changed, 249 insertions(+) create mode 100644 test/units/modules/network/f5/fixtures/load_gtm_pool_a_collection.json create mode 100644 test/units/modules/network/f5/fixtures/load_gtm_pool_a_example_stats.json create mode 100644 test/units/modules/network/f5/test_bigip_gtm_facts.py (limited to 'test/units/modules') diff --git a/test/units/modules/network/f5/fixtures/load_gtm_pool_a_collection.json b/test/units/modules/network/f5/fixtures/load_gtm_pool_a_collection.json new file mode 100644 index 0000000000..7ed5344503 --- /dev/null +++ b/test/units/modules/network/f5/fixtures/load_gtm_pool_a_collection.json @@ -0,0 +1,44 @@ +{ + "kind": "tm:gtm:pool:a:acollectionstate", + "selfLink": "https://localhost/mgmt/tm/gtm/pool/a?expandSubcollections=true&ver=13.0.0", + "items": [ + { + "kind": "tm:gtm:pool:a:astate", + "name": "foo.pool", + "partition": "Common", + "fullPath": "/Common/foo.pool", + "generation": 216, + "selfLink": "https://localhost/mgmt/tm/gtm/pool/a/~Common~foo.pool?ver=13.0.0", + "alternateMode": "round-robin", + "dynamicRatio": "disabled", + "enabled": true, + "fallbackIp": "any", + "fallbackMode": "return-to-dns", + "limitMaxBps": 0, + "limitMaxBpsStatus": "disabled", + "limitMaxConnections": 0, + "limitMaxConnectionsStatus": "disabled", + "limitMaxPps": 0, + "limitMaxPpsStatus": "disabled", + "loadBalancingMode": "round-robin", + "manualResume": "disabled", + "maxAnswersReturned": 1, + "monitor": "default", + "qosHitRatio": 5, + "qosHops": 0, + "qosKilobytesSecond": 3, + "qosLcs": 30, + "qosPacketRate": 1, + "qosRtt": 50, + "qosTopology": 0, + "qosVsCapacity": 0, + "qosVsScore": 0, + "ttl": 30, + "verifyMemberAvailability": "enabled", + "membersReference": { + "link": "https://localhost/mgmt/tm/gtm/pool/a/~Common~foo.pool/members?ver=13.0.0", + "isSubcollection": true + } + } + ] +} diff --git a/test/units/modules/network/f5/fixtures/load_gtm_pool_a_example_stats.json b/test/units/modules/network/f5/fixtures/load_gtm_pool_a_example_stats.json new file mode 100644 index 0000000000..70388c9144 --- /dev/null +++ b/test/units/modules/network/f5/fixtures/load_gtm_pool_a_example_stats.json @@ -0,0 +1,48 @@ +{ + "kind": "tm:gtm:pool:a:astats", + "generation": 216, + "selfLink": "https://localhost/mgmt/tm/gtm/pool/a/~Common~foo.pool/stats?ver=13.0.0", + "entries": { + "https://localhost/mgmt/tm/gtm/pool/a/~Common~foo.pool/~Common~foo.pool:A/stats": { + "nestedStats": { + "kind": "tm:gtm:pool:a:astats", + "selfLink": "https://localhost/mgmt/tm/gtm/pool/a/~Common~foo.pool/~Common~foo.pool:A/stats?ver=13.0.0", + "entries": { + "alternate": { + "value": 0 + }, + "dropped": { + "value": 0 + }, + "fallback": { + "value": 0 + }, + "tmName": { + "description": "/Common/foo.pool" + }, + "poolType": { + "description": "A" + }, + "preferred": { + "value": 0 + }, + "returnFromDns": { + "value": 0 + }, + "returnToDns": { + "value": 0 + }, + "status.availabilityState": { + "description": "offline" + }, + "status.enabledState": { + "description": "enabled" + }, + "status.statusReason": { + "description": "No enabled pool members available" + } + } + } + } + } +} diff --git a/test/units/modules/network/f5/test_bigip_gtm_facts.py b/test/units/modules/network/f5/test_bigip_gtm_facts.py new file mode 100644 index 0000000000..e4d2b89117 --- /dev/null +++ b/test/units/modules/network/f5/test_bigip_gtm_facts.py @@ -0,0 +1,157 @@ +# -*- coding: utf-8 -*- +# +# Copyright (c) 2017 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 sys + +from nose.plugins.skip import SkipTest +if sys.version_info < (2, 7): + raise SkipTest("F5 Ansible modules require Python >= 2.7") + +from ansible.compat.tests import unittest +from ansible.compat.tests.mock import patch, Mock +from ansible.module_utils import basic +from ansible.module_utils._text import to_bytes +from ansible.module_utils.f5_utils import AnsibleF5Client +from ansible.module_utils.six import iteritems + +try: + from library.bigip_gtm_facts import Parameters + from library.bigip_gtm_facts import ServerParameters + from library.bigip_gtm_facts import PoolParameters + from library.bigip_gtm_facts import WideIpParameters + from library.bigip_gtm_facts import ModuleManager + from library.bigip_gtm_facts import ServerFactManager + from library.bigip_gtm_facts import PoolFactManager + from library.bigip_gtm_facts import TypedPoolFactManager + from library.bigip_gtm_facts import UntypedPoolFactManager + from library.bigip_gtm_facts import WideIpFactManager + from library.bigip_gtm_facts import TypedWideIpFactManager + from library.bigip_gtm_facts import UntypedWideIpFactManager + from library.bigip_gtm_facts import ArgumentSpec + from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError + from f5.bigip.tm.gtm.pool import A + from f5.utils.responses.handlers import Stats +except ImportError: + try: + from ansible.modules.network.f5.bigip_gtm_pool import Parameters + from ansible.modules.network.f5.bigip_gtm_pool import ServerParameters + from ansible.modules.network.f5.bigip_gtm_pool import PoolParameters + from ansible.modules.network.f5.bigip_gtm_pool import WideIpParameters + from ansible.modules.network.f5.bigip_gtm_pool import ModuleManager + from ansible.modules.network.f5.bigip_gtm_pool import ServerFactManager + from ansible.modules.network.f5.bigip_gtm_pool import PoolFactManager + from ansible.modules.network.f5.bigip_gtm_pool import TypedPoolFactManager + from ansible.modules.network.f5.bigip_gtm_pool import UntypedPoolFactManager + from ansible.modules.network.f5.bigip_gtm_pool import WideIpFactManager + from ansible.modules.network.f5.bigip_gtm_pool import TypedWideIpFactManager + from ansible.modules.network.f5.bigip_gtm_pool import UntypedWideIpFactManager + from ansible.modules.network.f5.bigip_gtm_pool import ArgumentSpec + from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError + from f5.bigip.tm.gtm.pool import A + from f5.utils.responses.handlers import Stats + 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 = {} + + +def set_module_args(args): + args = json.dumps({'ANSIBLE_MODULE_ARGS': args}) + basic._ANSIBLE_ARGS = to_bytes(args) + + +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 FakeStatResource(object): + def __init__(self, obj): + self.entries = obj + + +class FakeARecord(A): + def __init__(self, *args, **kwargs): + attrs = kwargs.pop('attrs', {}) + for key, value in iteritems(attrs): + setattr(self, key, value) + + +class TestParameters(unittest.TestCase): + def test_module_parameters(self): + args = dict( + include=['pool'], + filter='name.*' + ) + p = Parameters(args) + assert p.include == ['pool'] + assert p.filter == 'name.*' + + +@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root', + return_value=True) +class TestManager(unittest.TestCase): + + def setUp(self): + self.spec = ArgumentSpec() + + def test_get_typed_pool_facts(self, *args): + set_module_args(dict( + include='pool', + password='passsword', + server='localhost', + user='admin' + )) + + fixture1 = load_fixture('load_gtm_pool_a_collection.json') + fixture2 = load_fixture('load_gtm_pool_a_example_stats.json') + collection = [FakeARecord(attrs=x) for x in fixture1['items']] + stats = Stats(FakeStatResource(fixture2['entries'])) + + client = AnsibleF5Client( + argument_spec=self.spec.argument_spec, + supports_check_mode=self.spec.supports_check_mode, + f5_product_name=self.spec.f5_product_name + ) + + # Override methods in the specific type of manager + tfm = TypedPoolFactManager(client) + tfm.read_collection_from_device = Mock(return_value=collection) + tfm.read_stats_from_device = Mock(return_value=stats.stat) + + tm = PoolFactManager(client) + tm.version_is_less_than_12 = Mock(return_value=False) + tm.get_manager = Mock(return_value=tfm) + + # Override methods to force specific logic in the module to happen + mm = ModuleManager(client) + mm.get_manager = Mock(return_value=tm) + mm.gtm_provisioned = Mock(return_value=True) + + results = mm.exec_module() + + assert results['changed'] is True + assert 'pool' in results + assert len(results['pool']) > 0 + assert 'load_balancing_mode' in results['pool'][0] -- cgit v1.2.1