1# -*- coding: utf-8 -*-
2#
3# Copyright (c) 2017 F5 Networks 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
9import os
10import json
11import pytest
12import sys
13
14if sys.version_info < (2, 7):
15    pytestmark = pytest.mark.skip("F5 Ansible modules require Python >= 2.7")
16
17from ansible.module_utils.basic import AnsibleModule
18
19from ansible_collections.f5networks.f5_modules.plugins.modules.bigip_vcmp_guest import (
20    ModuleParameters, ApiParameters, ModuleManager, ArgumentSpec
21)
22from ansible_collections.f5networks.f5_modules.tests.unit.compat import unittest
23from ansible_collections.f5networks.f5_modules.tests.unit.compat.mock import Mock, patch
24from ansible_collections.f5networks.f5_modules.tests.unit.modules.utils import set_module_args
25
26
27fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures')
28fixture_data = {}
29
30
31def load_fixture(name):
32    path = os.path.join(fixture_path, name)
33
34    if path in fixture_data:
35        return fixture_data[path]
36
37    with open(path) as f:
38        data = f.read()
39
40    try:
41        data = json.loads(data)
42    except Exception:
43        pass
44
45    fixture_data[path] = data
46    return data
47
48
49class TestParameters(unittest.TestCase):
50    def test_module_parameters(self):
51        args = dict(
52            initial_image='BIGIP-12.1.0.1.0.1447-HF1.iso',
53            mgmt_network='bridged',
54            mgmt_address='1.2.3.4/24',
55            vlans=[
56                'vlan1',
57                'vlan2'
58            ]
59        )
60
61        p = ModuleParameters(params=args)
62        assert p.initial_image == 'BIGIP-12.1.0.1.0.1447-HF1.iso'
63        assert p.mgmt_network == 'bridged'
64
65    def test_module_parameters_mgmt_bridged_without_subnet(self):
66        args = dict(
67            mgmt_network='bridged',
68            mgmt_address='1.2.3.4'
69        )
70
71        p = ModuleParameters(params=args)
72        assert p.mgmt_network == 'bridged'
73        assert p.mgmt_address == '1.2.3.4/32'
74
75    def test_module_parameters_mgmt_address_cidr(self):
76        args = dict(
77            mgmt_network='bridged',
78            mgmt_address='1.2.3.4/24'
79        )
80
81        p = ModuleParameters(params=args)
82        assert p.mgmt_network == 'bridged'
83        assert p.mgmt_address == '1.2.3.4/24'
84
85    def test_module_parameters_mgmt_address_subnet(self):
86        args = dict(
87            mgmt_network='bridged',
88            mgmt_address='1.2.3.4/255.255.255.0'
89        )
90
91        p = ModuleParameters(params=args)
92        assert p.mgmt_network == 'bridged'
93        assert p.mgmt_address == '1.2.3.4/24'
94
95    def test_module_parameters_mgmt_route(self):
96        args = dict(
97            mgmt_route='1.2.3.4'
98        )
99
100        p = ModuleParameters(params=args)
101        assert p.mgmt_route == '1.2.3.4'
102
103    def test_module_parameters_vcmp_software_image_facts(self):
104        # vCMP images may include a forward slash in their names. This is probably
105        # related to the slots on the system, but it is not a valid value to specify
106        # that slot when providing an initial image
107        args = dict(
108            initial_image='BIGIP-12.1.0.1.0.1447-HF1.iso/1',
109        )
110
111        p = ModuleParameters(params=args)
112        assert p.initial_image == 'BIGIP-12.1.0.1.0.1447-HF1.iso/1'
113
114    def test_api_parameters(self):
115        args = dict(
116            initialImage="BIGIP-tmos-tier2-13.1.0.0.0.931.iso",
117            managementGw="2.2.2.2",
118            managementIp="1.1.1.1/24",
119            managementNetwork="bridged",
120            state="deployed",
121            vlans=[
122                "/Common/vlan1",
123                "/Common/vlan2"
124            ]
125        )
126
127        p = ApiParameters(params=args)
128        assert p.initial_image == 'BIGIP-tmos-tier2-13.1.0.0.0.931.iso'
129        assert p.mgmt_route == '2.2.2.2'
130        assert p.mgmt_address == '1.1.1.1/24'
131        assert '/Common/vlan1' in p.vlans
132        assert '/Common/vlan2' in p.vlans
133
134    def test_api_parameters_with_hotfix(self):
135        args = dict(
136            initialImage="BIGIP-14.1.0.3-0.0.6.iso",
137            initialHotfix="Hotfix-BIGIP-14.1.0.3.0.5.6-ENG.iso",
138            managementGw="2.2.2.2",
139            managementIp="1.1.1.1/24",
140            managementNetwork="bridged",
141            state="deployed",
142            vlans=[
143                "/Common/vlan1",
144                "/Common/vlan2"
145            ]
146        )
147
148        p = ApiParameters(params=args)
149        assert p.initial_image == 'BIGIP-14.1.0.3-0.0.6.iso'
150        assert p.initial_hotfix == 'Hotfix-BIGIP-14.1.0.3.0.5.6-ENG.iso'
151        assert p.mgmt_route == '2.2.2.2'
152        assert p.mgmt_address == '1.1.1.1/24'
153        assert '/Common/vlan1' in p.vlans
154        assert '/Common/vlan2' in p.vlans
155
156
157class TestManager(unittest.TestCase):
158    def setUp(self):
159        self.spec = ArgumentSpec()
160        self.patcher1 = patch('time.sleep')
161        self.patcher1.start()
162
163        self.p1 = patch('ansible_collections.f5networks.f5_modules.plugins.modules.bigip_vcmp_guest.ModuleParameters.initial_image_exists')
164        self.m1 = self.p1.start()
165        self.m1.return_value = True
166        self.p2 = patch('ansible_collections.f5networks.f5_modules.plugins.modules.bigip_vcmp_guest.ModuleParameters.initial_hotfix_exists')
167        self.m2 = self.p2.start()
168        self.m2.return_value = True
169        self.p3 = patch('ansible_collections.f5networks.f5_modules.plugins.modules.bigip_vcmp_guest.tmos_version')
170        self.p4 = patch('ansible_collections.f5networks.f5_modules.plugins.modules.bigip_vcmp_guest.send_teem')
171        self.m3 = self.p3.start()
172        self.m3.return_value = '14.1.0'
173        self.m4 = self.p4.start()
174        self.m4.return_value = True
175
176    def tearDown(self):
177        self.patcher1.stop()
178        self.p1.stop()
179        self.p2.stop()
180        self.p3.stop()
181        self.p4.stop()
182
183    def test_create_vcmpguest(self, *args):
184        set_module_args(dict(
185            name="guest1",
186            mgmt_network="bridged",
187            mgmt_address="10.10.10.10/24",
188            initial_image="BIGIP-13.1.0.0.0.931.iso",
189            provider=dict(
190                server='localhost',
191                password='password',
192                user='admin'
193            )
194        ))
195
196        module = AnsibleModule(
197            argument_spec=self.spec.argument_spec,
198            supports_check_mode=self.spec.supports_check_mode,
199            required_if=self.spec.required_if
200        )
201
202        # Override methods to force specific logic in the module to happen
203        mm = ModuleManager(module=module)
204        mm.create_on_device = Mock(return_value=True)
205        mm.exists = Mock(return_value=False)
206        mm.is_deployed = Mock(side_effect=[False, True, True, True, True])
207        mm.deploy_on_device = Mock(return_value=True)
208
209        results = mm.exec_module()
210
211        assert results['changed'] is True
212        assert results['name'] == 'guest1'
213
214    def test_create_vcmpguest_with_hotfix(self, *args):
215        set_module_args(dict(
216            name="guest2",
217            mgmt_network="bridged",
218            mgmt_address="10.10.10.10/24",
219            initial_image="BIGIP-14.1.0.3-0.0.6.iso",
220            initial_hotfix="Hotfix-BIGIP-14.1.0.3.0.5.6-ENG.iso",
221            provider=dict(
222                server='localhost',
223                password='password',
224                user='admin'
225            )
226        ))
227
228        module = AnsibleModule(
229            argument_spec=self.spec.argument_spec,
230            supports_check_mode=self.spec.supports_check_mode,
231            required_if=self.spec.required_if
232        )
233
234        # Override methods to force specific logic in the module to happen
235        mm = ModuleManager(module=module)
236        mm.create_on_device = Mock(return_value=True)
237        mm.exists = Mock(return_value=False)
238        mm.is_deployed = Mock(side_effect=[False, True, True, True, True])
239        mm.deploy_on_device = Mock(return_value=True)
240
241        results = mm.exec_module()
242
243        assert results['changed'] is True
244        assert results['name'] == 'guest2'
245