Browse code

Refactors and deprecation removals (#34830)

This patch is primarily a refactor to make the validate-modules arg-spec
no longer generate a traceback. It additionally includes removal of deprecated
code in the virtual server module.

Tim Rupp authored on 2018/01/13 16:03:41
Showing 26 changed files
... ...
@@ -30,7 +30,6 @@ options:
30 30
         that an existing variable is set to C(value). When C(reset) sets the
31 31
         variable back to the default value. At least one of value and state
32 32
         C(reset) are required.
33
-    required: False
34 33
     default: present
35 34
     choices:
36 35
       - present
... ...
@@ -39,14 +38,9 @@ options:
39 39
     description:
40 40
       - The value to set the key to. At least one of value and state C(reset)
41 41
         are required.
42
-    required: False
43 42
 notes:
44
-  - Requires the f5-sdk Python package on the host. This is as easy as pip
45
-    install f5-sdk.
46 43
   - Requires BIG-IP version 12.0.0 or greater
47 44
 extends_documentation_fragment: f5
48
-requirements:
49
-  - f5-sdk
50 45
 author:
51 46
   - Tim Rupp (@caphrim007)
52 47
 '''
... ...
@@ -98,15 +92,37 @@ value:
98 98
   sample: false
99 99
 '''
100 100
 
101
-from ansible.module_utils.f5_utils import AnsibleF5Client
102
-from ansible.module_utils.f5_utils import AnsibleF5Parameters
103
-from ansible.module_utils.f5_utils import HAS_F5SDK
104
-from ansible.module_utils.f5_utils import F5ModuleError
101
+from ansible.module_utils.basic import AnsibleModule
102
+
103
+HAS_DEVEL_IMPORTS = False
105 104
 
106 105
 try:
107
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
106
+    # Sideband repository used for dev
107
+    from library.module_utils.network.f5.bigip import HAS_F5SDK
108
+    from library.module_utils.network.f5.bigip import F5Client
109
+    from library.module_utils.network.f5.common import F5ModuleError
110
+    from library.module_utils.network.f5.common import AnsibleF5Parameters
111
+    from library.module_utils.network.f5.common import cleanup_tokens
112
+    from library.module_utils.network.f5.common import fqdn_name
113
+    from library.module_utils.network.f5.common import f5_argument_spec
114
+    try:
115
+        from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
116
+    except ImportError:
117
+        HAS_F5SDK = False
118
+    HAS_DEVEL_IMPORTS = True
108 119
 except ImportError:
109
-    HAS_F5SDK = False
120
+    # Upstream Ansible
121
+    from ansible.module_utils.network.f5.bigip import HAS_F5SDK
122
+    from ansible.module_utils.network.f5.bigip import F5Client
123
+    from ansible.module_utils.network.f5.common import F5ModuleError
124
+    from ansible.module_utils.network.f5.common import AnsibleF5Parameters
125
+    from ansible.module_utils.network.f5.common import cleanup_tokens
126
+    from ansible.module_utils.network.f5.common import fqdn_name
127
+    from ansible.module_utils.network.f5.common import f5_argument_spec
128
+    try:
129
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
130
+    except ImportError:
131
+        HAS_F5SDK = False
110 132
 
111 133
 
112 134
 class Parameters(AnsibleF5Parameters):
... ...
@@ -124,16 +140,6 @@ class Parameters(AnsibleF5Parameters):
124 124
         result = self._filter_params(result)
125 125
         return result
126 126
 
127
-    def api_params(self):
128
-        result = {}
129
-        for api_attribute in self.api_attributes:
130
-            if self.api_map is not None and api_attribute in self.api_map:
131
-                result[api_attribute] = getattr(self, self.api_map[api_attribute])
132
-            else:
133
-                result[api_attribute] = getattr(self, api_attribute)
134
-        result = self._filter_params(result)
135
-        return result
136
-
137 127
     @property
138 128
     def name(self):
139 129
         return self._values['key']
... ...
@@ -143,12 +149,17 @@ class Parameters(AnsibleF5Parameters):
143 143
         self._values['key'] = value
144 144
 
145 145
 
146
+class Changes(Parameters):
147
+    pass
148
+
149
+
146 150
 class ModuleManager(object):
147
-    def __init__(self, client):
148
-        self.client = client
151
+    def __init__(self, *args, **kwargs):
152
+        self.module = kwargs.get('module', None)
153
+        self.client = kwargs.get('client', None)
149 154
         self.have = None
150
-        self.want = Parameters(self.client.module.params)
151
-        self.changes = Parameters()
155
+        self.want = Parameters(params=self.module.params)
156
+        self.changes = Changes()
152 157
 
153 158
     def _update_changed_options(self):
154 159
         changed = {}
... ...
@@ -159,10 +170,10 @@ class ModuleManager(object):
159 159
                 if attr1 != attr2:
160 160
                     changed[key] = attr1
161 161
         if self.want.state == 'reset':
162
-            if str(self.want.value) == str(self.want.default_value):
163
-                changed[self.want.key] = self.want.value
162
+            if str(self.have.value) != str(self.have.default_value):
163
+                changed[self.want.key] = self.have.default_value
164 164
         if changed:
165
-            self.changes = Parameters(changed)
165
+            self.changes = Changes(params=changed)
166 166
             return True
167 167
         return False
168 168
 
... ...
@@ -189,7 +200,7 @@ class ModuleManager(object):
189 189
             name=self.want.key
190 190
         )
191 191
         result = resource.attrs
192
-        return Parameters(result)
192
+        return Parameters(params=result)
193 193
 
194 194
     def exists(self):
195 195
         resource = self.client.api.tm.sys.dbs.db.load(
... ...
@@ -213,7 +224,7 @@ class ModuleManager(object):
213 213
         self.have = self.read_current_from_device()
214 214
         if not self.should_update():
215 215
             return False
216
-        if self.client.check_mode:
216
+        if self.module.check_mode:
217 217
             return True
218 218
         self.update_on_device()
219 219
         return True
... ...
@@ -235,9 +246,11 @@ class ModuleManager(object):
235 235
         self.have = self.read_current_from_device()
236 236
         if not self.should_update():
237 237
             return False
238
-        if self.client.check_mode:
238
+        if self.module.check_mode:
239 239
             return True
240
-        self.update_on_device()
240
+        self.reset_on_device()
241
+        self.want.update({'key': self.want.key})
242
+        self.want.update({'value': self.have.default_value})
241 243
         if self.exists():
242 244
             return True
243 245
         else:
... ...
@@ -249,13 +262,13 @@ class ModuleManager(object):
249 249
         resource = self.client.api.tm.sys.dbs.db.load(
250 250
             name=self.want.key
251 251
         )
252
-        resource.update(value=self.want.default_value)
252
+        resource.update(value=self.have.default_value)
253 253
 
254 254
 
255 255
 class ArgumentSpec(object):
256 256
     def __init__(self):
257 257
         self.supports_check_mode = True
258
-        self.argument_spec = dict(
258
+        argument_spec = dict(
259 259
             key=dict(required=True),
260 260
             state=dict(
261 261
                 default='present',
... ...
@@ -263,27 +276,30 @@ class ArgumentSpec(object):
263 263
             ),
264 264
             value=dict()
265 265
         )
266
-        self.f5_product_name = 'bigip'
266
+        self.argument_spec = {}
267
+        self.argument_spec.update(f5_argument_spec)
268
+        self.argument_spec.update(argument_spec)
267 269
 
268 270
 
269 271
 def main():
270
-    if not HAS_F5SDK:
271
-        raise F5ModuleError("The python f5-sdk module is required")
272
-
273 272
     spec = ArgumentSpec()
274 273
 
275
-    client = AnsibleF5Client(
274
+    module = AnsibleModule(
276 275
         argument_spec=spec.argument_spec,
277
-        supports_check_mode=spec.supports_check_mode,
278
-        f5_product_name=spec.f5_product_name
276
+        supports_check_mode=spec.supports_check_mode
279 277
     )
278
+    if not HAS_F5SDK:
279
+        module.fail_json(msg="The python f5-sdk module is required")
280 280
 
281 281
     try:
282
-        mm = ModuleManager(client)
282
+        client = F5Client(**module.params)
283
+        mm = ModuleManager(module=module, client=client)
283 284
         results = mm.exec_module()
284
-        client.module.exit_json(**results)
285
-    except F5ModuleError as e:
286
-        client.module.fail_json(msg=str(e))
285
+        cleanup_tokens(client)
286
+        module.exit_json(**results)
287
+    except F5ModuleError as ex:
288
+        cleanup_tokens(client)
289
+        module.fail_json(msg=str(ex))
287 290
 
288 291
 
289 292
 if __name__ == '__main__':
... ...
@@ -30,48 +30,44 @@ options:
30 30
   gui_setup:
31 31
     description:
32 32
       - C(enable) or C(disabled) the Setup utility in the browser-based
33
-        Configuration utility
34
-    choices: ['yes', 'no']
33
+        Configuration utility.
34
+    type: bool
35 35
   lcd_display:
36 36
     description:
37 37
       - Specifies, when C(enabled), that the system menu displays on the
38 38
         LCD screen on the front of the unit. This setting has no effect
39 39
         when used on the VE platform.
40
-    choices: ['yes', 'no']
40
+    type: bool
41 41
   mgmt_dhcp:
42 42
     description:
43 43
       - Specifies whether or not to enable DHCP client on the management
44 44
         interface
45
-    choices: ['yes', 'no']
45
+    type: bool
46 46
   net_reboot:
47 47
     description:
48 48
       - Specifies, when C(enabled), that the next time you reboot the system,
49 49
         the system boots to an ISO image on the network, rather than an
50 50
         internal media drive.
51
-    choices: ['yes', 'no']
51
+    type: bool
52 52
   quiet_boot:
53 53
     description:
54 54
       - Specifies, when C(enabled), that the system suppresses informational
55 55
         text on the console during the boot cycle. When C(disabled), the
56 56
         system presents messages and informational text on the console during
57 57
         the boot cycle.
58
-    choices: ['yes', 'no']
58
+    type: bool
59 59
   security_banner:
60 60
     description:
61 61
       - Specifies whether the system displays an advisory message on the
62 62
         login screen.
63
-    choices: ['yes', 'no']
63
+    type: bool
64 64
   state:
65 65
     description:
66 66
       - The state of the variable on the system. When C(present), guarantees
67 67
         that an existing variable is set to C(value).
68
-    required: false
69 68
     default: present
70 69
     choices:
71 70
       - present
72
-notes:
73
-  - Requires the f5-sdk Python package on the host. This is as easy as pip
74
-    install f5-sdk.
75 71
 extends_documentation_fragment: f5
76 72
 requirements:
77 73
   - f5-sdk
... ...
@@ -139,20 +135,40 @@ security_banner:
139 139
   sample: enabled
140 140
 '''
141 141
 
142
-from ansible.module_utils.f5_utils import AnsibleF5Client
143
-from ansible.module_utils.f5_utils import AnsibleF5Parameters
144
-from ansible.module_utils.f5_utils import HAS_F5SDK
145
-from ansible.module_utils.f5_utils import F5ModuleError
142
+from ansible.module_utils.basic import AnsibleModule
146 143
 from ansible.module_utils.parsing.convert_bool import BOOLEANS
147 144
 from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE
148 145
 from ansible.module_utils.parsing.convert_bool import BOOLEANS_FALSE
149
-from ansible.module_utils.six import iteritems
150
-from collections import defaultdict
146
+
147
+HAS_DEVEL_IMPORTS = False
151 148
 
152 149
 try:
153
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
150
+    # Sideband repository used for dev
151
+    from library.module_utils.network.f5.bigip import HAS_F5SDK
152
+    from library.module_utils.network.f5.bigip import F5Client
153
+    from library.module_utils.network.f5.common import F5ModuleError
154
+    from library.module_utils.network.f5.common import AnsibleF5Parameters
155
+    from library.module_utils.network.f5.common import cleanup_tokens
156
+    from library.module_utils.network.f5.common import fqdn_name
157
+    from library.module_utils.network.f5.common import f5_argument_spec
158
+    try:
159
+        from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
160
+    except ImportError:
161
+        HAS_F5SDK = False
162
+    HAS_DEVEL_IMPORTS = True
154 163
 except ImportError:
155
-    HAS_F5SDK = False
164
+    # Upstream Ansible
165
+    from ansible.module_utils.network.f5.bigip import HAS_F5SDK
166
+    from ansible.module_utils.network.f5.bigip import F5Client
167
+    from ansible.module_utils.network.f5.common import F5ModuleError
168
+    from ansible.module_utils.network.f5.common import AnsibleF5Parameters
169
+    from ansible.module_utils.network.f5.common import cleanup_tokens
170
+    from ansible.module_utils.network.f5.common import fqdn_name
171
+    from ansible.module_utils.network.f5.common import f5_argument_spec
172
+    try:
173
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
174
+    except ImportError:
175
+        HAS_F5SDK = False
156 176
 
157 177
 
158 178
 class Parameters(AnsibleF5Parameters):
... ...
@@ -182,46 +198,6 @@ class Parameters(AnsibleF5Parameters):
182 182
         'mgmt_dhcp', 'net_reboot', 'quiet_boot', 'console_timeout'
183 183
     ]
184 184
 
185
-    def __init__(self, params=None):
186
-        self._values = defaultdict(lambda: None)
187
-        self._values['__warnings'] = []
188
-        if params:
189
-            self.update(params=params)
190
-
191
-    def update(self, params=None):
192
-        if params:
193
-            for k, v in iteritems(params):
194
-                if self.api_map is not None and k in self.api_map:
195
-                    map_key = self.api_map[k]
196
-                else:
197
-                    map_key = k
198
-
199
-                # Handle weird API parameters like `dns.proxy.__iter__` by
200
-                # using a map provided by the module developer
201
-                class_attr = getattr(type(self), map_key, None)
202
-                if isinstance(class_attr, property):
203
-                    # There is a mapped value for the api_map key
204
-                    if class_attr.fset is None:
205
-                        # If the mapped value does not have
206
-                        # an associated setter
207
-                        self._values[map_key] = v
208
-                    else:
209
-                        # The mapped value has a setter
210
-                        setattr(self, map_key, v)
211
-                else:
212
-                    # If the mapped value is not a @property
213
-                    self._values[map_key] = v
214
-
215
-    def api_params(self):
216
-        result = {}
217
-        for api_attribute in self.api_attributes:
218
-            if self.api_map is not None and api_attribute in self.api_map:
219
-                result[api_attribute] = getattr(self, self.api_map[api_attribute])
220
-            else:
221
-                result[api_attribute] = getattr(self, api_attribute)
222
-        result = self._filter_params(result)
223
-        return result
224
-
225 185
 
226 186
 class ApiParameters(Parameters):
227 187
     pass
... ...
@@ -323,9 +299,10 @@ class Difference(object):
323 323
 
324 324
 
325 325
 class ModuleManager(object):
326
-    def __init__(self, client):
327
-        self.client = client
328
-        self.want = ModuleParameters(params=self.client.module.params)
326
+    def __init__(self, *args, **kwargs):
327
+        self.module = kwargs.get('module', None)
328
+        self.client = kwargs.get('client', None)
329
+        self.want = ModuleParameters(params=self.module.params)
329 330
         self.have = ApiParameters()
330 331
         self.changes = UsableChanges()
331 332
 
... ...
@@ -335,7 +312,7 @@ class ModuleManager(object):
335 335
             if getattr(self.want, key) is not None:
336 336
                 changed[key] = getattr(self.want, key)
337 337
         if changed:
338
-            self.changes = UsableChanges(changed)
338
+            self.changes = UsableChanges(params=changed)
339 339
 
340 340
     def _update_changed_options(self):
341 341
         diff = Difference(self.want, self.have)
... ...
@@ -351,7 +328,7 @@ class ModuleManager(object):
351 351
                 else:
352 352
                     changed[k] = change
353 353
         if changed:
354
-            self.changes = UsableChanges(changed)
354
+            self.changes = UsableChanges(params=changed)
355 355
             return True
356 356
         return False
357 357
 
... ...
@@ -369,7 +346,7 @@ class ModuleManager(object):
369 369
         except iControlUnexpectedHTTPError as e:
370 370
             raise F5ModuleError(str(e))
371 371
 
372
-        reportable = ReportableChanges(self.changes.to_return())
372
+        reportable = ReportableChanges(params=self.changes.to_return())
373 373
         changes = reportable.to_return()
374 374
         result.update(**changes)
375 375
         result.update(dict(changed=changed))
... ...
@@ -379,7 +356,7 @@ class ModuleManager(object):
379 379
     def _announce_deprecations(self, result):
380 380
         warnings = result.pop('__warnings', [])
381 381
         for warning in warnings:
382
-            self.client.module.deprecate(
382
+            self.module.deprecate(
383 383
                 msg=warning['msg'],
384 384
                 version=warning['version']
385 385
             )
... ...
@@ -390,13 +367,13 @@ class ModuleManager(object):
390 390
     def read_current_from_device(self):
391 391
         resource = self.client.api.tm.sys.global_settings.load()
392 392
         result = resource.attrs
393
-        return ApiParameters(result)
393
+        return ApiParameters(params=result)
394 394
 
395 395
     def update(self):
396 396
         self.have = self.read_current_from_device()
397 397
         if not self.should_update():
398 398
             return False
399
-        if self.client.check_mode:
399
+        if self.module.check_mode:
400 400
             return True
401 401
         self.update_on_device()
402 402
         return True
... ...
@@ -412,7 +389,7 @@ class ArgumentSpec(object):
412 412
         self.supports_check_mode = True
413 413
         self.states = ['present']
414 414
         self.on_off_choices = ['enabled', 'disabled', 'True', 'False'] + list(BOOLEANS)
415
-        self.argument_spec = dict(
415
+        argument_spec = dict(
416 416
             security_banner=dict(
417 417
                 choices=self.on_off_choices
418 418
             ),
... ...
@@ -435,39 +412,30 @@ class ArgumentSpec(object):
435 435
             console_timeout=dict(required=False, type='int', default=None),
436 436
             state=dict(default='present', choices=['present'])
437 437
         )
438
-        self.f5_product_name = 'bigip'
439
-
440
-
441
-def cleanup_tokens(client):
442
-    try:
443
-        resource = client.api.shared.authz.tokens_s.token.load(
444
-            name=client.api.icrs.token
445
-        )
446
-        resource.delete()
447
-    except Exception:
448
-        pass
438
+        self.argument_spec = {}
439
+        self.argument_spec.update(f5_argument_spec)
440
+        self.argument_spec.update(argument_spec)
449 441
 
450 442
 
451 443
 def main():
452
-    if not HAS_F5SDK:
453
-        raise F5ModuleError("The python f5-sdk module is required")
454
-
455 444
     spec = ArgumentSpec()
456 445
 
457
-    client = AnsibleF5Client(
446
+    module = AnsibleModule(
458 447
         argument_spec=spec.argument_spec,
459
-        supports_check_mode=spec.supports_check_mode,
460
-        f5_product_name=spec.f5_product_name
448
+        supports_check_mode=spec.supports_check_mode
461 449
     )
450
+    if not HAS_F5SDK:
451
+        module.fail_json(msg="The python f5-sdk module is required")
462 452
 
463 453
     try:
464
-        mm = ModuleManager(client)
454
+        client = F5Client(**module.params)
455
+        mm = ModuleManager(module=module, client=client)
465 456
         results = mm.exec_module()
466 457
         cleanup_tokens(client)
467
-        client.module.exit_json(**results)
468
-    except F5ModuleError as e:
458
+        module.exit_json(**results)
459
+    except F5ModuleError as ex:
469 460
         cleanup_tokens(client)
470
-        client.module.fail_json(msg=str(e))
461
+        module.fail_json(msg=str(ex))
471 462
 
472 463
 
473 464
 if __name__ == '__main__':
... ...
@@ -24,11 +24,20 @@ options:
24 24
     description:
25 25
       - The name of the traffic group.
26 26
     required: True
27
-notes:
28
-  - Requires the f5-sdk Python package on the host. This is as easy as
29
-    C(pip install f5-sdk).
30
-requirements:
31
-  - f5-sdk >= 3.0.5
27
+  partition:
28
+    description:
29
+      - Device partition to manage resources on.
30
+    default: Common
31
+    version_added: 2.5
32
+  state:
33
+    description:
34
+      - When C(present), ensures that the traffic group exists.
35
+      - When C(absent), ensures the traffic group is removed.
36
+    default: present
37
+    choices:
38
+      - present
39
+      - absent
40
+    version_added: 2.5
32 41
 extends_documentation_fragment: f5
33 42
 author:
34 43
   - Tim Rupp (@caphrim007)
... ...
@@ -49,18 +58,38 @@ RETURN = r'''
49 49
 # only common fields returned
50 50
 '''
51 51
 
52
+from ansible.module_utils.basic import AnsibleModule
53
+from ansible.module_utils.basic import env_fallback
52 54
 
53
-from ansible.module_utils.f5_utils import AnsibleF5Client
54
-from ansible.module_utils.f5_utils import AnsibleF5Parameters
55
-from ansible.module_utils.f5_utils import HAS_F5SDK
56
-from ansible.module_utils.f5_utils import F5ModuleError
57
-from ansible.module_utils.six import iteritems
58
-from collections import defaultdict
55
+HAS_DEVEL_IMPORTS = False
59 56
 
60 57
 try:
61
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
58
+    # Sideband repository used for dev
59
+    from library.module_utils.network.f5.bigip import HAS_F5SDK
60
+    from library.module_utils.network.f5.bigip import F5Client
61
+    from library.module_utils.network.f5.common import F5ModuleError
62
+    from library.module_utils.network.f5.common import AnsibleF5Parameters
63
+    from library.module_utils.network.f5.common import cleanup_tokens
64
+    from library.module_utils.network.f5.common import fqdn_name
65
+    from library.module_utils.network.f5.common import f5_argument_spec
66
+    try:
67
+        from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
68
+    except ImportError:
69
+        HAS_F5SDK = False
70
+    HAS_DEVEL_IMPORTS = True
62 71
 except ImportError:
63
-    HAS_F5SDK = False
72
+    # Upstream Ansible
73
+    from ansible.module_utils.network.f5.bigip import HAS_F5SDK
74
+    from ansible.module_utils.network.f5.bigip import F5Client
75
+    from ansible.module_utils.network.f5.common import F5ModuleError
76
+    from ansible.module_utils.network.f5.common import AnsibleF5Parameters
77
+    from ansible.module_utils.network.f5.common import cleanup_tokens
78
+    from ansible.module_utils.network.f5.common import fqdn_name
79
+    from ansible.module_utils.network.f5.common import f5_argument_spec
80
+    try:
81
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
82
+    except ImportError:
83
+        HAS_F5SDK = False
64 84
 
65 85
 
66 86
 class Parameters(AnsibleF5Parameters):
... ...
@@ -80,36 +109,6 @@ class Parameters(AnsibleF5Parameters):
80 80
 
81 81
     ]
82 82
 
83
-    def __init__(self, params=None):
84
-        self._values = defaultdict(lambda: None)
85
-        self._values['__warnings'] = []
86
-        if params:
87
-            self.update(params=params)
88
-
89
-    def update(self, params=None):
90
-        if params:
91
-            for k, v in iteritems(params):
92
-                if self.api_map is not None and k in self.api_map:
93
-                    map_key = self.api_map[k]
94
-                else:
95
-                    map_key = k
96
-
97
-                # Handle weird API parameters like `dns.proxy.__iter__` by
98
-                # using a map provided by the module developer
99
-                class_attr = getattr(type(self), map_key, None)
100
-                if isinstance(class_attr, property):
101
-                    # There is a mapped value for the api_map key
102
-                    if class_attr.fset is None:
103
-                        # If the mapped value does not have
104
-                        # an associated setter
105
-                        self._values[map_key] = v
106
-                    else:
107
-                        # The mapped value has a setter
108
-                        setattr(self, map_key, v)
109
-                else:
110
-                    # If the mapped value is not a @property
111
-                    self._values[map_key] = v
112
-
113 83
     def to_return(self):
114 84
         result = {}
115 85
         try:
... ...
@@ -120,16 +119,6 @@ class Parameters(AnsibleF5Parameters):
120 120
             pass
121 121
         return result
122 122
 
123
-    def api_params(self):
124
-        result = {}
125
-        for api_attribute in self.api_attributes:
126
-            if self.api_map is not None and api_attribute in self.api_map:
127
-                result[api_attribute] = getattr(self, self.api_map[api_attribute])
128
-            else:
129
-                result[api_attribute] = getattr(self, api_attribute)
130
-        result = self._filter_params(result)
131
-        return result
132
-
133 123
 
134 124
 class Changes(Parameters):
135 125
     pass
... ...
@@ -164,9 +153,10 @@ class Difference(object):
164 164
 
165 165
 
166 166
 class ModuleManager(object):
167
-    def __init__(self, client):
168
-        self.client = client
169
-        self.want = Parameters(self.client.module.params)
167
+    def __init__(self, *args, **kwargs):
168
+        self.module = kwargs.get('module', None)
169
+        self.client = kwargs.get('client', None)
170
+        self.want = Parameters(params=self.module.params)
170 171
         self.changes = Changes()
171 172
 
172 173
     def _set_changed_options(self):
... ...
@@ -175,38 +165,9 @@ class ModuleManager(object):
175 175
             if getattr(self.want, key) is not None:
176 176
                 changed[key] = getattr(self.want, key)
177 177
         if changed:
178
-            self.changes = Changes(changed)
178
+            self.changes = Changes(params=changed)
179 179
 
180 180
     def _update_changed_options(self):
181
-        """Sets the changed updatables when updating a resource
182
-
183
-        A module needs to know what changed to determine whether to update
184
-        a resource (or set of resources). This method accomplishes this by
185
-        invoking the Difference engine code.
186
-
187
-        Each parameter in the `Parameter` class' `updatables` array will be
188
-        given to the Difference engine's `compare` method. This is done in the
189
-        order the updatables are listed in the array.
190
-
191
-        The `compare` method updates the `changes` dictionary if the following
192
-        way,
193
-
194
-        * If `None` is returned, a change will not be registered.
195
-        * If a dictionary is returned, the `changes` dictionary will be updated
196
-          with the values in what was returned.
197
-        * Otherwise, the `changes` dictionary's key (the parameter being
198
-          compared) will be set to the value that is returned by `compare`
199
-
200
-        The dictionary behavior is in place to allow you to change the key
201
-        that is set in the `changes` dictionary. There are frequently cases
202
-        where there is not a clean API map that can be set, nor a way to
203
-        otherwise allow you to change the attribute name of the resource being
204
-        updated before it is sent off to the remote device. Using a dictionary
205
-        return value of `compare` allows you to do this.
206
-
207
-        Returns:
208
-            bool: True when changes are present. False otherwise.
209
-        """
210 181
         diff = Difference(self.want, self.have)
211 182
         updatables = Parameters.updatables
212 183
         changed = dict()
... ...
@@ -220,7 +181,7 @@ class ModuleManager(object):
220 220
                 else:
221 221
                     changed[k] = change
222 222
         if changed:
223
-            self.changes = Changes(changed)
223
+            self.changes = Changes(params=changed)
224 224
             return True
225 225
         return False
226 226
 
... ...
@@ -252,7 +213,7 @@ class ModuleManager(object):
252 252
     def _announce_deprecations(self, result):
253 253
         warnings = result.pop('__warnings', [])
254 254
         for warning in warnings:
255
-            self.client.module.deprecate(
255
+            self.module.deprecate(
256 256
                 msg=warning['msg'],
257 257
                 version=warning['version']
258 258
             )
... ...
@@ -274,13 +235,13 @@ class ModuleManager(object):
274 274
         self.have = self.read_current_from_device()
275 275
         if not self.should_update():
276 276
             return False
277
-        if self.client.check_mode:
277
+        if self.module.check_mode:
278 278
             return True
279 279
         self.update_on_device()
280 280
         return True
281 281
 
282 282
     def remove(self):
283
-        if self.client.check_mode:
283
+        if self.module.check_mode:
284 284
             return True
285 285
         self.remove_from_device()
286 286
         if self.exists():
... ...
@@ -293,7 +254,7 @@ class ModuleManager(object):
293 293
             raise F5ModuleError(
294 294
                 "Traffic groups can only be created in the /Common partition"
295 295
             )
296
-        if self.client.check_mode:
296
+        if self.module.check_mode:
297 297
             return True
298 298
         self.create_on_device()
299 299
         return True
... ...
@@ -333,49 +294,44 @@ class ModuleManager(object):
333 333
             partition=self.want.partition
334 334
         )
335 335
         result = resource.attrs
336
-        return Parameters(result)
336
+        return Parameters(params=result)
337 337
 
338 338
 
339 339
 class ArgumentSpec(object):
340 340
     def __init__(self):
341 341
         self.supports_check_mode = True
342
-        self.argument_spec = dict(
342
+        argument_spec = dict(
343 343
             name=dict(required=True),
344
-            state=dict(default='present', choices=['absent', 'present'])
345
-        )
346
-        self.f5_product_name = 'bigip'
347
-
348
-
349
-def cleanup_tokens(client):
350
-    try:
351
-        resource = client.api.shared.authz.tokens_s.token.load(
352
-            name=client.api.icrs.token
344
+            state=dict(default='present', choices=['absent', 'present']),
345
+            partition=dict(
346
+                default='Common',
347
+                fallback=(env_fallback, ['F5_PARTITION'])
348
+            )
353 349
         )
354
-        resource.delete()
355
-    except Exception:
356
-        pass
350
+        self.argument_spec = {}
351
+        self.argument_spec.update(f5_argument_spec)
352
+        self.argument_spec.update(argument_spec)
357 353
 
358 354
 
359 355
 def main():
360
-    if not HAS_F5SDK:
361
-        raise F5ModuleError("The python f5-sdk module is required")
362
-
363 356
     spec = ArgumentSpec()
364 357
 
365
-    client = AnsibleF5Client(
358
+    module = AnsibleModule(
366 359
         argument_spec=spec.argument_spec,
367
-        supports_check_mode=spec.supports_check_mode,
368
-        f5_product_name=spec.f5_product_name
360
+        supports_check_mode=spec.supports_check_mode
369 361
     )
362
+    if not HAS_F5SDK:
363
+        module.fail_json(msg="The python f5-sdk module is required")
370 364
 
371 365
     try:
372
-        mm = ModuleManager(client)
366
+        client = F5Client(**module.params)
367
+        mm = ModuleManager(module=module, client=client)
373 368
         results = mm.exec_module()
374 369
         cleanup_tokens(client)
375
-        client.module.exit_json(**results)
376
-    except F5ModuleError as e:
370
+        module.exit_json(**results)
371
+    except F5ModuleError as ex:
377 372
         cleanup_tokens(client)
378
-        client.module.fail_json(msg=str(e))
373
+        module.fail_json(msg=str(ex))
379 374
 
380 375
 
381 376
 if __name__ == '__main__':
... ...
@@ -87,8 +87,6 @@ options:
87 87
       - installed
88 88
       - present
89 89
 notes:
90
-   - Requires the f5-sdk Python package on the host. This is as easy as
91
-     pip install f5-sdk.
92 90
    - Only the most basic checks are performed by this module. Other checks and
93 91
      considerations need to be taken into account. See the following URL.
94 92
      https://support.f5.com/kb/en-us/solutions/public/11000/300/sol11318.html
... ...
@@ -110,8 +108,6 @@ notes:
110 110
    - This module does not support restoring encrypted archives on replacement
111 111
      RMA units.
112 112
 extends_documentation_fragment: f5
113
-requirements:
114
-  - f5-sdk
115 113
 author:
116 114
   - Tim Rupp (@caphrim007)
117 115
 '''
... ...
@@ -182,28 +178,49 @@ RETURN = r'''
182 182
 
183 183
 import os
184 184
 import re
185
-import sys
186 185
 import time
187 186
 
188
-from distutils.version import LooseVersion
189
-from ansible.module_utils.f5_utils import AnsibleF5Client
190
-from ansible.module_utils.f5_utils import AnsibleF5Parameters
191
-from ansible.module_utils.f5_utils import HAS_F5SDK
192
-from ansible.module_utils.f5_utils import F5ModuleError
187
+from ansible.module_utils.basic import AnsibleModule
193 188
 from ansible.module_utils.six import iteritems
189
+from distutils.version import LooseVersion
190
+
191
+HAS_DEVEL_IMPORTS = False
194 192
 
195 193
 try:
196
-    from collections import OrderedDict
194
+    # Sideband repository used for dev
195
+    from library.module_utils.network.f5.bigip import HAS_F5SDK
196
+    from library.module_utils.network.f5.bigip import F5Client
197
+    from library.module_utils.network.f5.common import F5ModuleError
198
+    from library.module_utils.network.f5.common import AnsibleF5Parameters
199
+    from library.module_utils.network.f5.common import cleanup_tokens
200
+    from library.module_utils.network.f5.common import fqdn_name
201
+    from library.module_utils.network.f5.common import f5_argument_spec
202
+    try:
203
+        from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
204
+    except ImportError:
205
+        HAS_F5SDK = False
206
+    HAS_DEVEL_IMPORTS = True
197 207
 except ImportError:
208
+    # Upstream Ansible
209
+    from ansible.module_utils.network.f5.bigip import HAS_F5SDK
210
+    from ansible.module_utils.network.f5.bigip import F5Client
211
+    from ansible.module_utils.network.f5.common import F5ModuleError
212
+    from ansible.module_utils.network.f5.common import AnsibleF5Parameters
213
+    from ansible.module_utils.network.f5.common import cleanup_tokens
214
+    from ansible.module_utils.network.f5.common import fqdn_name
215
+    from ansible.module_utils.network.f5.common import f5_argument_spec
198 216
     try:
199
-        from ordereddict import OrderedDict
217
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
200 218
     except ImportError:
201
-        pass
219
+        HAS_F5SDK = False
202 220
 
203 221
 try:
204
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
222
+    from collections import OrderedDict
205 223
 except ImportError:
206
-    HAS_F5SDK = False
224
+    try:
225
+        from ordereddict import OrderedDict
226
+    except ImportError:
227
+        pass
207 228
 
208 229
 
209 230
 class Parameters(AnsibleF5Parameters):
... ...
@@ -292,14 +309,15 @@ class Parameters(AnsibleF5Parameters):
292 292
 
293 293
 
294 294
 class ModuleManager(object):
295
-    def __init__(self, client):
296
-        self.client = client
295
+    def __init__(self, *args, **kwargs):
296
+        self.client = kwargs.get('client', None)
297
+        self.kwargs = kwargs
297 298
 
298 299
     def exec_module(self):
299 300
         if self.is_version_v1():
300
-            manager = V1Manager(self.client)
301
+            manager = V1Manager(**self.kwargs)
301 302
         else:
302
-            manager = V2Manager(self.client)
303
+            manager = V2Manager(**self.kwargs)
303 304
 
304 305
         return manager.exec_module()
305 306
 
... ...
@@ -321,10 +339,10 @@ class ModuleManager(object):
321 321
 
322 322
 
323 323
 class BaseManager(object):
324
-    def __init__(self, client):
325
-        self.client = client
326
-        self.have = None
327
-        self.want = Parameters(self.client.module.params)
324
+    def __init__(self, *args, **kwargs):
325
+        self.module = kwargs.get('module', None)
326
+        self.client = kwargs.get('client', None)
327
+        self.want = Parameters(params=self.module.params)
328 328
         self.changes = Parameters()
329 329
 
330 330
     def exec_module(self):
... ...
@@ -352,7 +370,7 @@ class BaseManager(object):
352 352
             return self.create()
353 353
 
354 354
     def update(self):
355
-        if self.client.check_mode:
355
+        if self.module.check_mode:
356 356
             if self.want.force:
357 357
                 return True
358 358
             return False
... ...
@@ -365,7 +383,7 @@ class BaseManager(object):
365 365
             return False
366 366
 
367 367
     def create(self):
368
-        if self.client.check_mode:
368
+        if self.module.check_mode:
369 369
             return True
370 370
         self.create_on_device()
371 371
         if not self.exists():
... ...
@@ -386,7 +404,7 @@ class BaseManager(object):
386 386
         return False
387 387
 
388 388
     def remove(self):
389
-        if self.client.check_mode:
389
+        if self.module.check_mode:
390 390
             return True
391 391
         self.remove_from_device()
392 392
         if self.exists():
... ...
@@ -466,7 +484,6 @@ class V1Manager(BaseManager):
466 466
       * No API to upload UCS files
467 467
 
468 468
     """
469
-
470 469
     def create_on_device(self):
471 470
         remote_path = "/var/local/ucs"
472 471
         tpath_name = '/var/config/rest/downloads'
... ...
@@ -563,7 +580,7 @@ class V2Manager(V1Manager):
563 563
 class ArgumentSpec(object):
564 564
     def __init__(self):
565 565
         self.supports_check_mode = True
566
-        self.argument_spec = dict(
566
+        argument_spec = dict(
567 567
             force=dict(
568 568
                 type='bool',
569 569
                 default='no'
... ...
@@ -585,30 +602,30 @@ class ArgumentSpec(object):
585 585
             ),
586 586
             ucs=dict(required=True)
587 587
         )
588
-        self.f5_product_name = 'bigip'
588
+        self.argument_spec = {}
589
+        self.argument_spec.update(f5_argument_spec)
590
+        self.argument_spec.update(argument_spec)
589 591
 
590 592
 
591 593
 def main():
592
-    if not HAS_F5SDK:
593
-        raise F5ModuleError("The python f5-sdk module is required")
594
-
595
-    if sys.version_info < (2, 7):
596
-        raise F5ModuleError("F5 Ansible modules require Python >= 2.7")
597
-
598 594
     spec = ArgumentSpec()
599 595
 
600
-    client = AnsibleF5Client(
596
+    module = AnsibleModule(
601 597
         argument_spec=spec.argument_spec,
602
-        supports_check_mode=spec.supports_check_mode,
603
-        f5_product_name=spec.f5_product_name
598
+        supports_check_mode=spec.supports_check_mode
604 599
     )
600
+    if not HAS_F5SDK:
601
+        module.fail_json(msg="The python f5-sdk module is required")
605 602
 
606 603
     try:
607
-        mm = ModuleManager(client)
604
+        client = F5Client(**module.params)
605
+        mm = ModuleManager(module=module, client=client)
608 606
         results = mm.exec_module()
609
-        client.module.exit_json(**results)
610
-    except F5ModuleError as e:
611
-        client.module.fail_json(msg=str(e))
607
+        cleanup_tokens(client)
608
+        module.exit_json(**results)
609
+    except F5ModuleError as ex:
610
+        cleanup_tokens(client)
611
+        module.fail_json(msg=str(ex))
612 612
 
613 613
 
614 614
 if __name__ == '__main__':
... ...
@@ -74,13 +74,14 @@ options:
74 74
     choices:
75 75
       - always
76 76
       - on_create
77
+  partition:
78
+    description:
79
+      - Device partition to manage resources on.
80
+    default: Common
81
+    version_added: 2.5
77 82
 notes:
78
-   - Requires the f5-sdk Python package on the host. This is as easy as
79
-     pip install f5-sdk.
80 83
    - Requires BIG-IP versions >= 12.0.0
81 84
 extends_documentation_fragment: f5
82
-requirements:
83
-  - f5-sdk
84 85
 author:
85 86
   - Tim Rupp (@caphrim007)
86 87
   - Wojciech Wypior (@wojtek0806)
... ...
@@ -191,23 +192,44 @@ shell:
191 191
 
192 192
 import re
193 193
 
194
+from ansible.module_utils.basic import AnsibleModule
195
+from ansible.module_utils.basic import env_fallback
194 196
 from distutils.version import LooseVersion
195
-from ansible.module_utils.f5_utils import AnsibleF5Client
196
-from ansible.module_utils.f5_utils import AnsibleF5Parameters
197
-from ansible.module_utils.f5_utils import HAS_F5SDK
198
-from ansible.module_utils.f5_utils import F5ModuleError
199
-from ansible.module_utils.six import iteritems
200
-from collections import defaultdict
197
+
198
+HAS_DEVEL_IMPORTS = False
201 199
 
202 200
 try:
203
-    from StringIO import StringIO
201
+    # Sideband repository used for dev
202
+    from library.module_utils.network.f5.bigip import HAS_F5SDK
203
+    from library.module_utils.network.f5.bigip import F5Client
204
+    from library.module_utils.network.f5.common import F5ModuleError
205
+    from library.module_utils.network.f5.common import AnsibleF5Parameters
206
+    from library.module_utils.network.f5.common import cleanup_tokens
207
+    from library.module_utils.network.f5.common import fqdn_name
208
+    from library.module_utils.network.f5.common import f5_argument_spec
209
+    try:
210
+        from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
211
+    except ImportError:
212
+        HAS_F5SDK = False
213
+    HAS_DEVEL_IMPORTS = True
204 214
 except ImportError:
205
-    from io import StringIO
215
+    # Upstream Ansible
216
+    from ansible.module_utils.network.f5.bigip import HAS_F5SDK
217
+    from ansible.module_utils.network.f5.bigip import F5Client
218
+    from ansible.module_utils.network.f5.common import F5ModuleError
219
+    from ansible.module_utils.network.f5.common import AnsibleF5Parameters
220
+    from ansible.module_utils.network.f5.common import cleanup_tokens
221
+    from ansible.module_utils.network.f5.common import fqdn_name
222
+    from ansible.module_utils.network.f5.common import f5_argument_spec
223
+    try:
224
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
225
+    except ImportError:
226
+        HAS_F5SDK = False
206 227
 
207 228
 try:
208
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
229
+    from StringIO import StringIO
209 230
 except ImportError:
210
-    HAS_F5SDK = False
231
+    from io import StringIO
211 232
 
212 233
 
213 234
 class Parameters(AnsibleF5Parameters):
... ...
@@ -228,36 +250,6 @@ class Parameters(AnsibleF5Parameters):
228 228
         'shell', 'partitionAccess', 'description', 'name', 'password'
229 229
     ]
230 230
 
231
-    def __init__(self, params=None):
232
-        self._values = defaultdict(lambda: None)
233
-        self._values['__warnings'] = []
234
-        if params:
235
-            self.update(params=params)
236
-
237
-    def update(self, params=None):
238
-        if params:
239
-            for k, v in iteritems(params):
240
-                if self.api_map is not None and k in self.api_map:
241
-                    map_key = self.api_map[k]
242
-                else:
243
-                    map_key = k
244
-
245
-                # Handle weird API parameters like `dns.proxy.__iter__` by
246
-                # using a map provided by the module developer
247
-                class_attr = getattr(type(self), map_key, None)
248
-                if isinstance(class_attr, property):
249
-                    # There is a mapped value for the api_map key
250
-                    if class_attr.fset is None:
251
-                        # If the mapped value does not have
252
-                        # an associated setter
253
-                        self._values[map_key] = v
254
-                    else:
255
-                        # The mapped value has a setter
256
-                        setattr(self, map_key, v)
257
-                else:
258
-                    # If the mapped value is not a @property
259
-                    self._values[map_key] = v
260
-
261 231
     @property
262 232
     def partition_access(self):
263 233
         """Partition access values will require some transformation.
... ...
@@ -324,18 +316,28 @@ class Parameters(AnsibleF5Parameters):
324 324
 
325 325
 
326 326
 class ModuleManager(object):
327
-    def __init__(self, client):
328
-        self.client = client
327
+    def __init__(self, *args, **kwargs):
328
+        self.module = kwargs.get('module', None)
329
+        self.client = kwargs.get('client', None)
330
+        self.kwargs = kwargs
329 331
 
330 332
     def exec_module(self):
331 333
         if self.is_root_username_credential():
332
-            manager = RootUserManager(self.client)
334
+            manager = self.get_manager('root')
333 335
         elif self.is_version_less_than_13():
334
-            manager = UnparitionedManager(self.client)
336
+            manager = self.get_manager('v1')
335 337
         else:
336
-            manager = PartitionedManager(self.client)
338
+            manager = self.get_manager('v2')
337 339
         return manager.exec_module()
338 340
 
341
+    def get_manager(self, type):
342
+        if type == 'root':
343
+            return RootUserManager(**self.kwargs)
344
+        elif type == 'v1':
345
+            return UnparitionedManager(**self.kwargs)
346
+        elif type == 'v2':
347
+            return PartitionedManager(**self.kwargs)
348
+
339 349
     def is_version_less_than_13(self):
340 350
         """Checks to see if the TMOS version is less than 13
341 351
 
... ...
@@ -351,17 +353,18 @@ class ModuleManager(object):
351 351
             return False
352 352
 
353 353
     def is_root_username_credential(self):
354
-        user = self.client.module.params.get('username_credential', None)
354
+        user = self.module.params.get('username_credential', None)
355 355
         if user == 'root':
356 356
             return True
357 357
         return False
358 358
 
359 359
 
360 360
 class BaseManager(object):
361
-    def __init__(self, client):
362
-        self.client = client
361
+    def __init__(self, *args, **kwargs):
362
+        self.module = kwargs.get('module', None)
363
+        self.client = kwargs.get('client', None)
363 364
         self.have = None
364
-        self.want = Parameters(self.client.module.params)
365
+        self.want = Parameters(params=self.module.params)
365 366
         self.changes = Parameters()
366 367
 
367 368
     def exec_module(self):
... ...
@@ -388,7 +391,7 @@ class BaseManager(object):
388 388
             if getattr(self.want, key) is not None:
389 389
                 changed[key] = getattr(self.want, key)
390 390
         if changed:
391
-            self.changes = Parameters(changed)
391
+            self.changes = Parameters(params=changed)
392 392
 
393 393
     def _update_changed_options(self):
394 394
         changed = {}
... ...
@@ -411,7 +414,7 @@ class BaseManager(object):
411 411
                         changed[key] = attr1
412 412
 
413 413
         if changed:
414
-            self.changes = Parameters(changed)
414
+            self.changes = Parameters(params=changed)
415 415
             return True
416 416
         return False
417 417
 
... ...
@@ -481,13 +484,13 @@ class BaseManager(object):
481 481
         self.have = self.read_current_from_device()
482 482
         if not self.should_update():
483 483
             return False
484
-        if self.client.check_mode:
484
+        if self.module.check_mode:
485 485
             return True
486 486
         self.update_on_device()
487 487
         return True
488 488
 
489 489
     def remove(self):
490
-        if self.client.check_mode:
490
+        if self.module.check_mode:
491 491
             return True
492 492
         self.remove_from_device()
493 493
         if self.exists():
... ...
@@ -499,7 +502,7 @@ class BaseManager(object):
499 499
         if self.want.shell == 'bash':
500 500
             self.validate_shell_parameter()
501 501
         self._set_changed_options()
502
-        if self.client.check_mode:
502
+        if self.module.check_mode:
503 503
             return True
504 504
         self.create_on_device()
505 505
         return True
... ...
@@ -518,7 +521,7 @@ class UnparitionedManager(BaseManager):
518 518
     def read_current_from_device(self):
519 519
         tmp_res = self.client.api.tm.auth.users.user.load(name=self.want.name)
520 520
         result = tmp_res.attrs
521
-        return Parameters(result)
521
+        return Parameters(params=result)
522 522
 
523 523
     def exists(self):
524 524
         return self.client.api.tm.auth.users.user.exists(name=self.want.name)
... ...
@@ -570,7 +573,7 @@ class PartitionedManager(BaseManager):
570 570
     def read_current_from_device(self):
571 571
         resource = self._read_one_resource_from_collection()
572 572
         result = resource.attrs
573
-        return Parameters(result)
573
+        return Parameters(params=result)
574 574
 
575 575
     def exists(self):
576 576
         collection = self.client.api.tm.auth.users.get_collection(
... ...
@@ -646,7 +649,7 @@ class RootUserManager(BaseManager):
646 646
 class ArgumentSpec(object):
647 647
     def __init__(self):
648 648
         self.supports_check_mode = True
649
-        self.argument_spec = dict(
649
+        argument_spec = dict(
650 650
             name=dict(
651 651
                 required=True,
652 652
                 aliases=['username_credential']
... ...
@@ -664,41 +667,37 @@ class ArgumentSpec(object):
664 664
             update_password=dict(
665 665
                 default='always',
666 666
                 choices=['always', 'on_create']
667
+            ),
668
+            state=dict(default='present', choices=['absent', 'present']),
669
+            partition=dict(
670
+                default='Common',
671
+                fallback=(env_fallback, ['F5_PARTITION'])
667 672
             )
668 673
         )
669
-        self.f5_product_name = 'bigip'
670
-
671
-
672
-def cleanup_tokens(client):
673
-    try:
674
-        resource = client.api.shared.authz.tokens_s.token.load(
675
-            name=client.api.icrs.token
676
-        )
677
-        resource.delete()
678
-    except Exception:
679
-        pass
674
+        self.argument_spec = {}
675
+        self.argument_spec.update(f5_argument_spec)
676
+        self.argument_spec.update(argument_spec)
680 677
 
681 678
 
682 679
 def main():
683
-    if not HAS_F5SDK:
684
-        raise F5ModuleError("The python f5-sdk module is required")
685
-
686 680
     spec = ArgumentSpec()
687 681
 
688
-    client = AnsibleF5Client(
682
+    module = AnsibleModule(
689 683
         argument_spec=spec.argument_spec,
690
-        supports_check_mode=spec.supports_check_mode,
691
-        f5_product_name=spec.f5_product_name
684
+        supports_check_mode=spec.supports_check_mode
692 685
     )
686
+    if not HAS_F5SDK:
687
+        module.fail_json(msg="The python f5-sdk module is required")
693 688
 
694 689
     try:
695
-        mm = ModuleManager(client)
690
+        client = F5Client(**module.params)
691
+        mm = ModuleManager(module=module, client=client)
696 692
         results = mm.exec_module()
697 693
         cleanup_tokens(client)
698
-        client.module.exit_json(**results)
699
-    except F5ModuleError as e:
694
+        module.exit_json(**results)
695
+    except F5ModuleError as ex:
700 696
         cleanup_tokens(client)
701
-        client.module.fail_json(msg=str(e))
697
+        module.fail_json(msg=str(ex))
702 698
 
703 699
 
704 700
 if __name__ == '__main__':
... ...
@@ -112,9 +112,11 @@ options:
112 112
       - The number you can specify depends on the type of hardware you have.
113 113
       - In the event of a reboot, the system persists the guest to the same slot on
114 114
         which it ran prior to the reboot.
115
+  partition:
116
+    description:
117
+      - Device partition to manage resources on.
118
+    default: Common
115 119
 notes:
116
-  - Requires the f5-sdk Python package on the host. This is as easy as pip
117
-    install f5-sdk.
118 120
   - This module can take a lot of time to deploy vCMP guests. This is an intrinsic
119 121
     limitation of the vCMP system because it is booting real VMs on the BIG-IP
120 122
     device. This boot time is very similar in length to the time it takes to
... ...
@@ -123,8 +125,6 @@ notes:
123 123
     means that it is not unusual for a vCMP host with many guests to take a
124 124
     long time (60+ minutes) to reboot and bring all the guests online. The
125 125
     BIG-IP chassis will be available before all vCMP guests are online.
126
-requirements:
127
-  - f5-sdk >= 3.0.3
128 126
   - netaddr
129 127
 extends_documentation_fragment: f5
130 128
 author:
... ...
@@ -173,16 +173,41 @@ vlans:
173 173
   sample: ['/Common/vlan1', '/Common/vlan2']
174 174
 '''
175 175
 
176
+import time
176 177
 
177
-from ansible.module_utils.f5_utils import AnsibleF5Client
178
-from ansible.module_utils.f5_utils import AnsibleF5Parameters
179
-from ansible.module_utils.f5_utils import HAS_F5SDK
180
-from ansible.module_utils.f5_utils import F5ModuleError
181
-from ansible.module_utils.six import iteritems
182
-from collections import defaultdict
178
+from ansible.module_utils.basic import AnsibleModule
179
+from ansible.module_utils.basic import env_fallback
183 180
 from collections import namedtuple
184 181
 
185
-import time
182
+HAS_DEVEL_IMPORTS = False
183
+
184
+try:
185
+    # Sideband repository used for dev
186
+    from library.module_utils.network.f5.bigip import HAS_F5SDK
187
+    from library.module_utils.network.f5.bigip import F5Client
188
+    from library.module_utils.network.f5.common import F5ModuleError
189
+    from library.module_utils.network.f5.common import AnsibleF5Parameters
190
+    from library.module_utils.network.f5.common import cleanup_tokens
191
+    from library.module_utils.network.f5.common import fqdn_name
192
+    from library.module_utils.network.f5.common import f5_argument_spec
193
+    try:
194
+        from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
195
+    except ImportError:
196
+        HAS_F5SDK = False
197
+    HAS_DEVEL_IMPORTS = True
198
+except ImportError:
199
+    # Upstream Ansible
200
+    from ansible.module_utils.network.f5.bigip import HAS_F5SDK
201
+    from ansible.module_utils.network.f5.bigip import F5Client
202
+    from ansible.module_utils.network.f5.common import F5ModuleError
203
+    from ansible.module_utils.network.f5.common import AnsibleF5Parameters
204
+    from ansible.module_utils.network.f5.common import cleanup_tokens
205
+    from ansible.module_utils.network.f5.common import fqdn_name
206
+    from ansible.module_utils.network.f5.common import f5_argument_spec
207
+    try:
208
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
209
+    except ImportError:
210
+        HAS_F5SDK = False
186 211
 
187 212
 try:
188 213
     from netaddr import IPAddress, AddrFormatError, IPNetwork
... ...
@@ -192,7 +217,6 @@ except ImportError:
192 192
 
193 193
 try:
194 194
     from f5.utils.responses.handlers import Stats
195
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
196 195
 except ImportError:
197 196
     HAS_F5SDK = False
198 197
 
... ...
@@ -222,37 +246,6 @@ class Parameters(AnsibleF5Parameters):
222 222
         'state'
223 223
     ]
224 224
 
225
-    def __init__(self, params=None, client=None):
226
-        self._values = defaultdict(lambda: None)
227
-        self._values['__warnings'] = []
228
-        if params:
229
-            self.update(params=params)
230
-        self.client = client
231
-
232
-    def update(self, params=None):
233
-        if params:
234
-            for k, v in iteritems(params):
235
-                if self.api_map is not None and k in self.api_map:
236
-                    map_key = self.api_map[k]
237
-                else:
238
-                    map_key = k
239
-
240
-                # Handle weird API parameters like `dns.proxy.__iter__` by
241
-                # using a map provided by the module developer
242
-                class_attr = getattr(type(self), map_key, None)
243
-                if isinstance(class_attr, property):
244
-                    # There is a mapped value for the api_map key
245
-                    if class_attr.fset is None:
246
-                        # If the mapped value does not have
247
-                        # an associated setter
248
-                        self._values[map_key] = v
249
-                    else:
250
-                        # The mapped value has a setter
251
-                        setattr(self, map_key, v)
252
-                else:
253
-                    # If the mapped value is not a @property
254
-                    self._values[map_key] = v
255
-
256 225
     def _fqdn_name(self, value):
257 226
         if value is not None and not value.startswith('/'):
258 227
             return '/{0}/{1}'.format(self.partition, value)
... ...
@@ -268,16 +261,6 @@ class Parameters(AnsibleF5Parameters):
268 268
             pass
269 269
         return result
270 270
 
271
-    def api_params(self):
272
-        result = {}
273
-        for api_attribute in self.api_attributes:
274
-            if self.api_map is not None and api_attribute in self.api_map:
275
-                result[api_attribute] = getattr(self, self.api_map[api_attribute])
276
-            else:
277
-                result[api_attribute] = getattr(self, api_attribute)
278
-        result = self._filter_params(result)
279
-        return result
280
-
281 271
     @property
282 272
     def mgmt_route(self):
283 273
         if self._values['mgmt_route'] is None:
... ...
@@ -394,9 +377,10 @@ class Difference(object):
394 394
 
395 395
 
396 396
 class ModuleManager(object):
397
-    def __init__(self, client):
398
-        self.client = client
399
-        self.want = Parameters(client=client, params=self.client.module.params)
397
+    def __init__(self, *args, **kwargs):
398
+        self.module = kwargs.get('module', None)
399
+        self.client = kwargs.get('client', None)
400
+        self.want = Parameters(client=self.client, params=self.module.params)
400 401
         self.changes = Changes()
401 402
 
402 403
     def _set_changed_options(self):
... ...
@@ -405,7 +389,7 @@ class ModuleManager(object):
405 405
             if getattr(self.want, key) is not None:
406 406
                 changed[key] = getattr(self.want, key)
407 407
         if changed:
408
-            self.changes = Changes(changed)
408
+            self.changes = Changes(params=changed)
409 409
 
410 410
     def _update_changed_options(self):
411 411
         diff = Difference(self.want, self.have)
... ...
@@ -418,7 +402,7 @@ class ModuleManager(object):
418 418
             else:
419 419
                 changed[k] = change
420 420
         if changed:
421
-            self.changes = Parameters(changed)
421
+            self.changes = Parameters(params=changed)
422 422
             return True
423 423
         return False
424 424
 
... ...
@@ -450,7 +434,7 @@ class ModuleManager(object):
450 450
     def _announce_deprecations(self, result):
451 451
         warnings = result.pop('__warnings', [])
452 452
         for warning in warnings:
453
-            self.client.module.deprecate(
453
+            self.module.deprecate(
454 454
                 msg=warning['msg'],
455 455
                 version=warning['version']
456 456
             )
... ...
@@ -476,7 +460,7 @@ class ModuleManager(object):
476 476
         self.have = self.read_current_from_device()
477 477
         if not self.should_update():
478 478
             return False
479
-        if self.client.check_mode:
479
+        if self.module.check_mode:
480 480
             return True
481 481
         self.update_on_device()
482 482
         if self.want.state == 'provisioned':
... ...
@@ -488,7 +472,7 @@ class ModuleManager(object):
488 488
         return True
489 489
 
490 490
     def remove(self):
491
-        if self.client.check_mode:
491
+        if self.module.check_mode:
492 492
             return True
493 493
         if self.want.delete_virtual_disk:
494 494
             self.have = self.read_current_from_device()
... ...
@@ -501,7 +485,7 @@ class ModuleManager(object):
501 501
 
502 502
     def create(self):
503 503
         self._set_changed_options()
504
-        if self.client.check_mode:
504
+        if self.module.check_mode:
505 505
             return True
506 506
         if self.want.mgmt_tuple.subnet is None:
507 507
             self.want.update(dict(
... ...
@@ -547,7 +531,7 @@ class ModuleManager(object):
547 547
             name=self.want.name
548 548
         )
549 549
         result = resource.attrs
550
-        return Parameters(result)
550
+        return Parameters(params=result)
551 551
 
552 552
     def remove_virtual_disk(self):
553 553
         if self.virtual_disk_exists():
... ...
@@ -666,7 +650,7 @@ class ModuleManager(object):
666 666
 class ArgumentSpec(object):
667 667
     def __init__(self):
668 668
         self.supports_check_mode = True
669
-        self.argument_spec = dict(
669
+        argument_spec = dict(
670 670
             name=dict(required=True),
671 671
             vlans=dict(type='list'),
672 672
             mgmt_network=dict(choices=['bridged', 'isolated', 'host only']),
... ...
@@ -680,47 +664,41 @@ class ArgumentSpec(object):
680 680
             delete_virtual_disk=dict(
681 681
                 type='bool', default='no'
682 682
             ),
683
-            cores_per_slot=dict(type='int')
683
+            cores_per_slot=dict(type='int'),
684
+            partition=dict(
685
+                default='Common',
686
+                fallback=(env_fallback, ['F5_PARTITION'])
687
+            )
684 688
         )
685
-        self.f5_product_name = 'bigip'
689
+        self.argument_spec = {}
690
+        self.argument_spec.update(f5_argument_spec)
691
+        self.argument_spec.update(argument_spec)
686 692
         self.required_if = [
687 693
             ['mgmt_network', 'bridged', ['mgmt_address']]
688 694
         ]
689 695
 
690 696
 
691
-def cleanup_tokens(client):
692
-    try:
693
-        resource = client.api.shared.authz.tokens_s.token.load(
694
-            name=client.api.icrs.token
695
-        )
696
-        resource.delete()
697
-    except Exception:
698
-        pass
699
-
700
-
701 697
 def main():
702
-    if not HAS_F5SDK:
703
-        raise F5ModuleError("The python f5-sdk module is required")
704
-
705
-    if not HAS_NETADDR:
706
-        raise F5ModuleError("The python netaddr module is required")
707
-
708 698
     spec = ArgumentSpec()
709 699
 
710
-    client = AnsibleF5Client(
700
+    module = AnsibleModule(
711 701
         argument_spec=spec.argument_spec,
712
-        supports_check_mode=spec.supports_check_mode,
713
-        f5_product_name=spec.f5_product_name
702
+        supports_check_mode=spec.supports_check_mode
714 703
     )
704
+    if not HAS_F5SDK:
705
+        module.fail_json(msg="The python f5-sdk module is required")
706
+    if not HAS_NETADDR:
707
+        module.fail_json(msg="The python netaddr module is required")
715 708
 
716 709
     try:
717
-        mm = ModuleManager(client)
710
+        client = F5Client(**module.params)
711
+        mm = ModuleManager(module=module, client=client)
718 712
         results = mm.exec_module()
719 713
         cleanup_tokens(client)
720
-        client.module.exit_json(**results)
721
-    except F5ModuleError as e:
714
+        module.exit_json(**results)
715
+    except F5ModuleError as ex:
722 716
         cleanup_tokens(client)
723
-        client.module.fail_json(msg=str(e))
717
+        module.fail_json(msg=str(ex))
724 718
 
725 719
 
726 720
 if __name__ == '__main__':
... ...
@@ -100,14 +100,11 @@ options:
100 100
       - Specifies whether the system uses route advertisement for this
101 101
         virtual address. When disabled, the system does not advertise
102 102
         routes for this virtual address.
103
-    choices:
104
-      - yes
105
-      - no
103
+    type: bool
106 104
   partition:
107 105
     description:
108 106
       - Device partition to manage resources on.
109
-    required: False
110
-    default: 'Common'
107
+    default: Common
111 108
     version_added: 2.5
112 109
   traffic_group:
113 110
     description:
... ...
@@ -116,13 +113,10 @@ options:
116 116
         will be used.
117 117
     version_added: 2.5
118 118
 notes:
119
-  - Requires the f5-sdk Python package on the host. This is as easy as pip
120
-    install f5-sdk.
121 119
   - Requires the netaddr Python package on the host. This is as easy as pip
122 120
     install netaddr.
123 121
 extends_documentation_fragment: f5
124 122
 requirements:
125
-  - f5-sdk
126 123
   - netaddr
127 124
 author:
128 125
   - Tim Rupp (@caphrim007)
... ...
@@ -193,23 +187,46 @@ state:
193 193
   sample: disabled
194 194
 '''
195 195
 
196
-try:
197
-    import netaddr
198
-    HAS_NETADDR = True
199
-except ImportError:
200
-    HAS_NETADDR = False
201
-
202
-from ansible.module_utils.f5_utils import AnsibleF5Client
203
-from ansible.module_utils.f5_utils import AnsibleF5Parameters
204
-from ansible.module_utils.f5_utils import HAS_F5SDK
205
-from ansible.module_utils.f5_utils import F5ModuleError
196
+from ansible.module_utils.basic import AnsibleModule
197
+from ansible.module_utils.basic import env_fallback
206 198
 from ansible.module_utils.parsing.convert_bool import BOOLEANS_TRUE
207 199
 from ansible.module_utils.parsing.convert_bool import BOOLEANS_FALSE
208 200
 
201
+HAS_DEVEL_IMPORTS = False
202
+
209 203
 try:
210
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
204
+    # Sideband repository used for dev
205
+    from library.module_utils.network.f5.bigip import HAS_F5SDK
206
+    from library.module_utils.network.f5.bigip import F5Client
207
+    from library.module_utils.network.f5.common import F5ModuleError
208
+    from library.module_utils.network.f5.common import AnsibleF5Parameters
209
+    from library.module_utils.network.f5.common import cleanup_tokens
210
+    from library.module_utils.network.f5.common import fqdn_name
211
+    from library.module_utils.network.f5.common import f5_argument_spec
212
+    try:
213
+        from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
214
+    except ImportError:
215
+        HAS_F5SDK = False
216
+    HAS_DEVEL_IMPORTS = True
211 217
 except ImportError:
212
-    HAS_F5SDK = False
218
+    # Upstream Ansible
219
+    from ansible.module_utils.network.f5.bigip import HAS_F5SDK
220
+    from ansible.module_utils.network.f5.bigip import F5Client
221
+    from ansible.module_utils.network.f5.common import F5ModuleError
222
+    from ansible.module_utils.network.f5.common import AnsibleF5Parameters
223
+    from ansible.module_utils.network.f5.common import cleanup_tokens
224
+    from ansible.module_utils.network.f5.common import fqdn_name
225
+    from ansible.module_utils.network.f5.common import f5_argument_spec
226
+    try:
227
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
228
+    except ImportError:
229
+        HAS_F5SDK = False
230
+
231
+try:
232
+    import netaddr
233
+    HAS_NETADDR = True
234
+except ImportError:
235
+    HAS_NETADDR = False
213 236
 
214 237
 
215 238
 class Parameters(AnsibleF5Parameters):
... ...
@@ -349,17 +366,6 @@ class Parameters(AnsibleF5Parameters):
349 349
         result = self._filter_params(result)
350 350
         return result
351 351
 
352
-    def api_params(self):
353
-        result = {}
354
-        for api_attribute in self.api_attributes:
355
-            if api_attribute in self.api_map:
356
-                result[api_attribute] = getattr(
357
-                    self, self.api_map[api_attribute])
358
-            else:
359
-                result[api_attribute] = getattr(self, api_attribute)
360
-        result = self._filter_params(result)
361
-        return result
362
-
363 352
 
364 353
 class Changes(Parameters):
365 354
     pass
... ...
@@ -393,10 +399,11 @@ class Difference(object):
393 393
 
394 394
 
395 395
 class ModuleManager(object):
396
-    def __init__(self, client):
397
-        self.client = client
396
+    def __init__(self, *args, **kwargs):
397
+        self.module = kwargs.get('module', None)
398
+        self.client = kwargs.get('client', None)
398 399
         self.have = None
399
-        self.want = Parameters(self.client.module.params)
400
+        self.want = Parameters(client=self.client, params=self.module.params)
400 401
         self.changes = Changes()
401 402
 
402 403
     def _set_changed_options(self):
... ...
@@ -405,7 +412,7 @@ class ModuleManager(object):
405 405
             if getattr(self.want, key) is not None:
406 406
                 changed[key] = getattr(self.want, key)
407 407
         if changed:
408
-            self.changes = Changes(changed)
408
+            self.changes = Changes(params=changed)
409 409
 
410 410
     def _update_changed_options(self):
411 411
         diff = Difference(self.want, self.have)
... ...
@@ -421,7 +428,7 @@ class ModuleManager(object):
421 421
                 else:
422 422
                     changed[k] = change
423 423
         if changed:
424
-            self.changes = Changes(changed)
424
+            self.changes = Changes(params=changed)
425 425
             return True
426 426
         return False
427 427
 
... ...
@@ -467,7 +474,7 @@ class ModuleManager(object):
467 467
             partition=self.want.partition
468 468
         )
469 469
         result = resource.attrs
470
-        return Parameters(result)
470
+        return Parameters(params=result)
471 471
 
472 472
     def exists(self):
473 473
         result = self.client.api.tm.ltm.virtual_address_s.virtual_address.exists(
... ...
@@ -481,18 +488,18 @@ class ModuleManager(object):
481 481
         if self.want.netmask is not None:
482 482
             if self.have.netmask != self.want.netmask:
483 483
                 raise F5ModuleError(
484
-                    "The netmask cannot be changed. Delete and recreate"
484
+                    "The netmask cannot be changed. Delete and recreate "
485 485
                     "the virtual address if you need to do this."
486 486
                 )
487 487
         if self.want.address is not None:
488 488
             if self.have.address != self.want.address:
489 489
                 raise F5ModuleError(
490
-                    "The address cannot be changed. Delete and recreate"
490
+                    "The address cannot be changed. Delete and recreate "
491 491
                     "the virtual address if you need to do this."
492 492
                 )
493 493
         if not self.should_update():
494 494
             return False
495
-        if self.client.check_mode:
495
+        if self.module.check_mode:
496 496
             return True
497 497
         self.update_on_device()
498 498
         return True
... ...
@@ -509,7 +516,7 @@ class ModuleManager(object):
509 509
         self._set_changed_options()
510 510
         if self.want.traffic_group is None:
511 511
             self.want.update({'traffic_group': '/Common/traffic-group-1'})
512
-        if self.client.check_mode:
512
+        if self.module.check_mode:
513 513
             return True
514 514
         self.create_on_device()
515 515
         if self.exists():
... ...
@@ -527,7 +534,7 @@ class ModuleManager(object):
527 527
         )
528 528
 
529 529
     def remove(self):
530
-        if self.client.check_mode:
530
+        if self.module.check_mode:
531 531
             return True
532 532
         self.remove_from_device()
533 533
         if self.exists():
... ...
@@ -545,7 +552,7 @@ class ModuleManager(object):
545 545
 class ArgumentSpec(object):
546 546
     def __init__(self):
547 547
         self.supports_check_mode = True
548
-        self.argument_spec = dict(
548
+        argument_spec = dict(
549 549
             state=dict(
550 550
                 default='present',
551 551
                 choices=['present', 'absent', 'disabled', 'enabled']
... ...
@@ -577,29 +584,38 @@ class ArgumentSpec(object):
577 577
             use_route_advertisement=dict(
578 578
                 type='bool'
579 579
             ),
580
-            traffic_group=dict()
580
+            traffic_group=dict(),
581
+            partition=dict(
582
+                default='Common',
583
+                fallback=(env_fallback, ['F5_PARTITION'])
584
+            )
581 585
         )
582
-        self.f5_product_name = 'bigip'
586
+        self.argument_spec = {}
587
+        self.argument_spec.update(f5_argument_spec)
588
+        self.argument_spec.update(argument_spec)
583 589
 
584 590
 
585 591
 def main():
586
-    if not HAS_F5SDK:
587
-        raise F5ModuleError("The python f5-sdk module is required")
588
-
589 592
     spec = ArgumentSpec()
590 593
 
591
-    client = AnsibleF5Client(
594
+    module = AnsibleModule(
592 595
         argument_spec=spec.argument_spec,
593
-        supports_check_mode=spec.supports_check_mode,
594
-        f5_product_name=spec.f5_product_name
596
+        supports_check_mode=spec.supports_check_mode
595 597
     )
598
+    if not HAS_F5SDK:
599
+        module.fail_json(msg="The python f5-sdk module is required")
600
+    if not HAS_NETADDR:
601
+        module.fail_json(msg="The python netaddr module is required")
596 602
 
597 603
     try:
598
-        mm = ModuleManager(client)
604
+        client = F5Client(**module.params)
605
+        mm = ModuleManager(module=module, client=client)
599 606
         results = mm.exec_module()
600
-        client.module.exit_json(**results)
601
-    except F5ModuleError as e:
602
-        client.module.fail_json(msg=str(e))
607
+        cleanup_tokens(client)
608
+        module.exit_json(**results)
609
+    except F5ModuleError as ex:
610
+        cleanup_tokens(client)
611
+        module.fail_json(msg=str(ex))
603 612
 
604 613
 
605 614
 if __name__ == '__main__':
... ...
@@ -137,14 +137,6 @@ options:
137 137
       - Default Profile which manages the session persistence.
138 138
       - If you want to remove the existing default persistence profile, specify an
139 139
         empty value; C(""). See the documentation for an example.
140
-  route_advertisement_state:
141
-    description:
142
-      - Enable route advertisement for destination.
143
-      - Deprecated in 2.4. Use the C(bigip_virtual_address) module instead.
144
-    choices:
145
-      - enabled
146
-      - disabled
147
-    version_added: "2.3"
148 140
   description:
149 141
     description:
150 142
       - Virtual server description.
... ...
@@ -171,12 +163,9 @@ options:
171 171
     version_added: 2.5
172 172
 notes:
173 173
   - Requires BIG-IP software version >= 11
174
-  - Requires the f5-sdk Python package on the host. This is as easy as pip
175
-    install f5-sdk.
176 174
   - Requires the netaddr Python package on the host. This is as easy as pip
177 175
     install netaddr.
178 176
 requirements:
179
-  - f5-sdk
180 177
   - netaddr
181 178
 extends_documentation_fragment: f5
182 179
 author:
... ...
@@ -381,18 +370,38 @@ metadata:
381 381
 
382 382
 import re
383 383
 
384
-from ansible.module_utils.f5_utils import AnsibleF5Client
385
-from ansible.module_utils.f5_utils import AnsibleF5Parameters
386
-from ansible.module_utils.f5_utils import HAS_F5SDK
387
-from ansible.module_utils.f5_utils import F5ModuleError
384
+from ansible.module_utils.basic import AnsibleModule
385
+from ansible.module_utils.basic import env_fallback
388 386
 from ansible.module_utils.six import iteritems
389
-from collections import defaultdict
390 387
 from collections import namedtuple
391 388
 
392 389
 try:
393
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
390
+    # Sideband repository used for dev
391
+    from library.module_utils.network.f5.bigip import HAS_F5SDK
392
+    from library.module_utils.network.f5.bigip import F5Client
393
+    from library.module_utils.network.f5.common import F5ModuleError
394
+    from library.module_utils.network.f5.common import AnsibleF5Parameters
395
+    from library.module_utils.network.f5.common import cleanup_tokens
396
+    from library.module_utils.network.f5.common import fqdn_name
397
+    from library.module_utils.network.f5.common import f5_argument_spec
398
+    try:
399
+        from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
400
+    except ImportError:
401
+        HAS_F5SDK = False
402
+    HAS_DEVEL_IMPORTS = True
394 403
 except ImportError:
395
-    HAS_F5SDK = False
404
+    # Upstream Ansible
405
+    from ansible.module_utils.network.f5.bigip import HAS_F5SDK
406
+    from ansible.module_utils.network.f5.bigip import F5Client
407
+    from ansible.module_utils.network.f5.common import F5ModuleError
408
+    from ansible.module_utils.network.f5.common import AnsibleF5Parameters
409
+    from ansible.module_utils.network.f5.common import cleanup_tokens
410
+    from ansible.module_utils.network.f5.common import fqdn_name
411
+    from ansible.module_utils.network.f5.common import f5_argument_spec
412
+    try:
413
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
414
+    except ImportError:
415
+        HAS_F5SDK = False
396 416
 
397 417
 try:
398 418
     import netaddr
... ...
@@ -402,100 +411,6 @@ except ImportError:
402 402
 
403 403
 
404 404
 class Parameters(AnsibleF5Parameters):
405
-    def __init__(self, params=None):
406
-        self._values = defaultdict(lambda: None)
407
-        if params:
408
-            self.update(params=params)
409
-
410
-    def update(self, params=None):
411
-        if params:
412
-            for k, v in iteritems(params):
413
-                if self.api_map is not None and k in self.api_map:
414
-                    map_key = self.api_map[k]
415
-                else:
416
-                    map_key = k
417
-
418
-                # Handle weird API parameters like `dns.proxy.__iter__` by
419
-                # using a map provided by the module developer
420
-                class_attr = getattr(type(self), map_key, None)
421
-                if isinstance(class_attr, property):
422
-                    # There is a mapped value for the api_map key
423
-                    if class_attr.fset is None:
424
-                        # If the mapped value does not have
425
-                        # an associated setter
426
-                        self._values[map_key] = v
427
-                    else:
428
-                        # The mapped value has a setter
429
-                        setattr(self, map_key, v)
430
-                else:
431
-                    # If the mapped value is not a @property
432
-                    self._values[map_key] = v
433
-
434
-    def to_return(self):
435
-        result = {}
436
-        for returnable in self.returnables:
437
-            try:
438
-                result[returnable] = getattr(self, returnable)
439
-            except Exception as ex:
440
-                pass
441
-        result = self._filter_params(result)
442
-        return result
443
-
444
-    def _fqdn_name(self, value):
445
-        if value is not None and not value.startswith('/'):
446
-            return '/{0}/{1}'.format(self.partition, value)
447
-        return value
448
-
449
-    def api_params(self):
450
-        result = {}
451
-        for api_attribute in self.api_attributes:
452
-            if self.api_map is not None and api_attribute in self.api_map:
453
-                result[api_attribute] = getattr(self, self.api_map[api_attribute])
454
-            else:
455
-                result[api_attribute] = getattr(self, api_attribute)
456
-        result = self._filter_params(result)
457
-        return result
458
-
459
-
460
-class VirtualAddressParameters(Parameters):
461
-    api_map = {
462
-        'routeAdvertisement': 'route_advertisement_state'
463
-    }
464
-    returnables = [
465
-        'route_advertisement_state'
466
-    ]
467
-
468
-    updatables = [
469
-        'route_advertisement_state'
470
-    ]
471
-
472
-    api_attributes = [
473
-        'routeAdvertisement'
474
-    ]
475
-
476
-
477
-class VirtualAddressModuleParameters(VirtualAddressParameters):
478
-    @property
479
-    def route_advertisement_state(self):
480
-        # TODO: Remove in 2.5
481
-        if self._values['route_advertisement_state'] is None:
482
-            return None
483
-        if self._values['__warnings'] is None:
484
-            self._values['__warnings'] = []
485
-        self._values['__warnings'].append(
486
-            dict(
487
-                msg="Usage of the 'route_advertisement_state' parameter is deprecated. Use the bigip_virtual_address module instead",
488
-                version='2.4'
489
-            )
490
-        )
491
-        return str(self._values['route_advertisement_state'])
492
-
493
-
494
-class VirtualAddressApiParameters(VirtualAddressParameters):
495
-    pass
496
-
497
-
498
-class VirtualServerParameters(Parameters):
499 405
     api_map = {
500 406
         'sourceAddressTranslation': 'snat',
501 407
         'fallbackPersistence': 'fallback_persistence_profile',
... ...
@@ -566,12 +481,25 @@ class VirtualServerParameters(Parameters):
566 566
         'vlans_disabled'
567 567
     ]
568 568
 
569
-    def __init__(self, params=None):
570
-        super(VirtualServerParameters, self).__init__(params)
571
-        self.profiles_mutex = [
572
-            'sip', 'sipsession', 'iiop', 'rtsp', 'http', 'diameter',
573
-            'diametersession', 'radius', 'ftp', 'tftp', 'dns', 'pptp', 'fix'
574
-        ]
569
+    profiles_mutex = [
570
+        'sip', 'sipsession', 'iiop', 'rtsp', 'http', 'diameter',
571
+        'diametersession', 'radius', 'ftp', 'tftp', 'dns', 'pptp', 'fix'
572
+    ]
573
+
574
+    def to_return(self):
575
+        result = {}
576
+        for returnable in self.returnables:
577
+            try:
578
+                result[returnable] = getattr(self, returnable)
579
+            except Exception as ex:
580
+                pass
581
+        result = self._filter_params(result)
582
+        return result
583
+
584
+    def _fqdn_name(self, value):
585
+        if value is not None and not value.startswith('/'):
586
+            return '/{0}/{1}'.format(self.partition, value)
587
+        return value
575 588
 
576 589
     def is_valid_ip(self, value):
577 590
         try:
... ...
@@ -618,7 +546,7 @@ class VirtualServerParameters(Parameters):
618 618
         return result
619 619
 
620 620
 
621
-class VirtualServerApiParameters(VirtualServerParameters):
621
+class ApiParameters(Parameters):
622 622
     @property
623 623
     def destination(self):
624 624
         if self._values['destination'] is None:
... ...
@@ -648,7 +576,7 @@ class VirtualServerApiParameters(VirtualServerParameters):
648 648
         if self._values['destination'] is None:
649 649
             result = Destination(ip=None, port=None, route_domain=None)
650 650
             return result
651
-        destination = re.sub(r'^/[a-zA-Z_.-]+/', '', self._values['destination'])
651
+        destination = re.sub(r'^/[a-zA-Z0-9_.-]+/', '', self._values['destination'])
652 652
 
653 653
         if self.is_valid_ip(destination):
654 654
             result = Destination(
... ...
@@ -816,7 +744,7 @@ class VirtualServerApiParameters(VirtualServerParameters):
816 816
         return result
817 817
 
818 818
 
819
-class VirtualServerModuleParameters(VirtualServerParameters):
819
+class ModuleParameters(Parameters):
820 820
     def _handle_profile_context(self, tmp):
821 821
         if 'context' not in tmp:
822 822
             tmp['context'] = 'all'
... ...
@@ -1106,7 +1034,11 @@ class VirtualServerModuleParameters(VirtualServerParameters):
1106 1106
         return result
1107 1107
 
1108 1108
 
1109
-class VirtualServerUsableChanges(VirtualServerParameters):
1109
+class Changes(Parameters):
1110
+    pass
1111
+
1112
+
1113
+class UsableChanges(Changes):
1110 1114
     @property
1111 1115
     def vlans(self):
1112 1116
         if self._values['vlans'] is None:
... ...
@@ -1118,11 +1050,7 @@ class VirtualServerUsableChanges(VirtualServerParameters):
1118 1118
         return self._values['vlans']
1119 1119
 
1120 1120
 
1121
-class VirtualAddressUsableChanges(VirtualAddressParameters):
1122
-    pass
1123
-
1124
-
1125
-class VirtualServerReportableChanges(VirtualServerParameters):
1121
+class ReportableChanges(Changes):
1126 1122
     @property
1127 1123
     def snat(self):
1128 1124
         if self._values['snat'] is None:
... ...
@@ -1137,13 +1065,13 @@ class VirtualServerReportableChanges(VirtualServerParameters):
1137 1137
 
1138 1138
     @property
1139 1139
     def destination(self):
1140
-        params = VirtualServerApiParameters(dict(destination=self._values['destination']))
1140
+        params = ApiParameters(params=dict(destination=self._values['destination']))
1141 1141
         result = params.destination_tuple.ip
1142 1142
         return result
1143 1143
 
1144 1144
     @property
1145 1145
     def port(self):
1146
-        params = VirtualServerApiParameters(dict(destination=self._values['destination']))
1146
+        params = ApiParameters(params=dict(destination=self._values['destination']))
1147 1147
         result = params.destination_tuple.port
1148 1148
         return result
1149 1149
 
... ...
@@ -1175,10 +1103,6 @@ class VirtualServerReportableChanges(VirtualServerParameters):
1175 1175
             return self._values['vlans']
1176 1176
 
1177 1177
 
1178
-class VirtualAddressReportableChanges(VirtualAddressParameters):
1179
-    pass
1180
-
1181
-
1182 1178
 class Difference(object):
1183 1179
     def __init__(self, want, have=None):
1184 1180
         self.have = have
... ...
@@ -1461,49 +1385,12 @@ class Difference(object):
1461 1461
 
1462 1462
 
1463 1463
 class ModuleManager(object):
1464
-    def __init__(self, client):
1465
-        self.client = client
1466
-
1467
-    def exec_module(self):
1468
-        managers = list()
1469
-        managers.append(self.get_manager('virtual_server'))
1470
-        if self.client.module.params['route_advertisement_state'] is not None:
1471
-            managers.append(self.get_manager('virtual_address'))
1472
-        result = self.execute_managers(managers)
1473
-        return result
1474
-
1475
-    def execute_managers(self, managers):
1476
-        results = dict(changed=False)
1477
-        for manager in managers:
1478
-            result = manager.exec_module()
1479
-            for k, v in iteritems(result):
1480
-                if k == 'changed':
1481
-                    if v is True:
1482
-                        results['changed'] = True
1483
-                else:
1484
-                    results[k] = v
1485
-        return results
1486
-
1487
-    def get_manager(self, type):
1488
-        vsm = VirtualServerManager(self.client)
1489
-        if type == 'virtual_server':
1490
-            return vsm
1491
-        elif type == 'virtual_address':
1492
-            self.set_name_of_virtual_address()
1493
-            result = VirtualAddressManager(self.client)
1494
-            return result
1495
-
1496
-    def set_name_of_virtual_address(self):
1497
-        mgr = VirtualServerManager(self.client)
1498
-        params = mgr.read_current_from_device()
1499
-        destination = params.destination_tuple
1500
-        self.client.module.params['name'] = destination.ip
1501
-
1502
-
1503
-class BaseManager(object):
1504
-    def __init__(self, client):
1505
-        self.client = client
1506
-        self.have = None
1464
+    def __init__(self, *args, **kwargs):
1465
+        self.module = kwargs.get('module', None)
1466
+        self.client = kwargs.get('client', None)
1467
+        self.have = ApiParameters()
1468
+        self.want = ModuleParameters(client=self.client, params=self.module.params)
1469
+        self.changes = UsableChanges()
1507 1470
 
1508 1471
     def exec_module(self):
1509 1472
         changed = False
... ...
@@ -1518,7 +1405,7 @@ class BaseManager(object):
1518 1518
         except iControlUnexpectedHTTPError as e:
1519 1519
             raise F5ModuleError(str(e))
1520 1520
 
1521
-        reportable = self.get_reportable_changes()
1521
+        reportable = ReportableChanges(params=self.changes.to_return())
1522 1522
         changes = reportable.to_return()
1523 1523
         result.update(**changes)
1524 1524
         result.update(dict(changed=changed))
... ...
@@ -1528,7 +1415,7 @@ class BaseManager(object):
1528 1528
     def _announce_deprecations(self, result):
1529 1529
         warnings = result.pop('__warnings', [])
1530 1530
         for warning in warnings:
1531
-            self.client.module.deprecate(
1531
+            self.module.deprecate(
1532 1532
                 msg=warning['msg'],
1533 1533
                 version=warning['version']
1534 1534
             )
... ...
@@ -1548,23 +1435,11 @@ class BaseManager(object):
1548 1548
         self.have = self.read_current_from_device()
1549 1549
         if not self.should_update():
1550 1550
             return False
1551
-        if self.client.check_mode:
1551
+        if self.module.check_mode:
1552 1552
             return True
1553 1553
         self.update_on_device()
1554 1554
         return True
1555 1555
 
1556
-    def create(self):
1557
-        if self.client.check_mode:
1558
-            return True
1559
-
1560
-        # This must be changed back to a list to make a valid REST API
1561
-        # value. The module manipulates this as a normal dictionary
1562
-        if self.want.default_persistence_profile is not None:
1563
-            self.want.update({'default_persistence_profile': [self.want.default_persistence_profile]})
1564
-
1565
-        self.create_on_device()
1566
-        return True
1567
-
1568 1556
     def should_update(self):
1569 1557
         result = self._update_changed_options()
1570 1558
         if result:
... ...
@@ -1572,36 +1447,28 @@ class BaseManager(object):
1572 1572
         return False
1573 1573
 
1574 1574
     def remove(self):
1575
-        if self.client.check_mode:
1575
+        if self.module.check_mode:
1576 1576
             return True
1577 1577
         self.remove_from_device()
1578 1578
         if self.exists():
1579 1579
             raise F5ModuleError("Failed to delete the resource")
1580 1580
         return True
1581 1581
 
1582
-
1583
-class VirtualServerManager(BaseManager):
1584
-    def __init__(self, client):
1585
-        super(VirtualServerManager, self).__init__(client)
1586
-        self.have = None
1587
-        self.want = VirtualServerModuleParameters(self.client.module.params)
1588
-        self.changes = VirtualServerUsableChanges()
1589
-
1590 1582
     def get_reportable_changes(self):
1591
-        result = VirtualServerReportableChanges(self.changes.to_return())
1583
+        result = ReportableChanges(params=self.changes.to_return())
1592 1584
         return result
1593 1585
 
1594 1586
     def _set_changed_options(self):
1595 1587
         changed = {}
1596
-        for key in VirtualServerParameters.returnables:
1588
+        for key in Parameters.returnables:
1597 1589
             if getattr(self.want, key) is not None:
1598 1590
                 changed[key] = getattr(self.want, key)
1599 1591
         if changed:
1600
-            self.changes = VirtualServerUsableChanges(changed)
1592
+            self.changes = UsableChanges(params=changed)
1601 1593
 
1602 1594
     def _update_changed_options(self):
1603 1595
         diff = Difference(self.want, self.have)
1604
-        updatables = VirtualServerParameters.updatables
1596
+        updatables = Parameters.updatables
1605 1597
         changed = dict()
1606 1598
         for k in updatables:
1607 1599
             change = diff.compare(k)
... ...
@@ -1613,7 +1480,7 @@ class VirtualServerManager(BaseManager):
1613 1613
                 else:
1614 1614
                     changed[k] = change
1615 1615
         if changed:
1616
-            self.changes = VirtualServerUsableChanges(changed)
1616
+            self.changes = UsableChanges(params=changed)
1617 1617
             return True
1618 1618
         return False
1619 1619
 
... ...
@@ -1628,6 +1495,11 @@ class VirtualServerManager(BaseManager):
1628 1628
         required_resources = ['destination', 'port']
1629 1629
 
1630 1630
         self._set_changed_options()
1631
+        # This must be changed back to a list to make a valid REST API
1632
+        # value. The module manipulates this as a normal dictionary
1633
+        if self.want.default_persistence_profile is not None:
1634
+            self.want.update({'default_persistence_profile': [self.want.default_persistence_profile]})
1635
+
1631 1636
         if self.want.destination is None:
1632 1637
             raise F5ModuleError(
1633 1638
                 "'destination' must be specified when creating a virtual server"
... ...
@@ -1652,7 +1524,10 @@ class VirtualServerManager(BaseManager):
1652 1652
                 raise F5ModuleError(
1653 1653
                     "The source and destination addresses for the virtual server must be be the same type (IPv4 or IPv6)."
1654 1654
                 )
1655
-        return super(VirtualServerManager, self).create()
1655
+        if self.module.check_mode:
1656
+            return True
1657
+        self.create_on_device()
1658
+        return True
1656 1659
 
1657 1660
     def update_on_device(self):
1658 1661
         params = self.changes.api_params()
... ...
@@ -1674,7 +1549,7 @@ class VirtualServerManager(BaseManager):
1674 1674
         )
1675 1675
         params = result.attrs
1676 1676
         params.update(dict(kind=result.to_dict().get('kind', None)))
1677
-        result = VirtualServerApiParameters(params)
1677
+        result = ApiParameters(params=params)
1678 1678
         return result
1679 1679
 
1680 1680
     def create_on_device(self):
... ...
@@ -1694,71 +1569,10 @@ class VirtualServerManager(BaseManager):
1694 1694
             resource.delete()
1695 1695
 
1696 1696
 
1697
-class VirtualAddressManager(BaseManager):
1698
-    def __init__(self, client):
1699
-        super(VirtualAddressManager, self).__init__(client)
1700
-        self.want = VirtualAddressModuleParameters(self.client.module.params)
1701
-        self.have = VirtualAddressApiParameters()
1702
-        self.changes = VirtualAddressUsableChanges()
1703
-
1704
-    def get_reportable_changes(self):
1705
-        result = VirtualAddressReportableChanges(self.changes.to_return())
1706
-        return result
1707
-
1708
-    def _set_changed_options(self):
1709
-        changed = {}
1710
-        for key in VirtualAddressParameters.returnables:
1711
-            if getattr(self.want, key) is not None:
1712
-                changed[key] = getattr(self.want, key)
1713
-        if changed:
1714
-            self.changes = VirtualAddressUsableChanges(changed)
1715
-
1716
-    def _update_changed_options(self):
1717
-        diff = Difference(self.want, self.have)
1718
-        updatables = VirtualAddressParameters.updatables
1719
-        changed = dict()
1720
-        for k in updatables:
1721
-            change = diff.compare(k)
1722
-            if change is None:
1723
-                continue
1724
-            else:
1725
-                if isinstance(change, dict):
1726
-                    changed.update(change)
1727
-                else:
1728
-                    changed[k] = change
1729
-        if changed:
1730
-            self.changes = VirtualAddressUsableChanges(changed)
1731
-            return True
1732
-        return False
1733
-
1734
-    def read_current_from_device(self):
1735
-        result = self.client.api.tm.ltm.virtual_address_s.virtual_address.load(
1736
-            name=self.want.name,
1737
-            partition=self.want.partition
1738
-        )
1739
-        result = VirtualAddressParameters(result.attrs)
1740
-        return result
1741
-
1742
-    def update_on_device(self):
1743
-        params = self.want.api_params()
1744
-        resource = self.client.api.tm.ltm.virtual_address_s.virtual_address.load(
1745
-            name=self.want.name,
1746
-            partition=self.want.partition
1747
-        )
1748
-        resource.modify(**params)
1749
-
1750
-    def exists(self):
1751
-        result = self.client.api.tm.ltm.virtual_address_s.virtual_address.exists(
1752
-            name=self.want.name,
1753
-            partition=self.want.partition
1754
-        )
1755
-        return result
1756
-
1757
-
1758 1697
 class ArgumentSpec(object):
1759 1698
     def __init__(self):
1760 1699
         self.supports_check_mode = True
1761
-        self.argument_spec = dict(
1700
+        argument_spec = dict(
1762 1701
             state=dict(
1763 1702
                 default='present',
1764 1703
                 choices=['present', 'absent', 'disabled', 'enabled']
... ...
@@ -1798,54 +1612,45 @@ class ArgumentSpec(object):
1798 1798
             pool=dict(),
1799 1799
             description=dict(),
1800 1800
             snat=dict(),
1801
-            route_advertisement_state=dict(
1802
-                choices=['enabled', 'disabled']
1803
-            ),
1804 1801
             default_persistence_profile=dict(),
1805 1802
             fallback_persistence_profile=dict(),
1806 1803
             source=dict(),
1807
-            metadata=dict(type='raw')
1804
+            metadata=dict(type='raw'),
1805
+            partition=dict(
1806
+                default='Common',
1807
+                fallback=(env_fallback, ['F5_PARTITION'])
1808
+            )
1808 1809
         )
1809
-        self.f5_product_name = 'bigip'
1810
+        self.argument_spec = {}
1811
+        self.argument_spec.update(f5_argument_spec)
1812
+        self.argument_spec.update(argument_spec)
1810 1813
         self.mutually_exclusive = [
1811 1814
             ['enabled_vlans', 'disabled_vlans']
1812 1815
         ]
1813 1816
 
1814 1817
 
1815
-def cleanup_tokens(client):
1816
-    try:
1817
-        resource = client.api.shared.authz.tokens_s.token.load(
1818
-            name=client.api.icrs.token
1819
-        )
1820
-        resource.delete()
1821
-    except Exception:
1822
-        pass
1823
-
1824
-
1825 1818
 def main():
1826
-    if not HAS_F5SDK:
1827
-        raise F5ModuleError("The python f5-sdk module is required")
1828
-
1829
-    if not HAS_NETADDR:
1830
-        raise F5ModuleError("The python netaddr module is required")
1831
-
1832 1819
     spec = ArgumentSpec()
1833 1820
 
1834
-    client = AnsibleF5Client(
1821
+    module = AnsibleModule(
1835 1822
         argument_spec=spec.argument_spec,
1836 1823
         supports_check_mode=spec.supports_check_mode,
1837
-        f5_product_name=spec.f5_product_name,
1838 1824
         mutually_exclusive=spec.mutually_exclusive
1839 1825
     )
1826
+    if not HAS_F5SDK:
1827
+        module.fail_json(msg="The python f5-sdk module is required")
1828
+    if not HAS_NETADDR:
1829
+        module.fail_json(msg="The python netaddr module is required")
1840 1830
 
1841 1831
     try:
1842
-        mm = ModuleManager(client)
1832
+        client = F5Client(**module.params)
1833
+        mm = ModuleManager(module=module, client=client)
1843 1834
         results = mm.exec_module()
1844 1835
         cleanup_tokens(client)
1845
-        client.module.exit_json(**results)
1846
-    except F5ModuleError as e:
1836
+        module.exit_json(**results)
1837
+    except F5ModuleError as ex:
1847 1838
         cleanup_tokens(client)
1848
-        client.module.fail_json(msg=str(e))
1839
+        module.fail_json(msg=str(ex))
1849 1840
 
1850 1841
 
1851 1842
 if __name__ == '__main__':
... ...
@@ -55,13 +55,46 @@ options:
55 55
       - Tag number for the VLAN. The tag number can be any integer between 1
56 56
         and 4094. The system automatically assigns a tag number if you do not
57 57
         specify a value.
58
+  mtu:
59
+    description:
60
+      - Specifies the maximum transmission unit (MTU) for traffic on this VLAN.
61
+        When creating a new VLAN, if this parameter is not specified, the default
62
+        value used will be C(1500).
63
+      - This number must be between 576 to 9198.
64
+    version_added: 2.5
65
+  cmp_hash:
66
+    description:
67
+      - Specifies how the traffic on the VLAN will be disaggregated. The value
68
+        selected determines the traffic disaggregation method. You can choose to
69
+        disaggregate traffic based on C(source-address) (the source IP address),
70
+        C(destination-address) (destination IP address), or C(default), which
71
+        specifies that the default CMP hash uses L4 ports.
72
+      - When creating a new VLAN, if this parameter is not specified, the default
73
+        of C(default) is used.
74
+    version_added: 2.5
75
+  dag_tunnel:
76
+    description:
77
+      - Specifies how the disaggregator (DAG) distributes received tunnel-encapsulated
78
+        packets to TMM instances. Select C(inner) to distribute packets based on information
79
+        in inner headers. Select C(outer) to distribute packets based on information in
80
+        outer headers without inspecting inner headers.
81
+      - When creating a new VLAN, if this parameter is not specified, the default
82
+        of C(outer) is used.
83
+      - This parameter is not supported on Virtual Editions of BIG-IP.
84
+    version_added: 2.5
85
+  dag_round_robin:
86
+    description:
87
+      - Specifies whether some of the stateless traffic on the VLAN should be
88
+        disaggregated in a round-robin order instead of using a static hash. The
89
+        stateless traffic includes non-IP L2 traffic, ICMP, some UDP protocols,
90
+        and so on.
91
+      - When creating a new VLAN, if this parameter is not specified, the default
92
+        of (no) is used.
93
+    version_added: 2.5
94
+    choices: [yes, no]
58 95
 notes:
59
-  - Requires the f5-sdk Python package on the host. This is as easy as pip
60
-    install f5-sdk.
61 96
   - Requires BIG-IP versions >= 12.0.0
62 97
 extends_documentation_fragment: f5
63
-requirements:
64
-  - f5-sdk
65 98
 author:
66 99
   - Tim Rupp (@caphrim007)
67 100
   - Wojciech Wypior (@wojtek0806)
... ...
@@ -114,162 +147,296 @@ EXAMPLES = r'''
114 114
 
115 115
 RETURN = r'''
116 116
 description:
117
-    description: The description set on the VLAN
118
-    returned: changed
119
-    type: string
120
-    sample: foo VLAN
117
+  description: The description set on the VLAN.
118
+  returned: changed
119
+  type: string
120
+  sample: foo VLAN
121 121
 interfaces:
122
-    description: Interfaces that the VLAN is assigned to
123
-    returned: changed
124
-    type: list
125
-    sample: ['1.1','1.2']
126
-name:
127
-    description: The name of the VLAN
128
-    returned: changed
129
-    type: string
130
-    sample: net1
122
+  description: Interfaces that the VLAN is assigned to.
123
+  returned: changed
124
+  type: list
125
+  sample: ['1.1','1.2']
131 126
 partition:
132
-    description: The partition that the VLAN was created on
133
-    returned: changed
134
-    type: string
135
-    sample: Common
127
+  description: The partition that the VLAN was created on.
128
+  returned: changed
129
+  type: string
130
+  sample: Common
136 131
 tag:
137
-    description: The ID of the VLAN
138
-    returned: changed
139
-    type: int
140
-    sample: 2345
132
+  description: The ID of the VLAN.
133
+  returned: changed
134
+  type: int
135
+  sample: 2345
136
+cmp_hash:
137
+  description: New traffic disaggregation method.
138
+  returned: changed
139
+  type: string
140
+  sample: source-address
141
+dag_tunnel:
142
+  description: The new DAG tunnel setting.
143
+  returned: changed
144
+  type: string
145
+  sample: outer
141 146
 '''
142 147
 
143
-from ansible.module_utils.f5_utils import AnsibleF5Client
144
-from ansible.module_utils.f5_utils import AnsibleF5Parameters
145
-from ansible.module_utils.f5_utils import HAS_F5SDK
146
-from ansible.module_utils.f5_utils import F5ModuleError
147
-from ansible.module_utils.six import iteritems
148
-from collections import defaultdict
148
+from ansible.module_utils.basic import AnsibleModule
149
+from ansible.module_utils.basic import env_fallback
149 150
 
150 151
 try:
151
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
152
+    # Sideband repository used for dev
153
+    from library.module_utils.network.f5.bigip import HAS_F5SDK
154
+    from library.module_utils.network.f5.bigip import F5Client
155
+    from library.module_utils.network.f5.common import F5ModuleError
156
+    from library.module_utils.network.f5.common import AnsibleF5Parameters
157
+    from library.module_utils.network.f5.common import cleanup_tokens
158
+    from library.module_utils.network.f5.common import fqdn_name
159
+    from library.module_utils.network.f5.common import f5_argument_spec
160
+    try:
161
+        from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
162
+    except ImportError:
163
+        HAS_F5SDK = False
164
+    HAS_DEVEL_IMPORTS = True
152 165
 except ImportError:
153
-    HAS_F5SDK = False
166
+    # Upstream Ansible
167
+    from ansible.module_utils.network.f5.bigip import HAS_F5SDK
168
+    from ansible.module_utils.network.f5.bigip import F5Client
169
+    from ansible.module_utils.network.f5.common import F5ModuleError
170
+    from ansible.module_utils.network.f5.common import AnsibleF5Parameters
171
+    from ansible.module_utils.network.f5.common import cleanup_tokens
172
+    from ansible.module_utils.network.f5.common import fqdn_name
173
+    from ansible.module_utils.network.f5.common import f5_argument_spec
174
+    try:
175
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
176
+    except ImportError:
177
+        HAS_F5SDK = False
154 178
 
155 179
 
156 180
 class Parameters(AnsibleF5Parameters):
157
-    def __init__(self, params=None):
158
-        self._values = defaultdict(lambda: None)
159
-        if params:
160
-            self.update(params=params)
161
-
162
-    def update(self, params=None):
163
-        if params:
164
-            for k, v in iteritems(params):
165
-                if self.api_map is not None and k in self.api_map:
166
-                    map_key = self.api_map[k]
167
-                else:
168
-                    map_key = k
169
-
170
-                # Handle weird API parameters like `dns.proxy.__iter__` by
171
-                # using a map provided by the module developer
172
-                class_attr = getattr(type(self), map_key, None)
173
-                if isinstance(class_attr, property):
174
-                    # There is a mapped value for the api_map key
175
-                    if class_attr.fset is None:
176
-                        # If the mapped value does not have
177
-                        # an associated setter
178
-                        self._values[map_key] = v
179
-                    else:
180
-                        # The mapped value has a setter
181
-                        setattr(self, map_key, v)
182
-                else:
183
-                    # If the mapped value is not a @property
184
-                    self._values[map_key] = v
181
+    api_map = {
182
+        'cmpHash': 'cmp_hash',
183
+        'dagTunnel': 'dag_tunnel',
184
+        'dagRoundRobin': 'dag_round_robin'
185
+    }
185 186
 
186 187
     updatables = [
187 188
         'tagged_interfaces', 'untagged_interfaces', 'tag',
188
-        'description'
189
+        'description', 'mtu', 'cmp_hash', 'dag_tunnel',
190
+        'dag_round_robin'
189 191
     ]
190 192
 
191 193
     returnables = [
192
-        'description', 'partition', 'name', 'tag', 'interfaces',
193
-        'tagged_interfaces', 'untagged_interfaces'
194
+        'description', 'partition', 'tag', 'interfaces',
195
+        'tagged_interfaces', 'untagged_interfaces', 'mtu',
196
+        'cmp_hash', 'dag_tunnel', 'dag_round_robin'
194 197
     ]
195 198
 
196 199
     api_attributes = [
197
-        'description', 'interfaces', 'partition', 'name', 'tag'
200
+        'description', 'interfaces', 'tag', 'mtu', 'cmpHash',
201
+        'dagTunnel', 'dagRoundRobin'
198 202
     ]
199
-    api_map = {}
200 203
 
201
-    @property
202
-    def interfaces(self):
203
-        tagged = self._values['tagged_interfaces']
204
-        untagged = self._values['untagged_interfaces']
205
-        if tagged:
206
-            return [dict(name=x, tagged=True) for x in tagged]
207
-        if untagged:
208
-            return [dict(name=x, untagged=True) for x in untagged]
204
+    def to_return(self):
205
+        result = {}
206
+        for returnable in self.returnables:
207
+            result[returnable] = getattr(self, returnable)
208
+        result = self._filter_params(result)
209
+        return result
209 210
 
211
+
212
+class ApiParameters(Parameters):
210 213
     @property
211 214
     def tagged_interfaces(self):
212
-        value = self._values['tagged_interfaces']
213
-        if value is None:
215
+        if self._values['interfaces'] is None:
216
+            return None
217
+        result = [str(x.name) for x in self._values['interfaces'] if x.tagged is True]
218
+        result = sorted(result)
219
+        return result
220
+
221
+    @property
222
+    def untagged_interfaces(self):
223
+        if self._values['interfaces'] is None:
214 224
             return None
215
-        ifcs = self._parse_return_ifcs()
216
-        for ifc in value:
217
-            if ifc not in ifcs:
218
-                err = 'The specified interface "%s" was not found' % ifc
219
-                raise F5ModuleError(err)
220
-        return value
225
+        result = [str(x.name) for x in self._values['interfaces'] if x.untagged is True]
226
+        result = sorted(result)
227
+        return result
228
+
221 229
 
230
+class ModuleParameters(Parameters):
222 231
     @property
223 232
     def untagged_interfaces(self):
224
-        value = self._values['untagged_interfaces']
225
-        if value is None:
233
+        if self._values['untagged_interfaces'] is None:
234
+            return None
235
+        if self._values['untagged_interfaces'] is None:
236
+            return None
237
+        if len(self._values['untagged_interfaces']) == 1 and self._values['untagged_interfaces'][0] == '':
238
+            return ''
239
+        result = sorted([str(x) for x in self._values['untagged_interfaces']])
240
+        return result
241
+
242
+    @property
243
+    def tagged_interfaces(self):
244
+        if self._values['tagged_interfaces'] is None:
245
+            return None
246
+        if self._values['tagged_interfaces'] is None:
226 247
             return None
227
-        ifcs = self._parse_return_ifcs()
228
-        for ifc in value:
229
-            if ifc not in ifcs:
230
-                err = 'The specified interface "%s" was not found' % ifc
231
-                raise F5ModuleError(err)
232
-        return value
233
-
234
-    def _get_interfaces_from_device(self):
235
-        lst = self.client.api.tm.net.interfaces.get_collection()
236
-        return lst
237
-
238
-    def _parse_return_ifcs(self):
239
-        ifclst = self._get_interfaces_from_device()
240
-        ifcs = [str(x.name) for x in ifclst]
241
-        if not ifcs:
242
-            err = 'No interfaces were found'
243
-            raise F5ModuleError(err)
244
-        return ifcs
248
+        if len(self._values['tagged_interfaces']) == 1 and self._values['tagged_interfaces'][0] == '':
249
+            return ''
250
+        result = sorted([str(x) for x in self._values['tagged_interfaces']])
251
+        return result
252
+
253
+    @property
254
+    def mtu(self):
255
+        if self._values['mtu'] is None:
256
+            return None
257
+        if int(self._values['mtu']) < 576 or int(self._values['mtu']) > 9198:
258
+            raise F5ModuleError(
259
+                "The mtu value must be between 576 - 9198"
260
+            )
261
+        return int(self._values['mtu'])
245 262
 
263
+    @property
264
+    def cmp_hash(self):
265
+        if self._values['cmp_hash'] is None:
266
+            return None
267
+        if self._values['cmp_hash'] in ['source-address', 'src', 'src-ip', 'source']:
268
+            return 'src-ip'
269
+        if self._values['cmp_hash'] in ['destination-address', 'dest', 'dst-ip', 'destination', 'dst']:
270
+            return 'dst-ip'
271
+        else:
272
+            return 'default'
273
+
274
+    @property
275
+    def dag_round_robin(self):
276
+        if self._values['dag_round_robin'] is None:
277
+            return None
278
+        if self._values['dag_round_robin'] is True:
279
+            return 'enabled'
280
+        else:
281
+            return 'disabled'
282
+
283
+
284
+class Changes(Parameters):
246 285
     def to_return(self):
247 286
         result = {}
248
-        for returnable in self.returnables:
249
-            result[returnable] = getattr(self, returnable)
250
-        result = self._filter_params(result)
287
+        try:
288
+            for returnable in self.returnables:
289
+                result[returnable] = getattr(self, returnable)
290
+            result = self._filter_params(result)
291
+        except Exception:
292
+            pass
251 293
         return result
252 294
 
253
-    def api_params(self):
254
-        result = {}
255
-        for api_attribute in self.api_attributes:
256
-            if api_attribute in self.api_map:
257
-                result[api_attribute] = getattr(
258
-                    self, self.api_map[api_attribute])
259
-            else:
260
-                result[api_attribute] = getattr(self, api_attribute)
261
-        result = self._filter_params(result)
295
+
296
+class UsableChanges(Changes):
297
+    pass
298
+
299
+
300
+class ReportableChanges(Changes):
301
+    @property
302
+    def tagged_interfaces(self):
303
+        if self._values['interfaces'] is None:
304
+            return None
305
+        result = [str(x['name']) for x in self._values['interfaces'] if 'tagged' in x and x['tagged'] is True]
306
+        result = sorted(result)
307
+        return result
308
+
309
+    @property
310
+    def untagged_interfaces(self):
311
+        if self._values['interfaces'] is None:
312
+            return None
313
+        result = [str(x['name']) for x in self._values['interfaces'] if 'untagged' in x and x['untagged'] is True]
314
+        result = sorted(result)
315
+        return result
316
+
317
+
318
+class Difference(object):
319
+    def __init__(self, want, have=None):
320
+        self.want = want
321
+        self.have = have
322
+
323
+    def compare(self, param):
324
+        try:
325
+            result = getattr(self, param)
326
+            return result
327
+        except AttributeError:
328
+            return self.__default(param)
329
+
330
+    def __default(self, param):
331
+        attr1 = getattr(self.want, param)
332
+        try:
333
+            attr2 = getattr(self.have, param)
334
+            if attr1 != attr2:
335
+                return attr1
336
+        except AttributeError:
337
+            return attr1
338
+
339
+    @property
340
+    def untagged_interfaces(self):
341
+        result = []
342
+        if self.want.untagged_interfaces is None:
343
+            return None
344
+        elif self.want.untagged_interfaces == '' and self.have.untagged_interfaces is None:
345
+            return None
346
+        elif self.want.untagged_interfaces == '' and len(self.have.untagged_interfaces) > 0:
347
+            pass
348
+        elif not self.have.untagged_interfaces:
349
+            result = dict(
350
+                interfaces=[dict(name=x, untagged=True) for x in self.want.untagged_interfaces]
351
+            )
352
+        elif set(self.want.untagged_interfaces) != set(self.have.untagged_interfaces):
353
+            result = dict(
354
+                interfaces=[dict(name=x, untagged=True) for x in self.want.untagged_interfaces]
355
+            )
356
+        else:
357
+            return None
358
+        return result
359
+
360
+    @property
361
+    def tagged_interfaces(self):
362
+        result = []
363
+        if self.want.tagged_interfaces is None:
364
+            return None
365
+        elif self.want.tagged_interfaces == '' and self.have.tagged_interfaces is None:
366
+            return None
367
+        elif self.want.tagged_interfaces == '' and len(self.have.tagged_interfaces) > 0:
368
+            pass
369
+        elif not self.have.tagged_interfaces:
370
+            result = dict(
371
+                interfaces=[dict(name=x, tagged=True) for x in self.want.tagged_interfaces]
372
+            )
373
+        elif set(self.want.tagged_interfaces) != set(self.have.tagged_interfaces):
374
+            result = dict(
375
+                interfaces=[dict(name=x, tagged=True) for x in self.want.tagged_interfaces]
376
+            )
377
+        else:
378
+            return None
262 379
         return result
263 380
 
264 381
 
265 382
 class ModuleManager(object):
266
-    def __init__(self, client):
267
-        self.client = client
268
-        self.have = None
269
-        self.want = Parameters()
270
-        self.want.client = self.client
271
-        self.want.update(self.client.module.params)
272
-        self.changes = Parameters()
383
+    def __init__(self, *args, **kwargs):
384
+        self.module = kwargs.get('module', None)
385
+        self.client = kwargs.get('client', None)
386
+        self.want = ModuleParameters(params=self.module.params)
387
+        self.have = ApiParameters()
388
+        self.changes = UsableChanges()
389
+
390
+    def _update_changed_options(self):
391
+        diff = Difference(self.want, self.have)
392
+        updatables = Parameters.updatables
393
+        changed = dict()
394
+        for k in updatables:
395
+            change = diff.compare(k)
396
+            if change is None:
397
+                continue
398
+            else:
399
+                if isinstance(change, dict):
400
+                    changed.update(change)
401
+                else:
402
+                    changed[k] = change
403
+        if changed:
404
+            self.changes = UsableChanges(params=changed)
405
+            return True
406
+        return False
273 407
 
274 408
     def exec_module(self):
275 409
         changed = False
... ...
@@ -284,39 +451,20 @@ class ModuleManager(object):
284 284
         except iControlUnexpectedHTTPError as e:
285 285
             raise F5ModuleError(str(e))
286 286
 
287
-        changes = self.changes.to_return()
287
+        reportable = ReportableChanges(params=self.changes.to_return())
288
+        changes = reportable.to_return()
288 289
         result.update(**changes)
289 290
         result.update(dict(changed=changed))
291
+        self._announce_deprecations(result)
290 292
         return result
291 293
 
292
-    def _set_changed_options(self):
293
-        changed = {}
294
-        for key in Parameters.returnables:
295
-            if getattr(self.want, key) is not None:
296
-                changed[key] = getattr(self.want, key)
297
-        if changed:
298
-            self.changes = Parameters(changed)
299
-
300
-    def _update_changed_options(self):
301
-        changed = {}
302
-        for key in Parameters.updatables:
303
-            if getattr(self.want, key) is not None:
304
-                attr1 = getattr(self.want, key)
305
-                attr2 = getattr(self.have, key)
306
-                if attr1 != attr2:
307
-                    changed[key] = attr1
308
-        if changed:
309
-            self.changes = Parameters(changed)
310
-            return True
311
-        return False
312
-
313
-    def _have_interfaces(self, ifcs):
314
-        untagged = [str(x.name) for x in ifcs if hasattr(x, 'untagged')]
315
-        tagged = [str(x.name) for x in ifcs if hasattr(x, 'tagged')]
316
-        if untagged:
317
-            self.have.update({'untagged_interfaces': untagged})
318
-        if tagged:
319
-            self.have.update({'tagged_interfaces': tagged})
294
+    def _announce_deprecations(self, result):
295
+        warnings = result.pop('__warnings', [])
296
+        for warning in warnings:
297
+            self.module.deprecate(
298
+                msg=warning['msg'],
299
+                version=warning['version']
300
+            )
320 301
 
321 302
     def present(self):
322 303
         if self.exists():
... ...
@@ -336,18 +484,16 @@ class ModuleManager(object):
336 336
         return False
337 337
 
338 338
     def update(self):
339
-        self.have, ifcs = self.read_current_from_device()
340
-        if ifcs:
341
-            self._have_interfaces(ifcs)
339
+        self.have = self.read_current_from_device()
342 340
         if not self.should_update():
343 341
             return False
344
-        if self.client.check_mode:
342
+        if self.module.check_mode:
345 343
             return True
346 344
         self.update_on_device()
347 345
         return True
348 346
 
349 347
     def remove(self):
350
-        if self.client.check_mode:
348
+        if self.module.check_mode:
351 349
             return True
352 350
         self.remove_from_device()
353 351
         if self.exists():
... ...
@@ -355,49 +501,59 @@ class ModuleManager(object):
355 355
         return True
356 356
 
357 357
     def create(self):
358
-        self._set_changed_options()
359
-        if self.client.check_mode:
358
+        self.have = ApiParameters()
359
+        if self.want.mtu is None:
360
+            self.want.update({'mtu': 1500})
361
+        self._update_changed_options()
362
+        if self.module.check_mode:
360 363
             return True
361 364
         self.create_on_device()
362 365
         return True
363 366
 
364 367
     def create_on_device(self):
365
-        params = self.want.api_params()
366
-        self.client.api.tm.net.vlans.vlan.create(**params)
368
+        params = self.changes.api_params()
369
+        self.client.api.tm.net.vlans.vlan.create(
370
+            name=self.want.name,
371
+            partition=self.want.partition,
372
+            **params
373
+        )
367 374
 
368 375
     def update_on_device(self):
369
-        params = self.want.api_params()
370
-        result = self.client.api.tm.net.vlans.vlan.load(
371
-            name=self.want.name, partition=self.want.partition
376
+        params = self.changes.api_params()
377
+        resource = self.client.api.tm.net.vlans.vlan.load(
378
+            name=self.want.name,
379
+            partition=self.want.partition
372 380
         )
373
-        result.modify(**params)
381
+        resource.modify(**params)
374 382
 
375 383
     def exists(self):
376 384
         return self.client.api.tm.net.vlans.vlan.exists(
377
-            name=self.want.name, partition=self.want.partition
385
+            name=self.want.name,
386
+            partition=self.want.partition
378 387
         )
379 388
 
380 389
     def remove_from_device(self):
381
-        result = self.client.api.tm.net.vlans.vlan.load(
382
-            name=self.want.name, partition=self.want.partition
390
+        resource = self.client.api.tm.net.vlans.vlan.load(
391
+            name=self.want.name,
392
+            partition=self.want.partition
383 393
         )
384
-        if result:
385
-            result.delete()
394
+        if resource:
395
+            resource.delete()
386 396
 
387 397
     def read_current_from_device(self):
388
-        tmp_res = self.client.api.tm.net.vlans.vlan.load(
398
+        resource = self.client.api.tm.net.vlans.vlan.load(
389 399
             name=self.want.name, partition=self.want.partition
390 400
         )
391
-        ifcs = tmp_res.interfaces_s.get_collection()
392
-
393
-        result = tmp_res.attrs
394
-        return Parameters(result), ifcs
401
+        interfaces = resource.interfaces_s.get_collection()
402
+        result = resource.attrs
403
+        result['interfaces'] = interfaces
404
+        return ApiParameters(params=result)
395 405
 
396 406
 
397 407
 class ArgumentSpec(object):
398 408
     def __init__(self):
399 409
         self.supports_check_mode = True
400
-        self.argument_spec = dict(
410
+        argument_spec = dict(
401 411
             name=dict(
402 412
                 required=True,
403 413
             ),
... ...
@@ -412,32 +568,56 @@ class ArgumentSpec(object):
412 412
             description=dict(),
413 413
             tag=dict(
414 414
                 type='int'
415
+            ),
416
+            mtu=dict(type='int'),
417
+            cmp_hash=dict(
418
+                choices=[
419
+                    'default',
420
+                    'destination-address', 'dest', 'dst-ip', 'destination', 'dst',
421
+                    'source-address', 'src', 'src-ip', 'source'
422
+                ]
423
+            ),
424
+            dag_tunnel=dict(
425
+                choices=['inner', 'outer']
426
+            ),
427
+            dag_round_robin=dict(type='bool'),
428
+            state=dict(
429
+                default='present',
430
+                choices=['present', 'absent']
431
+            ),
432
+            partition=dict(
433
+                default='Common',
434
+                fallback=(env_fallback, ['F5_PARTITION'])
415 435
             )
416 436
         )
417
-        self.f5_product_name = 'bigip'
437
+        self.argument_spec = {}
438
+        self.argument_spec.update(f5_argument_spec)
439
+        self.argument_spec.update(argument_spec)
440
+        self.mutually_exclusive = [
441
+            ['tagged_interfaces', 'untagged_interfaces']
442
+        ]
418 443
 
419 444
 
420 445
 def main():
421
-    if not HAS_F5SDK:
422
-        raise F5ModuleError("The python f5-sdk module is required")
423
-
424 446
     spec = ArgumentSpec()
425 447
 
426
-    client = AnsibleF5Client(
448
+    module = AnsibleModule(
427 449
         argument_spec=spec.argument_spec,
428 450
         supports_check_mode=spec.supports_check_mode,
429
-        f5_product_name=spec.f5_product_name,
430
-        mutually_exclusive=[
431
-            ['tagged_interfaces', 'untagged_interfaces']
432
-        ]
451
+        mutually_exclusive=spec.mutually_exclusive
433 452
     )
453
+    if not HAS_F5SDK:
454
+        module.fail_json(msg="The python f5-sdk module is required")
434 455
 
435 456
     try:
436
-        mm = ModuleManager(client)
457
+        client = F5Client(**module.params)
458
+        mm = ModuleManager(module=module, client=client)
437 459
         results = mm.exec_module()
438
-        client.module.exit_json(**results)
460
+        cleanup_tokens(client)
461
+        module.exit_json(**results)
439 462
     except F5ModuleError as e:
440
-        client.module.fail_json(msg=str(e))
463
+        cleanup_tokens(client)
464
+        module.fail_json(msg=str(e))
441 465
 
442 466
 
443 467
 if __name__ == '__main__':
... ...
@@ -40,11 +40,6 @@ options:
40 40
   msg:
41 41
     description:
42 42
       - This overrides the normal error message from a failure to meet the required conditions.
43
-notes:
44
-  - Requires the f5-sdk Python package on the host. This is as easy as pip
45
-    install f5-sdk.
46
-requirements:
47
-  - f5-sdk >= 2.2.3
48 43
 extends_documentation_fragment: f5
49 44
 author:
50 45
   - Tim Rupp (@caphrim007)
... ...
@@ -84,133 +79,50 @@ import signal
84 84
 import time
85 85
 
86 86
 from ansible.module_utils.basic import AnsibleModule
87
-from ansible.module_utils.f5_utils import AnsibleF5Client
88
-from ansible.module_utils.f5_utils import AnsibleF5Parameters
89
-from ansible.module_utils.f5_utils import HAS_F5SDK
90
-from ansible.module_utils.f5_utils import F5ModuleError
91
-from ansible.module_utils.f5_utils import F5_COMMON_ARGS
92
-from ansible.module_utils.six import iteritems
93
-from collections import defaultdict
87
+
88
+HAS_DEVEL_IMPORTS = False
94 89
 
95 90
 try:
96
-    from f5.bigip import ManagementRoot as BigIpMgmt
97
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
91
+    # Sideband repository used for dev
92
+    from library.module_utils.network.f5.bigip import HAS_F5SDK
93
+    from library.module_utils.network.f5.bigip import F5Client
94
+    from library.module_utils.network.f5.common import F5ModuleError
95
+    from library.module_utils.network.f5.common import AnsibleF5Parameters
96
+    from library.module_utils.network.f5.common import cleanup_tokens
97
+    from library.module_utils.network.f5.common import fqdn_name
98
+    from library.module_utils.network.f5.common import f5_argument_spec
99
+    try:
100
+        from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
101
+    except ImportError:
102
+        HAS_F5SDK = False
103
+    HAS_DEVEL_IMPORTS = True
98 104
 except ImportError:
99
-    HAS_F5SDK = False
105
+    # Upstream Ansible
106
+    from ansible.module_utils.network.f5.bigip import HAS_F5SDK
107
+    from ansible.module_utils.network.f5.bigip import F5Client
108
+    from ansible.module_utils.network.f5.common import F5ModuleError
109
+    from ansible.module_utils.network.f5.common import AnsibleF5Parameters
110
+    from ansible.module_utils.network.f5.common import cleanup_tokens
111
+    from ansible.module_utils.network.f5.common import fqdn_name
112
+    from ansible.module_utils.network.f5.common import f5_argument_spec
113
+    try:
114
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
115
+    except ImportError:
116
+        HAS_F5SDK = False
100 117
 
101 118
 
102
-def hard_timeout(client, want, start):
119
+def hard_timeout(module, want, start):
103 120
     elapsed = datetime.datetime.utcnow() - start
104
-    client.module.fail_json(
121
+    module.fail_json(
105 122
         want.msg or "Timeout when waiting for BIG-IP", elapsed=elapsed.seconds
106 123
     )
107 124
 
108 125
 
109
-class AnsibleF5ClientStub(AnsibleF5Client):
110
-    """Interim class to disconnect Params from connection
111
-
112
-    This module is an interim class that was made to separate the Ansible Module
113
-    Parameters from the connection to BIG-IP.
114
-
115
-    Since this module needs to be able to control the connection process, the default
116
-    class is not appropriate. Therefore, we overload it and re-define out the
117
-    connection related work to a separate method.
118
-
119
-    This class should serve as a reason to break apart this work itself into separate
120
-    classes in module_utils. There will be on-going work to do this and, when done,
121
-    the result will replace this work here.
122
-
123
-    """
124
-    def __init__(self, argument_spec=None, supports_check_mode=False,
125
-                 mutually_exclusive=None, required_together=None,
126
-                 required_if=None, required_one_of=None, add_file_common_args=False,
127
-                 f5_product_name='bigip'):
128
-        self.f5_product_name = f5_product_name
129
-
130
-        merged_arg_spec = dict()
131
-        merged_arg_spec.update(F5_COMMON_ARGS)
132
-        if argument_spec:
133
-            merged_arg_spec.update(argument_spec)
134
-            self.arg_spec = merged_arg_spec
135
-
136
-        mutually_exclusive_params = []
137
-        if mutually_exclusive:
138
-            mutually_exclusive_params += mutually_exclusive
139
-
140
-        required_together_params = []
141
-        if required_together:
142
-            required_together_params += required_together
143
-
144
-        self.module = AnsibleModule(
145
-            argument_spec=merged_arg_spec,
146
-            supports_check_mode=supports_check_mode,
147
-            mutually_exclusive=mutually_exclusive_params,
148
-            required_together=required_together_params,
149
-            required_if=required_if,
150
-            required_one_of=required_one_of,
151
-            add_file_common_args=add_file_common_args
152
-        )
153
-
154
-        self.check_mode = self.module.check_mode
155
-        self._connect_params = self._get_connect_params()
156
-
157
-    def connect(self):
158
-        try:
159
-            if 'transport' not in self.module.params or self.module.params['transport'] != 'cli':
160
-                self.api = self._get_mgmt_root(
161
-                    self.f5_product_name, **self._connect_params
162
-                )
163
-            return True
164
-        except Exception:
165
-            return False
166
-
167
-    def _get_mgmt_root(self, type, **kwargs):
168
-        if type == 'bigip':
169
-            result = BigIpMgmt(
170
-                kwargs['server'],
171
-                kwargs['user'],
172
-                kwargs['password'],
173
-                port=kwargs['server_port'],
174
-                timeout=1,
175
-                token='tmos'
176
-            )
177
-            return result
178
-
179
-
180 126
 class Parameters(AnsibleF5Parameters):
181 127
     returnables = [
182 128
         'elapsed'
183 129
     ]
184 130
 
185
-    def __init__(self, params=None):
186
-        self._values = defaultdict(lambda: None)
187
-        if params:
188
-            self.update(params=params)
189
-        self._values['__warnings'] = []
190
-
191
-    def update(self, params=None):
192
-        if params:
193
-            for k, v in iteritems(params):
194
-                if self.api_map is not None and k in self.api_map:
195
-                    map_key = self.api_map[k]
196
-                else:
197
-                    map_key = k
198
-
199
-                # Handle weird API parameters like `dns.proxy.__iter__` by
200
-                # using a map provided by the module developer
201
-                class_attr = getattr(type(self), map_key, None)
202
-                if isinstance(class_attr, property):
203
-                    # There is a mapped value for the api_map key
204
-                    if class_attr.fset is None:
205
-                        # If the mapped value does not have an associated setter
206
-                        self._values[map_key] = v
207
-                    else:
208
-                        # The mapped value has a setter
209
-                        setattr(self, map_key, v)
210
-                else:
211
-                    # If the mapped value is not a @property
212
-                    self._values[map_key] = v
213
-
214 131
     def to_return(self):
215 132
         result = {}
216 133
         try:
... ...
@@ -245,10 +157,11 @@ class Changes(Parameters):
245 245
 
246 246
 
247 247
 class ModuleManager(object):
248
-    def __init__(self, client):
249
-        self.client = client
248
+    def __init__(self, *args, **kwargs):
249
+        self.module = kwargs.get('module', None)
250
+        self.client = kwargs.get('client', None)
250 251
         self.have = None
251
-        self.want = Parameters(self.client.module.params)
252
+        self.want = Parameters(params=self.module.params)
252 253
         self.changes = Parameters()
253 254
 
254 255
     def exec_module(self):
... ...
@@ -268,7 +181,7 @@ class ModuleManager(object):
268 268
     def _announce_deprecations(self, result):
269 269
         warnings = result.pop('__warnings', [])
270 270
         for warning in warnings:
271
-            self.client.module.deprecate(
271
+            self.module.deprecate(
272 272
                 msg=warning['msg'],
273 273
                 version=warning['version']
274 274
             )
... ...
@@ -276,7 +189,7 @@ class ModuleManager(object):
276 276
     def execute(self):
277 277
         signal.signal(
278 278
             signal.SIGALRM,
279
-            lambda sig, frame: hard_timeout(self.client, self.want, start)
279
+            lambda sig, frame: hard_timeout(self.module, self.want, start)
280 280
         )
281 281
 
282 282
         # setup handler before scheduling signal, to eliminate a race
... ...
@@ -291,8 +204,8 @@ class ModuleManager(object):
291 291
             try:
292 292
                 # The first test verifies that the REST API is available; this is done
293 293
                 # by repeatedly trying to login to it.
294
-                connected = self._connect_to_device()
295
-                if not connected:
294
+                self.client = F5Client(**self.module.params)
295
+                if not self.client:
296 296
                     continue
297 297
 
298 298
                 if self._device_is_rebooting():
... ...
@@ -333,17 +246,13 @@ class ModuleManager(object):
333 333
                 continue
334 334
         else:
335 335
             elapsed = datetime.datetime.utcnow() - start
336
-            self.client.module.fail_json(
336
+            self.module.fail_json(
337 337
                 msg=self.want.msg or "Timeout when waiting for BIG-IP", elapsed=elapsed.seconds
338 338
             )
339 339
         elapsed = datetime.datetime.utcnow() - start
340 340
         self.changes.update({'elapsed': elapsed.seconds})
341 341
         return False
342 342
 
343
-    def _connect_to_device(self):
344
-        result = self.client.connect()
345
-        return result
346
-
347 343
     def _device_is_rebooting(self):
348 344
         output = self.client.api.tm.util.bash.exec_cmd(
349 345
             'run',
... ...
@@ -386,45 +295,33 @@ class ModuleManager(object):
386 386
 class ArgumentSpec(object):
387 387
     def __init__(self):
388 388
         self.supports_check_mode = True
389
-        self.argument_spec = dict(
389
+        argument_spec = dict(
390 390
             timeout=dict(default=7200, type='int'),
391 391
             delay=dict(default=0, type='int'),
392 392
             sleep=dict(default=1, type='int'),
393 393
             msg=dict()
394 394
         )
395
-        self.f5_product_name = 'bigip'
396
-
397
-
398
-def cleanup_tokens(client):
399
-    try:
400
-        resource = client.api.shared.authz.tokens_s.token.load(
401
-            name=client.api.icrs.token
402
-        )
403
-        resource.delete()
404
-    except Exception:
405
-        pass
395
+        self.argument_spec = {}
396
+        self.argument_spec.update(f5_argument_spec)
397
+        self.argument_spec.update(argument_spec)
406 398
 
407 399
 
408 400
 def main():
409
-    if not HAS_F5SDK:
410
-        raise F5ModuleError("The python f5-sdk module is required")
411
-
412 401
     spec = ArgumentSpec()
413 402
 
414
-    client = AnsibleF5ClientStub(
403
+    module = AnsibleModule(
415 404
         argument_spec=spec.argument_spec,
416
-        supports_check_mode=spec.supports_check_mode,
417
-        f5_product_name=spec.f5_product_name,
405
+        supports_check_mode=spec.supports_check_mode
418 406
     )
407
+    if not HAS_F5SDK:
408
+        module.fail_json(msg="The python f5-sdk module is required")
419 409
 
420 410
     try:
421
-        mm = ModuleManager(client)
411
+        mm = ModuleManager(module=module)
422 412
         results = mm.exec_module()
423
-        cleanup_tokens(client)
424
-        client.module.exit_json(**results)
413
+        module.exit_json(**results)
425 414
     except F5ModuleError as e:
426
-        cleanup_tokens(client)
427
-        client.module.fail_json(msg=str(e))
415
+        module.fail_json(msg=str(e))
428 416
 
429 417
 
430 418
 if __name__ == '__main__':
... ...
@@ -89,17 +89,37 @@ description:
89 89
 
90 90
 import time
91 91
 
92
-from ansible.module_utils.f5_utils import AnsibleF5Client
93
-from ansible.module_utils.f5_utils import AnsibleF5Parameters
94
-from ansible.module_utils.f5_utils import HAS_F5SDK
95
-from ansible.module_utils.f5_utils import F5ModuleError
96
-from ansible.module_utils.six import iteritems
97
-from collections import defaultdict
92
+from ansible.module_utils.basic import AnsibleModule
93
+
94
+HAS_DEVEL_IMPORTS = False
98 95
 
99 96
 try:
100
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
97
+    # Sideband repository used for dev
98
+    from library.module_utils.network.f5.bigiq import HAS_F5SDK
99
+    from library.module_utils.network.f5.bigiq import F5Client
100
+    from library.module_utils.network.f5.common import F5ModuleError
101
+    from library.module_utils.network.f5.common import AnsibleF5Parameters
102
+    from library.module_utils.network.f5.common import cleanup_tokens
103
+    from library.module_utils.network.f5.common import fqdn_name
104
+    from library.module_utils.network.f5.common import f5_argument_spec
105
+    try:
106
+        from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
107
+    except ImportError:
108
+        HAS_F5SDK = False
109
+    HAS_DEVEL_IMPORTS = True
101 110
 except ImportError:
102
-    HAS_F5SDK = False
111
+    # Upstream Ansible
112
+    from ansible.module_utils.network.f5.bigiq import HAS_F5SDK
113
+    from ansible.module_utils.network.f5.bigiq import F5Client
114
+    from ansible.module_utils.network.f5.common import F5ModuleError
115
+    from ansible.module_utils.network.f5.common import AnsibleF5Parameters
116
+    from ansible.module_utils.network.f5.common import cleanup_tokens
117
+    from ansible.module_utils.network.f5.common import fqdn_name
118
+    from ansible.module_utils.network.f5.common import f5_argument_spec
119
+    try:
120
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
121
+    except ImportError:
122
+        HAS_F5SDK = False
103 123
 
104 124
 
105 125
 class Parameters(AnsibleF5Parameters):
... ...
@@ -119,36 +139,6 @@ class Parameters(AnsibleF5Parameters):
119 119
         'description'
120 120
     ]
121 121
 
122
-    def __init__(self, params=None):
123
-        self._values = defaultdict(lambda: None)
124
-        self._values['__warnings'] = []
125
-        if params:
126
-            self.update(params=params)
127
-
128
-    def update(self, params=None):
129
-        if params:
130
-            for k, v in iteritems(params):
131
-                if self.api_map is not None and k in self.api_map:
132
-                    map_key = self.api_map[k]
133
-                else:
134
-                    map_key = k
135
-
136
-                # Handle weird API parameters like `dns.proxy.__iter__` by
137
-                # using a map provided by the module developer
138
-                class_attr = getattr(type(self), map_key, None)
139
-                if isinstance(class_attr, property):
140
-                    # There is a mapped value for the api_map key
141
-                    if class_attr.fset is None:
142
-                        # If the mapped value does not have
143
-                        # an associated setter
144
-                        self._values[map_key] = v
145
-                    else:
146
-                        # The mapped value has a setter
147
-                        setattr(self, map_key, v)
148
-                else:
149
-                    # If the mapped value is not a @property
150
-                    self._values[map_key] = v
151
-
152 122
     def to_return(self):
153 123
         result = {}
154 124
         try:
... ...
@@ -159,16 +149,6 @@ class Parameters(AnsibleF5Parameters):
159 159
             pass
160 160
         return result
161 161
 
162
-    def api_params(self):
163
-        result = {}
164
-        for api_attribute in self.api_attributes:
165
-            if self.api_map is not None and api_attribute in self.api_map:
166
-                result[api_attribute] = getattr(self, self.api_map[api_attribute])
167
-            else:
168
-                result[api_attribute] = getattr(self, api_attribute)
169
-        result = self._filter_params(result)
170
-        return result
171
-
172 162
 
173 163
 class ApiParameters(Parameters):
174 164
     pass
... ...
@@ -230,10 +210,10 @@ class Difference(object):
230 230
 
231 231
 
232 232
 class ModuleManager(object):
233
-    def __init__(self, client):
234
-        self.client = client
235
-        self.want = ModuleParameters(params=self.client.module.params)
236
-        self.want.update(dict(client=client))
233
+    def __init__(self, *args, **kwargs):
234
+        self.module = kwargs.get('module', None)
235
+        self.client = kwargs.get('client', None)
236
+        self.want = ModuleParameters(client=self.client, params=self.module.params)
237 237
         self.have = ApiParameters()
238 238
         self.changes = UsableChanges()
239 239
 
... ...
@@ -243,7 +223,7 @@ class ModuleManager(object):
243 243
             if getattr(self.want, key) is not None:
244 244
                 changed[key] = getattr(self.want, key)
245 245
         if changed:
246
-            self.changes = UsableChanges(changed)
246
+            self.changes = UsableChanges(params=changed)
247 247
 
248 248
     def _update_changed_options(self):
249 249
         diff = Difference(self.want, self.have)
... ...
@@ -259,7 +239,7 @@ class ModuleManager(object):
259 259
                 else:
260 260
                     changed[k] = change
261 261
         if changed:
262
-            self.changes = UsableChanges(changed)
262
+            self.changes = UsableChanges(params=changed)
263 263
             return True
264 264
         return False
265 265
 
... ...
@@ -282,7 +262,7 @@ class ModuleManager(object):
282 282
         except iControlUnexpectedHTTPError as e:
283 283
             raise F5ModuleError(str(e))
284 284
 
285
-        reportable = ReportableChanges(self.changes.to_return())
285
+        reportable = ReportableChanges(params=self.changes.to_return())
286 286
         changes = reportable.to_return()
287 287
         result.update(**changes)
288 288
         result.update(dict(changed=changed))
... ...
@@ -292,7 +272,7 @@ class ModuleManager(object):
292 292
     def _announce_deprecations(self, result):
293 293
         warnings = result.pop('__warnings', [])
294 294
         for warning in warnings:
295
-            self.client.module.deprecate(
295
+            self.module.deprecate(
296 296
                 msg=warning['msg'],
297 297
                 version=warning['version']
298 298
             )
... ...
@@ -316,13 +296,13 @@ class ModuleManager(object):
316 316
         self.have = self.read_current_from_device()
317 317
         if not self.should_update():
318 318
             return False
319
-        if self.client.check_mode:
319
+        if self.module.check_mode:
320 320
             return True
321 321
         self.update_on_device()
322 322
         return True
323 323
 
324 324
     def remove(self):
325
-        if self.client.check_mode:
325
+        if self.module.check_mode:
326 326
             return True
327 327
         self.remove_from_device()
328 328
         if self.exists():
... ...
@@ -331,7 +311,7 @@ class ModuleManager(object):
331 331
 
332 332
     def create(self):
333 333
         self._set_changed_options()
334
-        if self.client.check_mode:
334
+        if self.module.check_mode:
335 335
             return True
336 336
         if self.want.accept_eula is False:
337 337
             raise F5ModuleError(
... ...
@@ -401,42 +381,48 @@ class ModuleManager(object):
401 401
         if resource is None:
402 402
             return False
403 403
         result = resource.attrs
404
-        return ApiParameters(result)
404
+        return ApiParameters(params=result)
405 405
 
406 406
 
407 407
 class ArgumentSpec(object):
408 408
     def __init__(self):
409 409
         self.supports_check_mode = True
410
-        self.argument_spec = dict(
410
+        argument_spec = dict(
411 411
             regkey_pool=dict(required=True),
412 412
             license_key=dict(required=True, no_log=True),
413 413
             description=dict(),
414
-            accept_eula=dict(type='bool')
414
+            accept_eula=dict(type='bool'),
415
+            state=dict(
416
+                default='present',
417
+                choices=['present', 'absent']
418
+            ),
415 419
         )
416
-        self.f5_product_name = 'bigiq'
420
+        self.argument_spec = {}
421
+        self.argument_spec.update(f5_argument_spec)
422
+        self.argument_spec.update(argument_spec)
417 423
         self.required_if = [
418 424
             ['state', 'present', ['accept_eula']]
419 425
         ]
420 426
 
421 427
 
422 428
 def main():
423
-    if not HAS_F5SDK:
424
-        raise F5ModuleError("The python f5-sdk module is required")
425
-
426 429
     spec = ArgumentSpec()
427 430
 
428
-    client = AnsibleF5Client(
431
+    module = AnsibleModule(
429 432
         argument_spec=spec.argument_spec,
430 433
         supports_check_mode=spec.supports_check_mode,
431
-        f5_product_name=spec.f5_product_name
434
+        required_if=spec.required_if
432 435
     )
436
+    if not HAS_F5SDK:
437
+        module.fail_json(msg="The python f5-sdk module is required")
433 438
 
434 439
     try:
435
-        mm = ModuleManager(client)
440
+        client = F5Client(**module.params)
441
+        mm = ModuleManager(module=module, client=client)
436 442
         results = mm.exec_module()
437
-        client.module.exit_json(**results)
443
+        module.exit_json(**results)
438 444
     except F5ModuleError as e:
439
-        client.module.fail_json(msg=str(e))
445
+        module.fail_json(msg=str(e))
440 446
 
441 447
 
442 448
 if __name__ == '__main__':
... ...
@@ -69,18 +69,37 @@ description:
69 69
   sample: My description
70 70
 '''
71 71
 
72
+from ansible.module_utils.basic import AnsibleModule
72 73
 
73
-from ansible.module_utils.f5_utils import AnsibleF5Client
74
-from ansible.module_utils.f5_utils import AnsibleF5Parameters
75
-from ansible.module_utils.f5_utils import HAS_F5SDK
76
-from ansible.module_utils.f5_utils import F5ModuleError
77
-from ansible.module_utils.six import iteritems
78
-from collections import defaultdict
74
+HAS_DEVEL_IMPORTS = False
79 75
 
80 76
 try:
81
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
77
+    # Sideband repository used for dev
78
+    from library.module_utils.network.f5.bigiq import HAS_F5SDK
79
+    from library.module_utils.network.f5.bigiq import F5Client
80
+    from library.module_utils.network.f5.common import F5ModuleError
81
+    from library.module_utils.network.f5.common import AnsibleF5Parameters
82
+    from library.module_utils.network.f5.common import cleanup_tokens
83
+    from library.module_utils.network.f5.common import fqdn_name
84
+    from library.module_utils.network.f5.common import f5_argument_spec
85
+    try:
86
+        from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
87
+    except ImportError:
88
+        HAS_F5SDK = False
89
+    HAS_DEVEL_IMPORTS = True
82 90
 except ImportError:
83
-    HAS_F5SDK = False
91
+    # Upstream Ansible
92
+    from ansible.module_utils.network.f5.bigiq import HAS_F5SDK
93
+    from ansible.module_utils.network.f5.bigiq import F5Client
94
+    from ansible.module_utils.network.f5.common import F5ModuleError
95
+    from ansible.module_utils.network.f5.common import AnsibleF5Parameters
96
+    from ansible.module_utils.network.f5.common import cleanup_tokens
97
+    from ansible.module_utils.network.f5.common import fqdn_name
98
+    from ansible.module_utils.network.f5.common import f5_argument_spec
99
+    try:
100
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
101
+    except ImportError:
102
+        HAS_F5SDK = False
84 103
 
85 104
 
86 105
 class Parameters(AnsibleF5Parameters):
... ...
@@ -100,36 +119,6 @@ class Parameters(AnsibleF5Parameters):
100 100
         'description'
101 101
     ]
102 102
 
103
-    def __init__(self, params=None):
104
-        self._values = defaultdict(lambda: None)
105
-        self._values['__warnings'] = []
106
-        if params:
107
-            self.update(params=params)
108
-
109
-    def update(self, params=None):
110
-        if params:
111
-            for k, v in iteritems(params):
112
-                if self.api_map is not None and k in self.api_map:
113
-                    map_key = self.api_map[k]
114
-                else:
115
-                    map_key = k
116
-
117
-                # Handle weird API parameters like `dns.proxy.__iter__` by
118
-                # using a map provided by the module developer
119
-                class_attr = getattr(type(self), map_key, None)
120
-                if isinstance(class_attr, property):
121
-                    # There is a mapped value for the api_map key
122
-                    if class_attr.fset is None:
123
-                        # If the mapped value does not have
124
-                        # an associated setter
125
-                        self._values[map_key] = v
126
-                    else:
127
-                        # The mapped value has a setter
128
-                        setattr(self, map_key, v)
129
-                else:
130
-                    # If the mapped value is not a @property
131
-                    self._values[map_key] = v
132
-
133 103
     def to_return(self):
134 104
         result = {}
135 105
         try:
... ...
@@ -140,16 +129,6 @@ class Parameters(AnsibleF5Parameters):
140 140
             pass
141 141
         return result
142 142
 
143
-    def api_params(self):
144
-        result = {}
145
-        for api_attribute in self.api_attributes:
146
-            if self.api_map is not None and api_attribute in self.api_map:
147
-                result[api_attribute] = getattr(self, self.api_map[api_attribute])
148
-            else:
149
-                result[api_attribute] = getattr(self, api_attribute)
150
-        result = self._filter_params(result)
151
-        return result
152
-
153 143
 
154 144
 class ModuleParameters(Parameters):
155 145
     @property
... ...
@@ -214,10 +193,10 @@ class Difference(object):
214 214
 
215 215
 
216 216
 class ModuleManager(object):
217
-    def __init__(self, client):
218
-        self.client = client
219
-        self.want = ModuleParameters(self.client.module.params)
220
-        self.want.update({'client': client})
217
+    def __init__(self, *args, **kwargs):
218
+        self.module = kwargs.get('module', None)
219
+        self.client = kwargs.get('client', None)
220
+        self.want = ModuleParameters(client=self.client, params=self.module.params)
221 221
         self.have = ApiParameters()
222 222
         self.changes = UsableChanges()
223 223
 
... ...
@@ -227,7 +206,7 @@ class ModuleManager(object):
227 227
             if getattr(self.want, key) is not None:
228 228
                 changed[key] = getattr(self.want, key)
229 229
         if changed:
230
-            self.changes = UsableChanges(changed)
230
+            self.changes = UsableChanges(params=changed)
231 231
 
232 232
     def _update_changed_options(self):
233 233
         diff = Difference(self.want, self.have)
... ...
@@ -243,7 +222,7 @@ class ModuleManager(object):
243 243
                 else:
244 244
                     changed[k] = change
245 245
         if changed:
246
-            self.changes = Changes(changed)
246
+            self.changes = Changes(params=changed)
247 247
             return True
248 248
         return False
249 249
 
... ...
@@ -266,7 +245,7 @@ class ModuleManager(object):
266 266
         except iControlUnexpectedHTTPError as e:
267 267
             raise F5ModuleError(str(e))
268 268
 
269
-        reportable = ReportableChanges(self.changes.to_return())
269
+        reportable = ReportableChanges(params=self.changes.to_return())
270 270
         changes = reportable.to_return()
271 271
         result.update(**changes)
272 272
         result.update(dict(changed=changed))
... ...
@@ -276,7 +255,7 @@ class ModuleManager(object):
276 276
     def _announce_deprecations(self, result):
277 277
         warnings = result.pop('__warnings', [])
278 278
         for warning in warnings:
279
-            self.client.module.deprecate(
279
+            self.module.deprecate(
280 280
                 msg=warning['msg'],
281 281
                 version=warning['version']
282 282
             )
... ...
@@ -297,13 +276,13 @@ class ModuleManager(object):
297 297
         self.have = self.read_current_from_device()
298 298
         if not self.should_update():
299 299
             return False
300
-        if self.client.check_mode:
300
+        if self.module.check_mode:
301 301
             return True
302 302
         self.update_on_device()
303 303
         return True
304 304
 
305 305
     def remove(self):
306
-        if self.client.check_mode:
306
+        if self.module.check_mode:
307 307
             return True
308 308
         self.remove_from_device()
309 309
         if self.exists():
... ...
@@ -312,7 +291,7 @@ class ModuleManager(object):
312 312
 
313 313
     def create(self):
314 314
         self._set_changed_options()
315
-        if self.client.check_mode:
315
+        if self.module.check_mode:
316 316
             return True
317 317
         self.create_on_device()
318 318
         return True
... ...
@@ -348,13 +327,13 @@ class ModuleManager(object):
348 348
             id=self.want.uuid
349 349
         )
350 350
         result = resource.attrs
351
-        return ApiParameters(result)
351
+        return ApiParameters(params=result)
352 352
 
353 353
 
354 354
 class ArgumentSpec(object):
355 355
     def __init__(self):
356 356
         self.supports_check_mode = True
357
-        self.argument_spec = dict(
357
+        argument_spec = dict(
358 358
             name=dict(required=True),
359 359
             description=dict(),
360 360
             state=dict(
... ...
@@ -362,27 +341,28 @@ class ArgumentSpec(object):
362 362
                 choices=['absent', 'present']
363 363
             )
364 364
         )
365
-        self.f5_product_name = 'bigiq'
365
+        self.argument_spec = {}
366
+        self.argument_spec.update(f5_argument_spec)
367
+        self.argument_spec.update(argument_spec)
366 368
 
367 369
 
368 370
 def main():
369
-    if not HAS_F5SDK:
370
-        raise F5ModuleError("The python f5-sdk module is required")
371
-
372 371
     spec = ArgumentSpec()
373 372
 
374
-    client = AnsibleF5Client(
373
+    module = AnsibleModule(
375 374
         argument_spec=spec.argument_spec,
376
-        supports_check_mode=spec.supports_check_mode,
377
-        f5_product_name=spec.f5_product_name
375
+        supports_check_mode=spec.supports_check_mode
378 376
     )
377
+    if not HAS_F5SDK:
378
+        module.fail_json(msg="The python f5-sdk module is required")
379 379
 
380 380
     try:
381
-        mm = ModuleManager(client)
381
+        client = F5Client(**module.params)
382
+        mm = ModuleManager(module=module, client=client)
382 383
         results = mm.exec_module()
383
-        client.module.exit_json(**results)
384
+        module.exit_json(**results)
384 385
     except F5ModuleError as e:
385
-        client.module.fail_json(msg=str(e))
386
+        module.fail_json(msg=str(e))
386 387
 
387 388
 
388 389
 if __name__ == '__main__':
... ...
@@ -41,18 +41,6 @@ lib/ansible/modules/net_tools/cloudflare_dns.py E317
41 41
 lib/ansible/modules/net_tools/haproxy.py E317
42 42
 lib/ansible/modules/net_tools/omapi_host.py E317
43 43
 lib/ansible/modules/network/cloudengine/ce_reboot.py E317
44
-lib/ansible/modules/network/f5/bigip_sys_db.py E321
45
-lib/ansible/modules/network/f5/bigip_sys_global.py E321
46
-lib/ansible/modules/network/f5/bigip_traffic_group.py E321
47
-lib/ansible/modules/network/f5/bigip_ucs.py E321
48
-lib/ansible/modules/network/f5/bigip_user.py E321
49
-lib/ansible/modules/network/f5/bigip_vcmp_guest.py E321
50
-lib/ansible/modules/network/f5/bigip_virtual_address.py E321
51
-lib/ansible/modules/network/f5/bigip_virtual_server.py E321
52
-lib/ansible/modules/network/f5/bigip_vlan.py E321
53
-lib/ansible/modules/network/f5/bigip_wait.py E321
54
-lib/ansible/modules/network/f5/bigiq_regkey_license.py E321
55
-lib/ansible/modules/network/f5/bigiq_regkey_pool.py E321
56 44
 lib/ansible/modules/network/illumos/dladm_linkprop.py E317
57 45
 lib/ansible/modules/network/illumos/ipadm_addrprop.py E317
58 46
 lib/ansible/modules/network/illumos/ipadm_ifprop.py E317
59 47
new file mode 100644
... ...
@@ -0,0 +1,15 @@
0
+{
1
+    "kind": "tm:net:vlan:interfaces:interfacescollectionstate",
2
+    "selfLink": "https://localhost/mgmt/tm/net/vlan/~Common~vlan1/interfaces?ver=13.0.0",
3
+    "items": [
4
+        {
5
+            "kind": "tm:net:vlan:interfaces:interfacesstate",
6
+            "name": "1.2",
7
+            "fullPath": "1.2",
8
+            "generation": 105,
9
+            "selfLink": "https://localhost/mgmt/tm/net/vlan/~Common~vlan1/interfaces/1.2?ver=13.0.0",
10
+            "tagMode": "none",
11
+            "tagged": true
12
+        }
13
+    ]
14
+}
... ...
@@ -17,20 +17,22 @@ if sys.version_info < (2, 7):
17 17
 from ansible.compat.tests import unittest
18 18
 from ansible.compat.tests.mock import Mock
19 19
 from ansible.compat.tests.mock import patch
20
-from ansible.module_utils.f5_utils import AnsibleF5Client
20
+from ansible.module_utils.basic import AnsibleModule
21 21
 
22 22
 try:
23 23
     from library.bigip_sys_db import Parameters
24 24
     from library.bigip_sys_db import ModuleManager
25 25
     from library.bigip_sys_db import ArgumentSpec
26
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
26
+    from library.module_utils.network.f5.common import F5ModuleError
27
+    from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
27 28
     from test.unit.modules.utils import set_module_args
28 29
 except ImportError:
29 30
     try:
30 31
         from ansible.modules.network.f5.bigip_sys_db import Parameters
31 32
         from ansible.modules.network.f5.bigip_sys_db import ModuleManager
32 33
         from ansible.modules.network.f5.bigip_sys_db import ArgumentSpec
33
-        from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
34
+        from ansible.module_utils.network.f5.common import F5ModuleError
35
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
34 36
         from units.modules.utils import set_module_args
35 37
     except ImportError:
36 38
         raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
... ...
@@ -66,7 +68,7 @@ class TestParameters(unittest.TestCase):
66 66
             server='localhost',
67 67
             user='admin'
68 68
         )
69
-        p = Parameters(args)
69
+        p = Parameters(params=args)
70 70
         assert p.key == 'foo'
71 71
         assert p.value == 'bar'
72 72
 
... ...
@@ -80,13 +82,11 @@ class TestParameters(unittest.TestCase):
80 80
             user='admin'
81 81
 
82 82
         )
83
-        p = Parameters(args)
83
+        p = Parameters(params=args)
84 84
         assert p.key == 'foo'
85 85
         assert p.value == 'bar'
86 86
 
87 87
 
88
-@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
89
-       return_value=True)
90 88
 class TestManager(unittest.TestCase):
91 89
 
92 90
     def setUp(self):
... ...
@@ -118,12 +118,11 @@ class TestManager(unittest.TestCase):
118 118
             )
119 119
         )
120 120
 
121
-        client = AnsibleF5Client(
121
+        module = AnsibleModule(
122 122
             argument_spec=self.spec.argument_spec,
123
-            supports_check_mode=self.spec.supports_check_mode,
124
-            f5_product_name=self.spec.f5_product_name
123
+            supports_check_mode=self.spec.supports_check_mode
125 124
         )
126
-        mm = ModuleManager(client)
125
+        mm = ModuleManager(module=module)
127 126
 
128 127
         # Override methods to force specific logic in the module to happen
129 128
         mm.exists = Mock(return_value=False)
... ...
@@ -17,14 +17,15 @@ if sys.version_info < (2, 7):
17 17
 from ansible.compat.tests import unittest
18 18
 from ansible.compat.tests.mock import Mock
19 19
 from ansible.compat.tests.mock import patch
20
-from ansible.module_utils.f5_utils import AnsibleF5Client
20
+from ansible.module_utils.basic import AnsibleModule
21 21
 
22 22
 try:
23 23
     from library.bigip_sys_global import ApiParameters
24 24
     from library.bigip_sys_global import ModuleParameters
25 25
     from library.bigip_sys_global import ModuleManager
26 26
     from library.bigip_sys_global import ArgumentSpec
27
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
27
+    from library.module_utils.network.f5.common import F5ModuleError
28
+    from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
28 29
     from test.unit.modules.utils import set_module_args
29 30
 except ImportError:
30 31
     try:
... ...
@@ -32,7 +33,8 @@ except ImportError:
32 32
         from ansible.modules.network.f5.bigip_sys_global import ModuleParameters
33 33
         from ansible.modules.network.f5.bigip_sys_global import ModuleManager
34 34
         from ansible.modules.network.f5.bigip_sys_global import ArgumentSpec
35
-        from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
35
+        from ansible.module_utils.network.f5.common import F5ModuleError
36
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
36 37
         from units.modules.utils import set_module_args
37 38
     except ImportError:
38 39
         raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
... ...
@@ -71,7 +73,7 @@ class TestParameters(unittest.TestCase):
71 71
             quiet_boot='yes',
72 72
             security_banner='yes',
73 73
         )
74
-        p = ModuleParameters(args)
74
+        p = ModuleParameters(params=args)
75 75
         assert p.banner_text == 'this is a banner'
76 76
         assert p.console_timeout == 100
77 77
         assert p.gui_setup == 'enabled'
... ...
@@ -83,7 +85,7 @@ class TestParameters(unittest.TestCase):
83 83
 
84 84
     def test_api_parameters(self):
85 85
         args = load_fixture('load_sys_global_settings.json')
86
-        p = ApiParameters(args)
86
+        p = ApiParameters(params=args)
87 87
         assert 'Welcome to the BIG-IP Configuration Utility' in p.banner_text
88 88
         assert p.console_timeout == 0
89 89
         assert p.gui_setup == 'disabled'
... ...
@@ -94,8 +96,6 @@ class TestParameters(unittest.TestCase):
94 94
         assert p.security_banner == 'enabled'
95 95
 
96 96
 
97
-@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
98
-       return_value=True)
99 97
 class TestManager(unittest.TestCase):
100 98
 
101 99
     def setUp(self):
... ...
@@ -113,14 +113,13 @@ class TestManager(unittest.TestCase):
113 113
 
114 114
         # Configure the parameters that would be returned by querying the
115 115
         # remote device
116
-        current = ApiParameters(load_fixture('load_sys_global_settings.json'))
116
+        current = ApiParameters(params=load_fixture('load_sys_global_settings.json'))
117 117
 
118
-        client = AnsibleF5Client(
118
+        module = AnsibleModule(
119 119
             argument_spec=self.spec.argument_spec,
120
-            supports_check_mode=self.spec.supports_check_mode,
121
-            f5_product_name=self.spec.f5_product_name
120
+            supports_check_mode=self.spec.supports_check_mode
122 121
         )
123
-        mm = ModuleManager(client)
122
+        mm = ModuleManager(module=module)
124 123
 
125 124
         # Override methods to force specific logic in the module to happen
126 125
         mm.exists = Mock(return_value=False)
... ...
@@ -18,21 +18,22 @@ if sys.version_info < (2, 7):
18 18
 from ansible.compat.tests import unittest
19 19
 from ansible.compat.tests.mock import Mock
20 20
 from ansible.compat.tests.mock import patch
21
-from ansible.module_utils.f5_utils import AnsibleF5Client
22
-from ansible.module_utils.f5_utils import F5ModuleError
21
+from ansible.module_utils.basic import AnsibleModule
23 22
 
24 23
 try:
25 24
     from library.bigip_traffic_group import Parameters
26 25
     from library.bigip_traffic_group import ModuleManager
27 26
     from library.bigip_traffic_group import ArgumentSpec
28
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
27
+    from library.module_utils.network.f5.common import F5ModuleError
28
+    from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
29 29
     from test.unit.modules.utils import set_module_args
30 30
 except ImportError:
31 31
     try:
32 32
         from ansible.modules.network.f5.bigip_traffic_group import Parameters
33 33
         from ansible.modules.network.f5.bigip_traffic_group import ModuleManager
34 34
         from ansible.modules.network.f5.bigip_traffic_group import ArgumentSpec
35
-        from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
35
+        from ansible.module_utils.network.f5.common import F5ModuleError
36
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
36 37
         from units.modules.utils import set_module_args
37 38
     except ImportError:
38 39
         raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
... ...
@@ -65,12 +66,10 @@ class TestParameters(unittest.TestCase):
65 65
             name='foo'
66 66
         )
67 67
 
68
-        p = Parameters(args)
68
+        p = Parameters(params=args)
69 69
         assert p.name == 'foo'
70 70
 
71 71
 
72
-@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
73
-       return_value=True)
74 72
 class TestManager(unittest.TestCase):
75 73
 
76 74
     def setUp(self):
... ...
@@ -84,13 +83,12 @@ class TestManager(unittest.TestCase):
84 84
             user='admin'
85 85
         ))
86 86
 
87
-        client = AnsibleF5Client(
87
+        module = AnsibleModule(
88 88
             argument_spec=self.spec.argument_spec,
89
-            supports_check_mode=self.spec.supports_check_mode,
90
-            f5_product_name=self.spec.f5_product_name
89
+            supports_check_mode=self.spec.supports_check_mode
91 90
         )
92 91
 
93
-        mm = ModuleManager(client)
92
+        mm = ModuleManager(module=module)
94 93
         mm.create_on_device = Mock(return_value=True)
95 94
         mm.exists = Mock(return_value=False)
96 95
 
... ...
@@ -18,8 +18,7 @@ if sys.version_info < (2, 7):
18 18
 from ansible.compat.tests import unittest
19 19
 from ansible.compat.tests.mock import Mock
20 20
 from ansible.compat.tests.mock import patch
21
-from ansible.module_utils.f5_utils import AnsibleF5Client
22
-from ansible.module_utils.f5_utils import F5ModuleError
21
+from ansible.module_utils.basic import AnsibleModule
23 22
 
24 23
 try:
25 24
     from library.bigip_ucs import Parameters
... ...
@@ -27,7 +26,8 @@ try:
27 27
     from library.bigip_ucs import ArgumentSpec
28 28
     from library.bigip_ucs import V1Manager
29 29
     from library.bigip_ucs import V2Manager
30
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
30
+    from library.module_utils.network.f5.common import F5ModuleError
31
+    from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
31 32
     from test.unit.modules.utils import set_module_args
32 33
 except ImportError:
33 34
     try:
... ...
@@ -36,7 +36,8 @@ except ImportError:
36 36
         from ansible.modules.network.f5.bigip_ucs import ArgumentSpec
37 37
         from ansible.modules.network.f5.bigip_ucs import V1Manager
38 38
         from ansible.modules.network.f5.bigip_ucs import V2Manager
39
-        from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
39
+        from ansible.module_utils.network.f5.common import F5ModuleError
40
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
40 41
         from units.modules.utils import set_module_args
41 42
     except ImportError:
42 43
         raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
... ...
@@ -76,7 +77,7 @@ class TestParameters(unittest.TestCase):
76 76
             state='installed'
77 77
         )
78 78
 
79
-        p = Parameters(args)
79
+        p = Parameters(params=args)
80 80
         assert p.ucs == '/root/bigip.localhost.localdomain.ucs'
81 81
         assert p.force is True
82 82
         assert p.include_chassis_level_config is True
... ...
@@ -98,7 +99,7 @@ class TestParameters(unittest.TestCase):
98 98
             reset_trust=False
99 99
         )
100 100
 
101
-        p = Parameters(args)
101
+        p = Parameters(params=args)
102 102
         assert p.ucs == '/root/bigip.localhost.localdomain.ucs'
103 103
         assert p.include_chassis_level_config is False
104 104
         assert p.no_license is False
... ...
@@ -107,8 +108,6 @@ class TestParameters(unittest.TestCase):
107 107
         assert p.install_command == "tmsh load sys ucs /var/local/ucs/bigip.localhost.localdomain.ucs"
108 108
 
109 109
 
110
-@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
111
-       return_value=True)
112 110
 class TestV1Manager(unittest.TestCase):
113 111
 
114 112
     def setUp(self):
... ...
@@ -122,17 +121,16 @@ class TestV1Manager(unittest.TestCase):
122 122
             user='admin'
123 123
         ))
124 124
 
125
-        client = AnsibleF5Client(
125
+        module = AnsibleModule(
126 126
             argument_spec=self.spec.argument_spec,
127
-            supports_check_mode=self.spec.supports_check_mode,
128
-            f5_product_name=self.spec.f5_product_name
127
+            supports_check_mode=self.spec.supports_check_mode
129 128
         )
130 129
 
131 130
         # Override methods to force specific logic in the module to happen
132
-        mm = ModuleManager(client)
131
+        mm = ModuleManager(module=module)
133 132
         mm.is_version_v1 = Mock(return_value=True)
134 133
 
135
-        vm = V1Manager(client)
134
+        vm = V1Manager(module=module)
136 135
         vm.create_on_device = Mock(return_value=True)
137 136
         vm.exists = Mock(side_effect=[False, True])
138 137
 
... ...
@@ -149,17 +147,16 @@ class TestV1Manager(unittest.TestCase):
149 149
             state='present'
150 150
         ))
151 151
 
152
-        client = AnsibleF5Client(
152
+        module = AnsibleModule(
153 153
             argument_spec=self.spec.argument_spec,
154
-            supports_check_mode=self.spec.supports_check_mode,
155
-            f5_product_name=self.spec.f5_product_name
154
+            supports_check_mode=self.spec.supports_check_mode
156 155
         )
157 156
 
158 157
         # Override methods to force specific logic in the module to happen
159
-        mm = ModuleManager(client)
158
+        mm = ModuleManager(module=module)
160 159
         mm.is_version_v1 = Mock(return_value=True)
161 160
 
162
-        vm = V1Manager(client)
161
+        vm = V1Manager(module=module)
163 162
         vm.create_on_device = Mock(return_value=True)
164 163
         vm.exists = Mock(side_effect=[False, True])
165 164
 
... ...
@@ -176,17 +173,16 @@ class TestV1Manager(unittest.TestCase):
176 176
             state='installed'
177 177
         ))
178 178
 
179
-        client = AnsibleF5Client(
179
+        module = AnsibleModule(
180 180
             argument_spec=self.spec.argument_spec,
181
-            supports_check_mode=self.spec.supports_check_mode,
182
-            f5_product_name=self.spec.f5_product_name
181
+            supports_check_mode=self.spec.supports_check_mode
183 182
         )
184 183
 
185 184
         # Override methods to force specific logic in the module to happen
186
-        mm = ModuleManager(client)
185
+        mm = ModuleManager(module=module)
187 186
         mm.is_version_v1 = Mock(return_value=True)
188 187
 
189
-        vm = V1Manager(client)
188
+        vm = V1Manager(module=module)
190 189
         vm.create_on_device = Mock(return_value=True)
191 190
         vm.exists = Mock(return_value=True)
192 191
         vm.install_on_device = Mock(return_value=True)
... ...
@@ -204,17 +200,16 @@ class TestV1Manager(unittest.TestCase):
204 204
             state='absent'
205 205
         ))
206 206
 
207
-        client = AnsibleF5Client(
207
+        module = AnsibleModule(
208 208
             argument_spec=self.spec.argument_spec,
209
-            supports_check_mode=self.spec.supports_check_mode,
210
-            f5_product_name=self.spec.f5_product_name
209
+            supports_check_mode=self.spec.supports_check_mode
211 210
         )
212 211
 
213 212
         # Override methods to force specific logic in the module to happen
214
-        mm = ModuleManager(client)
213
+        mm = ModuleManager(module=module)
215 214
         mm.is_version_v1 = Mock(return_value=True)
216 215
 
217
-        vm = V1Manager(client)
216
+        vm = V1Manager(module=module)
218 217
         vm.remove_from_device = Mock(return_value=True)
219 218
         vm.exists = Mock(side_effect=[True, False])
220 219
 
... ...
@@ -231,17 +226,16 @@ class TestV1Manager(unittest.TestCase):
231 231
             state='absent'
232 232
         ))
233 233
 
234
-        client = AnsibleF5Client(
234
+        module = AnsibleModule(
235 235
             argument_spec=self.spec.argument_spec,
236
-            supports_check_mode=self.spec.supports_check_mode,
237
-            f5_product_name=self.spec.f5_product_name
236
+            supports_check_mode=self.spec.supports_check_mode
238 237
         )
239 238
 
240 239
         # Override methods to force specific logic in the module to happen
241
-        mm = ModuleManager(client)
240
+        mm = ModuleManager(module=module)
242 241
         mm.is_version_v1 = Mock(return_value=True)
243 242
 
244
-        vm = V1Manager(client)
243
+        vm = V1Manager(module=module)
245 244
         vm.remove_from_device = Mock(return_value=True)
246 245
         vm.exists = Mock(side_effect=[True, True])
247 246
 
... ...
@@ -250,8 +244,6 @@ class TestV1Manager(unittest.TestCase):
250 250
         assert 'Failed to delete' in str(ex.value)
251 251
 
252 252
 
253
-@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
254
-       return_value=True)
255 253
 class TestV2Manager(unittest.TestCase):
256 254
 
257 255
     def setUp(self):
... ...
@@ -265,17 +257,16 @@ class TestV2Manager(unittest.TestCase):
265 265
             user='admin'
266 266
         ))
267 267
 
268
-        client = AnsibleF5Client(
268
+        module = AnsibleModule(
269 269
             argument_spec=self.spec.argument_spec,
270
-            supports_check_mode=self.spec.supports_check_mode,
271
-            f5_product_name=self.spec.f5_product_name
270
+            supports_check_mode=self.spec.supports_check_mode
272 271
         )
273 272
 
274 273
         # Override methods to force specific logic in the module to happen
275
-        mm = ModuleManager(client)
274
+        mm = ModuleManager(module=module)
276 275
         mm.is_version_v1 = Mock(return_value=False)
277 276
 
278
-        vm = V2Manager(client)
277
+        vm = V2Manager(module=module)
279 278
         vm.create_on_device = Mock(return_value=True)
280 279
         vm.exists = Mock(side_effect=[False, True])
281 280
 
... ...
@@ -292,17 +283,16 @@ class TestV2Manager(unittest.TestCase):
292 292
             state='present'
293 293
         ))
294 294
 
295
-        client = AnsibleF5Client(
295
+        module = AnsibleModule(
296 296
             argument_spec=self.spec.argument_spec,
297
-            supports_check_mode=self.spec.supports_check_mode,
298
-            f5_product_name=self.spec.f5_product_name
297
+            supports_check_mode=self.spec.supports_check_mode
299 298
         )
300 299
 
301 300
         # Override methods to force specific logic in the module to happen
302
-        mm = ModuleManager(client)
301
+        mm = ModuleManager(module=module)
303 302
         mm.is_version_v1 = Mock(return_value=False)
304 303
 
305
-        vm = V2Manager(client)
304
+        vm = V2Manager(module=module)
306 305
         vm.create_on_device = Mock(return_value=True)
307 306
         vm.exists = Mock(side_effect=[False, True])
308 307
 
... ...
@@ -319,17 +309,16 @@ class TestV2Manager(unittest.TestCase):
319 319
             state='installed'
320 320
         ))
321 321
 
322
-        client = AnsibleF5Client(
322
+        module = AnsibleModule(
323 323
             argument_spec=self.spec.argument_spec,
324
-            supports_check_mode=self.spec.supports_check_mode,
325
-            f5_product_name=self.spec.f5_product_name
324
+            supports_check_mode=self.spec.supports_check_mode
326 325
         )
327 326
 
328 327
         # Override methods to force specific logic in the module to happen
329
-        mm = ModuleManager(client)
328
+        mm = ModuleManager(module=module)
330 329
         mm.is_version_v1 = Mock(return_value=False)
331 330
 
332
-        vm = V2Manager(client)
331
+        vm = V2Manager(module=module)
333 332
         vm.create_on_device = Mock(return_value=True)
334 333
         vm.exists = Mock(return_value=True)
335 334
         vm.install_on_device = Mock(return_value=True)
... ...
@@ -347,17 +336,16 @@ class TestV2Manager(unittest.TestCase):
347 347
             state='absent'
348 348
         ))
349 349
 
350
-        client = AnsibleF5Client(
350
+        module = AnsibleModule(
351 351
             argument_spec=self.spec.argument_spec,
352
-            supports_check_mode=self.spec.supports_check_mode,
353
-            f5_product_name=self.spec.f5_product_name
352
+            supports_check_mode=self.spec.supports_check_mode
354 353
         )
355 354
 
356 355
         # Override methods to force specific logic in the module to happen
357
-        mm = ModuleManager(client)
356
+        mm = ModuleManager(module=module)
358 357
         mm.is_version_v1 = Mock(return_value=False)
359 358
 
360
-        vm = V1Manager(client)
359
+        vm = V1Manager(module=module)
361 360
         vm.remove_from_device = Mock(return_value=True)
362 361
         vm.exists = Mock(side_effect=[True, False])
363 362
 
... ...
@@ -374,17 +362,16 @@ class TestV2Manager(unittest.TestCase):
374 374
             state='absent'
375 375
         ))
376 376
 
377
-        client = AnsibleF5Client(
377
+        module = AnsibleModule(
378 378
             argument_spec=self.spec.argument_spec,
379
-            supports_check_mode=self.spec.supports_check_mode,
380
-            f5_product_name=self.spec.f5_product_name
379
+            supports_check_mode=self.spec.supports_check_mode
381 380
         )
382 381
 
383 382
         # Override methods to force specific logic in the module to happen
384
-        mm = ModuleManager(client)
383
+        mm = ModuleManager(module=module)
385 384
         mm.is_version_v1 = Mock(return_value=False)
386 385
 
387
-        vm = V1Manager(client)
386
+        vm = V1Manager(module=module)
388 387
         vm.remove_from_device = Mock(return_value=True)
389 388
         vm.exists = Mock(side_effect=[True, True])
390 389
 
... ...
@@ -18,8 +18,7 @@ if sys.version_info < (2, 7):
18 18
 from ansible.compat.tests import unittest
19 19
 from ansible.compat.tests.mock import Mock
20 20
 from ansible.compat.tests.mock import patch
21
-from ansible.module_utils.f5_utils import AnsibleF5Client
22
-from ansible.module_utils.f5_utils import F5ModuleError
21
+from ansible.module_utils.basic import AnsibleModule
23 22
 
24 23
 try:
25 24
     from library.bigip_user import Parameters
... ...
@@ -27,7 +26,8 @@ try:
27 27
     from library.bigip_user import ArgumentSpec
28 28
     from library.bigip_user import UnparitionedManager
29 29
     from library.bigip_user import PartitionedManager
30
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
30
+    from library.module_utils.network.f5.common import F5ModuleError
31
+    from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
31 32
     from test.unit.modules.utils import set_module_args
32 33
 except ImportError:
33 34
     try:
... ...
@@ -36,7 +36,8 @@ except ImportError:
36 36
         from ansible.modules.network.f5.bigip_user import ArgumentSpec
37 37
         from ansible.modules.network.f5.bigip_user import UnparitionedManager
38 38
         from ansible.modules.network.f5.bigip_user import PartitionedManager
39
-        from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
39
+        from ansible.module_utils.network.f5.common import F5ModuleError
40
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
40 41
         from units.modules.utils import set_module_args
41 42
     except ImportError:
42 43
         raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
... ...
@@ -74,7 +75,7 @@ class TestParameters(unittest.TestCase):
74 74
             update_password='always'
75 75
         )
76 76
 
77
-        p = Parameters(args)
77
+        p = Parameters(params=args)
78 78
         assert p.username_credential == 'someuser'
79 79
         assert p.password_credential == 'testpass'
80 80
         assert p.full_name == 'Fake Person'
... ...
@@ -91,7 +92,7 @@ class TestParameters(unittest.TestCase):
91 91
             shell='none'
92 92
         )
93 93
 
94
-        p = Parameters(args)
94
+        p = Parameters(params=args)
95 95
         assert p.name == 'someuser'
96 96
         assert p.password == 'testpass'
97 97
         assert p.full_name == 'Fake Person'
... ...
@@ -99,8 +100,6 @@ class TestParameters(unittest.TestCase):
99 99
         assert p.shell == 'none'
100 100
 
101 101
 
102
-@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
103
-       return_value=True)
104 102
 class TestManager(unittest.TestCase):
105 103
 
106 104
     def setUp(self):
... ...
@@ -118,21 +117,21 @@ class TestManager(unittest.TestCase):
118 118
             update_password='on_create'
119 119
         ))
120 120
 
121
-        client = AnsibleF5Client(
121
+        module = AnsibleModule(
122 122
             argument_spec=self.spec.argument_spec,
123
-            supports_check_mode=self.spec.supports_check_mode,
124
-            f5_product_name=self.spec.f5_product_name
123
+            supports_check_mode=self.spec.supports_check_mode
125 124
         )
126 125
 
127 126
         # Override methods to force specific logic in the module to happen
128
-        mm = ModuleManager(client)
129
-        mm.is_version_less_than_13 = Mock(return_value=False)
130
-
131
-        pm = PartitionedManager(client)
127
+        pm = PartitionedManager(module=module, params=module.params)
132 128
         pm.create_on_device = Mock(return_value=True)
133 129
         pm.exists = Mock(return_value=False)
134 130
 
135
-        results = pm.exec_module()
131
+        mm = ModuleManager(module=module)
132
+        mm.is_version_less_than_13 = Mock(return_value=False)
133
+        mm.get_manager = Mock(return_value=pm)
134
+
135
+        results = mm.exec_module()
136 136
 
137 137
         assert results['changed'] is True
138 138
         assert results['partition_access'] == access
... ...
@@ -147,21 +146,21 @@ class TestManager(unittest.TestCase):
147 147
             user='admin'
148 148
         ))
149 149
 
150
-        client = AnsibleF5Client(
150
+        module = AnsibleModule(
151 151
             argument_spec=self.spec.argument_spec,
152
-            supports_check_mode=self.spec.supports_check_mode,
153
-            f5_product_name=self.spec.f5_product_name
152
+            supports_check_mode=self.spec.supports_check_mode
154 153
         )
155 154
 
156 155
         # Override methods to force specific logic in the module to happen
157
-        mm = ModuleManager(client)
158
-        mm.is_version_less_than_13 = Mock(return_value=False)
159
-
160
-        pm = PartitionedManager(client)
156
+        pm = PartitionedManager(module=module, params=module.params)
161 157
         pm.create_on_device = Mock(return_value=True)
162 158
         pm.exists = Mock(return_value=False)
163 159
 
164
-        results = pm.exec_module()
160
+        mm = ModuleManager(module=module)
161
+        mm.is_version_less_than_13 = Mock(return_value=False)
162
+        mm.get_manager = Mock(return_value=pm)
163
+
164
+        results = mm.exec_module()
165 165
 
166 166
         assert results['changed'] is True
167 167
         assert results['partition_access'] == access
... ...
@@ -177,26 +176,26 @@ class TestManager(unittest.TestCase):
177 177
             user='admin'
178 178
         ))
179 179
 
180
-        client = AnsibleF5Client(
180
+        module = AnsibleModule(
181 181
             argument_spec=self.spec.argument_spec,
182
-            supports_check_mode=self.spec.supports_check_mode,
183
-            f5_product_name=self.spec.f5_product_name
182
+            supports_check_mode=self.spec.supports_check_mode
184 183
         )
185 184
 
186 185
         # Override methods to force specific logic in the module to happen
187
-        mm = ModuleManager(client)
188
-        mm.is_version_less_than_13 = Mock(return_value=False)
189
-
190
-        pm = PartitionedManager(client)
186
+        pm = PartitionedManager(module=module, params=module.params)
191 187
         pm.create_on_device = Mock(return_value=True)
192 188
         pm.exists = Mock(return_value=False)
193 189
 
190
+        mm = ModuleManager(module=module)
191
+        mm.is_version_less_than_13 = Mock(return_value=False)
192
+        mm.get_manager = Mock(return_value=pm)
193
+
194 194
         msg = "The 'update_password' option " \
195 195
               "needs to be set to 'on_create' when creating " \
196 196
               "a resource with a password."
197 197
 
198 198
         with pytest.raises(F5ModuleError) as ex:
199
-            pm.exec_module()
199
+            mm.exec_module()
200 200
         assert str(ex.value) == msg
201 201
 
202 202
     def test_create_user_partition_access_raises(self, *args):
... ...
@@ -207,25 +206,25 @@ class TestManager(unittest.TestCase):
207 207
             user='admin'
208 208
         ))
209 209
 
210
-        client = AnsibleF5Client(
210
+        module = AnsibleModule(
211 211
             argument_spec=self.spec.argument_spec,
212
-            supports_check_mode=self.spec.supports_check_mode,
213
-            f5_product_name=self.spec.f5_product_name
212
+            supports_check_mode=self.spec.supports_check_mode
214 213
         )
215 214
 
216 215
         # Override methods to force specific logic in the module to happen
217
-        mm = ModuleManager(client)
218
-        mm.is_version_less_than_13 = Mock(return_value=False)
219
-
220
-        pm = PartitionedManager(client)
216
+        pm = PartitionedManager(module=module, params=module.params)
221 217
         pm.create_on_device = Mock(return_value=True)
222 218
         pm.exists = Mock(return_value=False)
223 219
 
220
+        mm = ModuleManager(module=module)
221
+        mm.is_version_less_than_13 = Mock(return_value=False)
222
+        mm.get_manager = Mock(return_value=pm)
223
+
224 224
         msg = "The 'partition_access' option " \
225 225
               "is required when creating a resource."
226 226
 
227 227
         with pytest.raises(F5ModuleError) as ex:
228
-            pm.exec_module()
228
+            mm.exec_module()
229 229
         assert str(ex.value) == msg
230 230
 
231 231
     def test_create_user_shell_bash(self, *args):
... ...
@@ -241,21 +240,21 @@ class TestManager(unittest.TestCase):
241 241
             shell='bash'
242 242
         ))
243 243
 
244
-        client = AnsibleF5Client(
244
+        module = AnsibleModule(
245 245
             argument_spec=self.spec.argument_spec,
246
-            supports_check_mode=self.spec.supports_check_mode,
247
-            f5_product_name=self.spec.f5_product_name
246
+            supports_check_mode=self.spec.supports_check_mode
248 247
         )
249 248
 
250 249
         # Override methods to force specific logic in the module to happen
251
-        mm = ModuleManager(client)
252
-        mm.is_version_less_than_13 = Mock(return_value=False)
253
-
254
-        pm = PartitionedManager(client)
250
+        pm = PartitionedManager(module=module, params=module.params)
255 251
         pm.create_on_device = Mock(return_value=True)
256 252
         pm.exists = Mock(return_value=False)
257 253
 
258
-        results = pm.exec_module()
254
+        mm = ModuleManager(module=module)
255
+        mm.is_version_less_than_13 = Mock(return_value=False)
256
+        mm.get_manager = Mock(return_value=pm)
257
+
258
+        results = mm.exec_module()
259 259
 
260 260
         assert results['changed'] is True
261 261
         assert results['partition_access'] == access
... ...
@@ -273,25 +272,25 @@ class TestManager(unittest.TestCase):
273 273
             shell='bash'
274 274
         ))
275 275
 
276
-        client = AnsibleF5Client(
276
+        module = AnsibleModule(
277 277
             argument_spec=self.spec.argument_spec,
278
-            supports_check_mode=self.spec.supports_check_mode,
279
-            f5_product_name=self.spec.f5_product_name
278
+            supports_check_mode=self.spec.supports_check_mode
280 279
         )
281 280
 
282 281
         # Override methods to force specific logic in the module to happen
283
-        mm = ModuleManager(client)
284
-        mm.is_version_less_than_13 = Mock(return_value=False)
285
-
286
-        pm = PartitionedManager(client)
282
+        pm = PartitionedManager(module=module, params=module.params)
287 283
         pm.create_on_device = Mock(return_value=True)
288 284
         pm.exists = Mock(return_value=False)
289 285
 
286
+        mm = ModuleManager(module=module)
287
+        mm.is_version_less_than_13 = Mock(return_value=False)
288
+        mm.get_manager = Mock(return_value=pm)
289
+
290 290
         msg = "Shell access is only available to 'admin' or " \
291 291
               "'resource-admin' roles"
292 292
 
293 293
         with pytest.raises(F5ModuleError) as ex:
294
-            pm.exec_module()
294
+            mm.exec_module()
295 295
         assert str(ex.value) == msg
296 296
 
297 297
     def test_update_user_password_no_pass(self, *args):
... ...
@@ -303,26 +302,26 @@ class TestManager(unittest.TestCase):
303 303
             user='admin'
304 304
         ))
305 305
 
306
-        client = AnsibleF5Client(
306
+        module = AnsibleModule(
307 307
             argument_spec=self.spec.argument_spec,
308
-            supports_check_mode=self.spec.supports_check_mode,
309
-            f5_product_name=self.spec.f5_product_name
308
+            supports_check_mode=self.spec.supports_check_mode
310 309
         )
311 310
 
312 311
         # Configure the parameters that would be returned by querying the
313 312
         # remote device
314
-        current = Parameters(load_fixture('load_auth_user_no_pass.json'))
313
+        current = Parameters(params=load_fixture('load_auth_user_no_pass.json'))
315 314
 
316 315
         # Override methods to force specific logic in the module to happen
317
-        mm = ModuleManager(client)
318
-        mm.is_version_less_than_13 = Mock(return_value=False)
319
-
320
-        pm = PartitionedManager(client)
316
+        pm = PartitionedManager(module=module, params=module.params)
321 317
         pm.exists = Mock(return_value=True)
322 318
         pm.update_on_device = Mock(return_value=True)
323 319
         pm.read_current_from_device = Mock(return_value=current)
324 320
 
325
-        results = pm.exec_module()
321
+        mm = ModuleManager(module=module)
322
+        mm.is_version_less_than_13 = Mock(return_value=False)
323
+        mm.get_manager = Mock(return_value=pm)
324
+
325
+        results = mm.exec_module()
326 326
 
327 327
         assert results['changed'] is True
328 328
 
... ...
@@ -335,26 +334,26 @@ class TestManager(unittest.TestCase):
335 335
             user='admin'
336 336
         ))
337 337
 
338
-        client = AnsibleF5Client(
338
+        module = AnsibleModule(
339 339
             argument_spec=self.spec.argument_spec,
340
-            supports_check_mode=self.spec.supports_check_mode,
341
-            f5_product_name=self.spec.f5_product_name
340
+            supports_check_mode=self.spec.supports_check_mode
342 341
         )
343 342
 
344 343
         # Configure the parameters that would be returned by querying the
345 344
         # remote device
346
-        current = Parameters(load_fixture('load_auth_user_with_pass.json'))
345
+        current = Parameters(params=load_fixture('load_auth_user_with_pass.json'))
347 346
 
348 347
         # Override methods to force specific logic in the module to happen
349
-        mm = ModuleManager(client)
350
-        mm.is_version_less_than_13 = Mock(return_value=False)
351
-
352
-        pm = PartitionedManager(client)
348
+        pm = PartitionedManager(module=module, params=module.params)
353 349
         pm.exists = Mock(return_value=True)
354 350
         pm.update_on_device = Mock(return_value=True)
355 351
         pm.read_current_from_device = Mock(return_value=current)
356 352
 
357
-        results = pm.exec_module()
353
+        mm = ModuleManager(module=module)
354
+        mm.is_version_less_than_13 = Mock(return_value=False)
355
+        mm.get_manager = Mock(return_value=pm)
356
+
357
+        results = mm.exec_module()
358 358
 
359 359
         assert results['changed'] is True
360 360
 
... ...
@@ -367,31 +366,31 @@ class TestManager(unittest.TestCase):
367 367
             shell='none'
368 368
         ))
369 369
 
370
-        client = AnsibleF5Client(
370
+        module = AnsibleModule(
371 371
             argument_spec=self.spec.argument_spec,
372
-            supports_check_mode=self.spec.supports_check_mode,
373
-            f5_product_name=self.spec.f5_product_name
372
+            supports_check_mode=self.spec.supports_check_mode
374 373
         )
375 374
 
376 375
         # Configure the parameters that would be returned by querying the
377 376
         # remote device
378 377
         current = Parameters(
379
-            dict(
378
+            params=dict(
380 379
                 user='admin',
381 380
                 shell='tmsh'
382 381
             )
383 382
         )
384 383
 
385 384
         # Override methods to force specific logic in the module to happen
386
-        mm = ModuleManager(client)
387
-        mm.is_version_less_than_13 = Mock(return_value=False)
388
-
389
-        pm = PartitionedManager(client)
385
+        pm = PartitionedManager(module=module, params=module.params)
390 386
         pm.exists = Mock(return_value=True)
391 387
         pm.update_on_device = Mock(return_value=True)
392 388
         pm.read_current_from_device = Mock(return_value=current)
393 389
 
394
-        results = pm.exec_module()
390
+        mm = ModuleManager(module=module)
391
+        mm.is_version_less_than_13 = Mock(return_value=False)
392
+        mm.get_manager = Mock(return_value=pm)
393
+
394
+        results = mm.exec_module()
395 395
 
396 396
         assert results['changed'] is True
397 397
         assert results['shell'] == 'none'
... ...
@@ -405,32 +404,32 @@ class TestManager(unittest.TestCase):
405 405
             shell='none'
406 406
         ))
407 407
 
408
-        client = AnsibleF5Client(
408
+        module = AnsibleModule(
409 409
             argument_spec=self.spec.argument_spec,
410
-            supports_check_mode=self.spec.supports_check_mode,
411
-            f5_product_name=self.spec.f5_product_name
410
+            supports_check_mode=self.spec.supports_check_mode
412 411
         )
413 412
 
414 413
         # Configure the parameters that would be returned by querying the
415 414
         # remote device
416 415
         access = [{'name': 'Common', 'role': 'guest'}]
417 416
         current = Parameters(
418
-            dict(
417
+            params=dict(
419 418
                 user='admin',
420 419
                 partition_access=access
421 420
             )
422 421
         )
423 422
 
424 423
         # Override methods to force specific logic in the module to happen
425
-        mm = ModuleManager(client)
426
-        mm.is_version_less_than_13 = Mock(return_value=False)
427
-
428
-        pm = PartitionedManager(client)
424
+        pm = PartitionedManager(module=module, params=module.params)
429 425
         pm.exists = Mock(return_value=True)
430 426
         pm.update_on_device = Mock(return_value=True)
431 427
         pm.read_current_from_device = Mock(return_value=current)
432 428
 
433
-        results = pm.exec_module()
429
+        mm = ModuleManager(module=module)
430
+        mm.is_version_less_than_13 = Mock(return_value=False)
431
+        mm.get_manager = Mock(return_value=pm)
432
+
433
+        results = mm.exec_module()
434 434
 
435 435
         assert results['changed'] is False
436 436
         assert not hasattr(results, 'shell')
... ...
@@ -444,17 +443,16 @@ class TestManager(unittest.TestCase):
444 444
             shell='bash'
445 445
         ))
446 446
 
447
-        client = AnsibleF5Client(
447
+        module = AnsibleModule(
448 448
             argument_spec=self.spec.argument_spec,
449
-            supports_check_mode=self.spec.supports_check_mode,
450
-            f5_product_name=self.spec.f5_product_name
449
+            supports_check_mode=self.spec.supports_check_mode
451 450
         )
452 451
 
453 452
         # Configure the parameters that would be returned by querying the
454 453
         # remote device
455 454
         access = [{'name': 'all', 'role': 'admin'}]
456 455
         current = Parameters(
457
-            dict(
456
+            params=dict(
458 457
                 user='admin',
459 458
                 shell='tmsh',
460 459
                 partition_access=access
... ...
@@ -462,15 +460,16 @@ class TestManager(unittest.TestCase):
462 462
         )
463 463
 
464 464
         # Override methods to force specific logic in the module to happen
465
-        mm = ModuleManager(client)
466
-        mm.is_version_less_than_13 = Mock(return_value=True)
467
-
468
-        upm = UnparitionedManager(client)
465
+        upm = UnparitionedManager(module=module, params=module.params)
469 466
         upm.exists = Mock(return_value=True)
470 467
         upm.update_on_device = Mock(return_value=True)
471 468
         upm.read_current_from_device = Mock(return_value=current)
472 469
 
473
-        results = upm.exec_module()
470
+        mm = ModuleManager(module=module)
471
+        mm.is_version_less_than_13 = Mock(return_value=True)
472
+        mm.get_manager = Mock(return_value=upm)
473
+
474
+        results = mm.exec_module()
474 475
 
475 476
         assert results['changed'] is True
476 477
         assert results['shell'] == 'bash'
... ...
@@ -484,10 +483,9 @@ class TestManager(unittest.TestCase):
484 484
             shell='bash'
485 485
         ))
486 486
 
487
-        client = AnsibleF5Client(
487
+        module = AnsibleModule(
488 488
             argument_spec=self.spec.argument_spec,
489
-            supports_check_mode=self.spec.supports_check_mode,
490
-            f5_product_name=self.spec.f5_product_name
489
+            supports_check_mode=self.spec.supports_check_mode
491 490
         )
492 491
 
493 492
         # Configure the parameters that would be returned by querying the
... ...
@@ -497,7 +495,7 @@ class TestManager(unittest.TestCase):
497 497
             {'name': 'all', 'role': 'guest'}
498 498
         ]
499 499
         current = Parameters(
500
-            dict(
500
+            params=dict(
501 501
                 user='admin',
502 502
                 shell='tmsh',
503 503
                 partition_access=access
... ...
@@ -505,24 +503,23 @@ class TestManager(unittest.TestCase):
505 505
         )
506 506
 
507 507
         # Override methods to force specific logic in the module to happen
508
-        mm = ModuleManager(client)
509
-        mm.is_version_less_than_13 = Mock(return_value=True)
510
-
511
-        upm = UnparitionedManager(client)
508
+        upm = UnparitionedManager(module=module, params=module.params)
512 509
         upm.exists = Mock(return_value=True)
513 510
         upm.update_on_device = Mock(return_value=True)
514 511
         upm.read_current_from_device = Mock(return_value=current)
515 512
 
513
+        mm = ModuleManager(module=module)
514
+        mm.is_version_less_than_13 = Mock(return_value=True)
515
+        mm.get_manager = Mock(return_value=upm)
516
+
516 517
         msg = "Shell access is only available to 'admin' or " \
517 518
               "'resource-admin' roles"
518 519
 
519 520
         with pytest.raises(F5ModuleError) as ex:
520
-            upm.exec_module()
521
+            mm.exec_module()
521 522
         assert str(ex.value) == msg
522 523
 
523 524
 
524
-@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
525
-       return_value=True)
526 525
 class TestLegacyManager(unittest.TestCase):
527 526
 
528 527
     def setUp(self):
... ...
@@ -540,21 +537,21 @@ class TestLegacyManager(unittest.TestCase):
540 540
             update_password='on_create'
541 541
         ))
542 542
 
543
-        client = AnsibleF5Client(
543
+        module = AnsibleModule(
544 544
             argument_spec=self.spec.argument_spec,
545
-            supports_check_mode=self.spec.supports_check_mode,
546
-            f5_product_name=self.spec.f5_product_name
545
+            supports_check_mode=self.spec.supports_check_mode
547 546
         )
548 547
 
549 548
         # Override methods to force specific logic in the module to happen
550
-        mm = ModuleManager(client)
551
-        mm.is_version_less_than_13 = Mock(return_value=True)
552
-
553
-        upm = UnparitionedManager(client)
549
+        upm = UnparitionedManager(module=module, params=module.params)
554 550
         upm.create_on_device = Mock(return_value=True)
555 551
         upm.exists = Mock(return_value=False)
556 552
 
557
-        results = upm.exec_module()
553
+        mm = ModuleManager(module=module)
554
+        mm.is_version_less_than_13 = Mock(return_value=True)
555
+        mm.get_manager = Mock(return_value=upm)
556
+
557
+        results = mm.exec_module()
558 558
 
559 559
         assert results['changed'] is True
560 560
         assert results['partition_access'] == access
... ...
@@ -569,21 +566,21 @@ class TestLegacyManager(unittest.TestCase):
569 569
             user='admin'
570 570
         ))
571 571
 
572
-        client = AnsibleF5Client(
572
+        module = AnsibleModule(
573 573
             argument_spec=self.spec.argument_spec,
574
-            supports_check_mode=self.spec.supports_check_mode,
575
-            f5_product_name=self.spec.f5_product_name
574
+            supports_check_mode=self.spec.supports_check_mode
576 575
         )
577 576
 
578 577
         # Override methods to force specific logic in the module to happen
579
-        mm = ModuleManager(client)
580
-        mm.is_version_less_than_13 = Mock(return_value=True)
581
-
582
-        upm = UnparitionedManager(client)
578
+        upm = UnparitionedManager(module=module, params=module.params)
583 579
         upm.create_on_device = Mock(return_value=True)
584 580
         upm.exists = Mock(return_value=False)
585 581
 
586
-        results = upm.exec_module()
582
+        mm = ModuleManager(module=module)
583
+        mm.is_version_less_than_13 = Mock(return_value=True)
584
+        mm.get_manager = Mock(return_value=upm)
585
+
586
+        results = mm.exec_module()
587 587
 
588 588
         assert results['changed'] is True
589 589
         assert results['partition_access'] == access
... ...
@@ -599,26 +596,26 @@ class TestLegacyManager(unittest.TestCase):
599 599
             user='admin'
600 600
         ))
601 601
 
602
-        client = AnsibleF5Client(
602
+        module = AnsibleModule(
603 603
             argument_spec=self.spec.argument_spec,
604
-            supports_check_mode=self.spec.supports_check_mode,
605
-            f5_product_name=self.spec.f5_product_name
604
+            supports_check_mode=self.spec.supports_check_mode
606 605
         )
607 606
 
608 607
         # Override methods to force specific logic in the module to happen
609
-        mm = ModuleManager(client)
610
-        mm.is_version_less_than_13 = Mock(return_value=True)
611
-
612
-        upm = UnparitionedManager(client)
608
+        upm = UnparitionedManager(module=module, params=module.params)
613 609
         upm.create_on_device = Mock(return_value=True)
614 610
         upm.exists = Mock(return_value=False)
615 611
 
612
+        mm = ModuleManager(module=module)
613
+        mm.is_version_less_than_13 = Mock(return_value=True)
614
+        mm.get_manager = Mock(return_value=upm)
615
+
616 616
         msg = "The 'update_password' option " \
617 617
               "needs to be set to 'on_create' when creating " \
618 618
               "a resource with a password."
619 619
 
620 620
         with pytest.raises(F5ModuleError) as ex:
621
-            upm.exec_module()
621
+            mm.exec_module()
622 622
         assert str(ex.value) == msg
623 623
 
624 624
     def test_create_user_partition_access_raises(self, *args):
... ...
@@ -629,25 +626,25 @@ class TestLegacyManager(unittest.TestCase):
629 629
             user='admin'
630 630
         ))
631 631
 
632
-        client = AnsibleF5Client(
632
+        module = AnsibleModule(
633 633
             argument_spec=self.spec.argument_spec,
634
-            supports_check_mode=self.spec.supports_check_mode,
635
-            f5_product_name=self.spec.f5_product_name
634
+            supports_check_mode=self.spec.supports_check_mode
636 635
         )
637 636
 
638 637
         # Override methods to force specific logic in the module to happen
639
-        mm = ModuleManager(client)
640
-        mm.is_version_less_than_13 = Mock(return_value=True)
641
-
642
-        upm = UnparitionedManager(client)
638
+        upm = UnparitionedManager(module=module, params=module.params)
643 639
         upm.create_on_device = Mock(return_value=True)
644 640
         upm.exists = Mock(return_value=False)
645 641
 
642
+        mm = ModuleManager(module=module)
643
+        mm.is_version_less_than_13 = Mock(return_value=True)
644
+        mm.get_manager = Mock(return_value=upm)
645
+
646 646
         msg = "The 'partition_access' option " \
647 647
               "is required when creating a resource."
648 648
 
649 649
         with pytest.raises(F5ModuleError) as ex:
650
-            upm.exec_module()
650
+            mm.exec_module()
651 651
         assert str(ex.value) == msg
652 652
 
653 653
     def test_create_user_shell_bash(self, *args):
... ...
@@ -663,21 +660,21 @@ class TestLegacyManager(unittest.TestCase):
663 663
             shell='bash'
664 664
         ))
665 665
 
666
-        client = AnsibleF5Client(
666
+        module = AnsibleModule(
667 667
             argument_spec=self.spec.argument_spec,
668
-            supports_check_mode=self.spec.supports_check_mode,
669
-            f5_product_name=self.spec.f5_product_name
668
+            supports_check_mode=self.spec.supports_check_mode
670 669
         )
671 670
 
672 671
         # Override methods to force specific logic in the module to happen
673
-        mm = ModuleManager(client)
674
-        mm.is_version_less_than_13 = Mock(return_value=True)
675
-
676
-        upm = UnparitionedManager(client)
672
+        upm = UnparitionedManager(module=module, params=module.params)
677 673
         upm.create_on_device = Mock(return_value=True)
678 674
         upm.exists = Mock(return_value=False)
679 675
 
680
-        results = upm.exec_module()
676
+        mm = ModuleManager(module=module)
677
+        mm.is_version_less_than_13 = Mock(return_value=True)
678
+        mm.get_manager = Mock(return_value=upm)
679
+
680
+        results = mm.exec_module()
681 681
 
682 682
         assert results['changed'] is True
683 683
         assert results['partition_access'] == access
... ...
@@ -695,25 +692,25 @@ class TestLegacyManager(unittest.TestCase):
695 695
             shell='bash'
696 696
         ))
697 697
 
698
-        client = AnsibleF5Client(
698
+        module = AnsibleModule(
699 699
             argument_spec=self.spec.argument_spec,
700
-            supports_check_mode=self.spec.supports_check_mode,
701
-            f5_product_name=self.spec.f5_product_name
700
+            supports_check_mode=self.spec.supports_check_mode
702 701
         )
703 702
 
704 703
         # Override methods to force specific logic in the module to happen
705
-        mm = ModuleManager(client)
706
-        mm.is_version_less_than_13 = Mock(return_value=True)
707
-
708
-        upm = UnparitionedManager(client)
704
+        upm = UnparitionedManager(module=module, params=module.params)
709 705
         upm.create_on_device = Mock(return_value=True)
710 706
         upm.exists = Mock(return_value=False)
711 707
 
708
+        mm = ModuleManager(module=module)
709
+        mm.is_version_less_than_13 = Mock(return_value=True)
710
+        mm.get_manager = Mock(return_value=upm)
711
+
712 712
         msg = "Shell access is only available to 'admin' or " \
713 713
               "'resource-admin' roles"
714 714
 
715 715
         with pytest.raises(F5ModuleError) as ex:
716
-            upm.exec_module()
716
+            mm.exec_module()
717 717
         assert str(ex.value) == msg
718 718
 
719 719
     def test_update_user_password(self, *args):
... ...
@@ -725,32 +722,32 @@ class TestLegacyManager(unittest.TestCase):
725 725
             user='admin'
726 726
         ))
727 727
 
728
-        client = AnsibleF5Client(
728
+        module = AnsibleModule(
729 729
             argument_spec=self.spec.argument_spec,
730
-            supports_check_mode=self.spec.supports_check_mode,
731
-            f5_product_name=self.spec.f5_product_name
730
+            supports_check_mode=self.spec.supports_check_mode
732 731
         )
733 732
 
734 733
         # Configure the parameters that would be returned by querying the
735 734
         # remote device
736 735
         access = [{'name': 'Common', 'role': 'guest'}]
737 736
         current = Parameters(
738
-            dict(
737
+            params=dict(
739 738
                 shell='tmsh',
740 739
                 partition_access=access
741 740
             )
742 741
         )
743 742
 
744 743
         # Override methods to force specific logic in the module to happen
745
-        mm = ModuleManager(client)
746
-        mm.is_version_less_than_13 = Mock(return_value=True)
747
-
748
-        upm = UnparitionedManager(client)
744
+        upm = UnparitionedManager(module=module, params=module.params)
749 745
         upm.exists = Mock(return_value=True)
750 746
         upm.update_on_device = Mock(return_value=True)
751 747
         upm.read_current_from_device = Mock(return_value=current)
752 748
 
753
-        results = upm.exec_module()
749
+        mm = ModuleManager(module=module)
750
+        mm.is_version_less_than_13 = Mock(return_value=True)
751
+        mm.get_manager = Mock(return_value=upm)
752
+
753
+        results = mm.exec_module()
754 754
 
755 755
         assert results['changed'] is True
756 756
 
... ...
@@ -763,31 +760,31 @@ class TestLegacyManager(unittest.TestCase):
763 763
             shell='none'
764 764
         ))
765 765
 
766
-        client = AnsibleF5Client(
766
+        module = AnsibleModule(
767 767
             argument_spec=self.spec.argument_spec,
768
-            supports_check_mode=self.spec.supports_check_mode,
769
-            f5_product_name=self.spec.f5_product_name
768
+            supports_check_mode=self.spec.supports_check_mode
770 769
         )
771 770
 
772 771
         # Configure the parameters that would be returned by querying the
773 772
         # remote device
774 773
         current = Parameters(
775
-            dict(
774
+            params=dict(
776 775
                 user='admin',
777 776
                 shell='tmsh'
778 777
             )
779 778
         )
780 779
 
781 780
         # Override methods to force specific logic in the module to happen
782
-        mm = ModuleManager(client)
783
-        mm.is_version_less_than_13 = Mock(return_value=True)
784
-
785
-        upm = UnparitionedManager(client)
781
+        upm = UnparitionedManager(module=module, params=module.params)
786 782
         upm.exists = Mock(return_value=True)
787 783
         upm.update_on_device = Mock(return_value=True)
788 784
         upm.read_current_from_device = Mock(return_value=current)
789 785
 
790
-        results = upm.exec_module()
786
+        mm = ModuleManager(module=module)
787
+        mm.is_version_less_than_13 = Mock(return_value=True)
788
+        mm.get_manager = Mock(return_value=upm)
789
+
790
+        results = mm.exec_module()
791 791
 
792 792
         assert results['changed'] is True
793 793
         assert results['shell'] == 'none'
... ...
@@ -801,32 +798,32 @@ class TestLegacyManager(unittest.TestCase):
801 801
             shell='none'
802 802
         ))
803 803
 
804
-        client = AnsibleF5Client(
804
+        module = AnsibleModule(
805 805
             argument_spec=self.spec.argument_spec,
806
-            supports_check_mode=self.spec.supports_check_mode,
807
-            f5_product_name=self.spec.f5_product_name
806
+            supports_check_mode=self.spec.supports_check_mode
808 807
         )
809 808
 
810 809
         # Configure the parameters that would be returned by querying the
811 810
         # remote device
812 811
         access = [{'name': 'Common', 'role': 'guest'}]
813 812
         current = Parameters(
814
-            dict(
813
+            params=dict(
815 814
                 user='admin',
816 815
                 partition_access=access
817 816
             )
818 817
         )
819 818
 
820 819
         # Override methods to force specific logic in the module to happen
821
-        mm = ModuleManager(client)
822
-        mm.is_version_less_than_13 = Mock(return_value=True)
823
-
824
-        upm = UnparitionedManager(client)
820
+        upm = UnparitionedManager(module=module, params=module.params)
825 821
         upm.exists = Mock(return_value=True)
826 822
         upm.update_on_device = Mock(return_value=True)
827 823
         upm.read_current_from_device = Mock(return_value=current)
828 824
 
829
-        results = upm.exec_module()
825
+        mm = ModuleManager(module=module)
826
+        mm.is_version_less_than_13 = Mock(return_value=True)
827
+        mm.get_manager = Mock(return_value=upm)
828
+
829
+        results = mm.exec_module()
830 830
 
831 831
         assert results['changed'] is False
832 832
         assert not hasattr(results, 'shell')
... ...
@@ -840,17 +837,16 @@ class TestLegacyManager(unittest.TestCase):
840 840
             shell='bash'
841 841
         ))
842 842
 
843
-        client = AnsibleF5Client(
843
+        module = AnsibleModule(
844 844
             argument_spec=self.spec.argument_spec,
845
-            supports_check_mode=self.spec.supports_check_mode,
846
-            f5_product_name=self.spec.f5_product_name
845
+            supports_check_mode=self.spec.supports_check_mode
847 846
         )
848 847
 
849 848
         # Configure the parameters that would be returned by querying the
850 849
         # remote device
851 850
         access = [{'name': 'all', 'role': 'admin'}]
852 851
         current = Parameters(
853
-            dict(
852
+            params=dict(
854 853
                 user='admin',
855 854
                 shell='tmsh',
856 855
                 partition_access=access
... ...
@@ -858,15 +854,16 @@ class TestLegacyManager(unittest.TestCase):
858 858
         )
859 859
 
860 860
         # Override methods to force specific logic in the module to happen
861
-        mm = ModuleManager(client)
862
-        mm.is_version_less_than_13 = Mock(return_value=True)
863
-
864
-        upm = UnparitionedManager(client)
861
+        upm = UnparitionedManager(module=module, params=module.params)
865 862
         upm.exists = Mock(return_value=True)
866 863
         upm.update_on_device = Mock(return_value=True)
867 864
         upm.read_current_from_device = Mock(return_value=current)
868 865
 
869
-        results = upm.exec_module()
866
+        mm = ModuleManager(module=module)
867
+        mm.is_version_less_than_13 = Mock(return_value=True)
868
+        mm.get_manager = Mock(return_value=upm)
869
+
870
+        results = mm.exec_module()
870 871
 
871 872
         assert results['changed'] is True
872 873
         assert results['shell'] == 'bash'
... ...
@@ -880,10 +877,9 @@ class TestLegacyManager(unittest.TestCase):
880 880
             shell='bash'
881 881
         ))
882 882
 
883
-        client = AnsibleF5Client(
883
+        module = AnsibleModule(
884 884
             argument_spec=self.spec.argument_spec,
885
-            supports_check_mode=self.spec.supports_check_mode,
886
-            f5_product_name=self.spec.f5_product_name
885
+            supports_check_mode=self.spec.supports_check_mode
887 886
         )
888 887
 
889 888
         # Configure the parameters that would be returned by querying the
... ...
@@ -893,7 +889,7 @@ class TestLegacyManager(unittest.TestCase):
893 893
             {'name': 'all', 'role': 'guest'}
894 894
         ]
895 895
         current = Parameters(
896
-            dict(
896
+            params=dict(
897 897
                 user='admin',
898 898
                 shell='tmsh',
899 899
                 partition_access=access
... ...
@@ -901,17 +897,18 @@ class TestLegacyManager(unittest.TestCase):
901 901
         )
902 902
 
903 903
         # Override methods to force specific logic in the module to happen
904
-        mm = ModuleManager(client)
905
-        mm.is_version_less_than_13 = Mock(return_value=True)
906
-
907
-        upm = UnparitionedManager(client)
904
+        upm = UnparitionedManager(module=module, params=module.params)
908 905
         upm.exists = Mock(return_value=True)
909 906
         upm.update_on_device = Mock(return_value=True)
910 907
         upm.read_current_from_device = Mock(return_value=current)
911 908
 
909
+        mm = ModuleManager(module=module)
910
+        mm.is_version_less_than_13 = Mock(return_value=True)
911
+        mm.get_manager = Mock(return_value=upm)
912
+
912 913
         msg = "Shell access is only available to 'admin' or " \
913 914
               "'resource-admin' roles"
914 915
 
915 916
         with pytest.raises(F5ModuleError) as ex:
916
-            upm.exec_module()
917
+            mm.exec_module()
917 918
         assert str(ex.value) == msg
... ...
@@ -18,20 +18,22 @@ if sys.version_info < (2, 7):
18 18
 from ansible.compat.tests import unittest
19 19
 from ansible.compat.tests.mock import Mock
20 20
 from ansible.compat.tests.mock import patch
21
-from ansible.module_utils.f5_utils import AnsibleF5Client
21
+from ansible.module_utils.basic import AnsibleModule
22 22
 
23 23
 try:
24 24
     from library.bigip_vcmp_guest import Parameters
25 25
     from library.bigip_vcmp_guest import ModuleManager
26 26
     from library.bigip_vcmp_guest import ArgumentSpec
27
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
27
+    from library.module_utils.network.f5.common import F5ModuleError
28
+    from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
28 29
     from test.unit.modules.utils import set_module_args
29 30
 except ImportError:
30 31
     try:
31 32
         from ansible.modules.network.f5.bigip_vcmp_guest import Parameters
32 33
         from ansible.modules.network.f5.bigip_vcmp_guest import ModuleManager
33 34
         from ansible.modules.network.f5.bigip_vcmp_guest import ArgumentSpec
34
-        from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
35
+        from ansible.module_utils.network.f5.common import F5ModuleError
36
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
35 37
         from units.modules.utils import set_module_args
36 38
     except ImportError:
37 39
         raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
... ...
@@ -70,7 +72,7 @@ class TestParameters(unittest.TestCase):
70 70
             ]
71 71
         )
72 72
 
73
-        p = Parameters(args)
73
+        p = Parameters(params=args)
74 74
         assert p.initial_image == 'BIGIP-12.1.0.1.0.1447-HF1.iso'
75 75
         assert p.mgmt_network == 'bridged'
76 76
 
... ...
@@ -80,7 +82,7 @@ class TestParameters(unittest.TestCase):
80 80
             mgmt_address='1.2.3.4'
81 81
         )
82 82
 
83
-        p = Parameters(args)
83
+        p = Parameters(params=args)
84 84
         assert p.mgmt_network == 'bridged'
85 85
         assert p.mgmt_address == '1.2.3.4/32'
86 86
 
... ...
@@ -90,7 +92,7 @@ class TestParameters(unittest.TestCase):
90 90
             mgmt_address='1.2.3.4/24'
91 91
         )
92 92
 
93
-        p = Parameters(args)
93
+        p = Parameters(params=args)
94 94
         assert p.mgmt_network == 'bridged'
95 95
         assert p.mgmt_address == '1.2.3.4/24'
96 96
 
... ...
@@ -100,7 +102,7 @@ class TestParameters(unittest.TestCase):
100 100
             mgmt_address='1.2.3.4/255.255.255.0'
101 101
         )
102 102
 
103
-        p = Parameters(args)
103
+        p = Parameters(params=args)
104 104
         assert p.mgmt_network == 'bridged'
105 105
         assert p.mgmt_address == '1.2.3.4/24'
106 106
 
... ...
@@ -109,7 +111,7 @@ class TestParameters(unittest.TestCase):
109 109
             mgmt_route='1.2.3.4'
110 110
         )
111 111
 
112
-        p = Parameters(args)
112
+        p = Parameters(params=args)
113 113
         assert p.mgmt_route == '1.2.3.4'
114 114
 
115 115
     def test_module_parameters_vcmp_software_image_facts(self):
... ...
@@ -120,7 +122,7 @@ class TestParameters(unittest.TestCase):
120 120
             initial_image='BIGIP-12.1.0.1.0.1447-HF1.iso/1',
121 121
         )
122 122
 
123
-        p = Parameters(args)
123
+        p = Parameters(params=args)
124 124
         assert p.initial_image == 'BIGIP-12.1.0.1.0.1447-HF1.iso/1'
125 125
 
126 126
     def test_api_parameters(self):
... ...
@@ -136,7 +138,7 @@ class TestParameters(unittest.TestCase):
136 136
             ]
137 137
         )
138 138
 
139
-        p = Parameters(args)
139
+        p = Parameters(params=args)
140 140
         assert p.initial_image == 'BIGIP-tmos-tier2-13.1.0.0.0.931.iso'
141 141
         assert p.mgmt_route == '2.2.2.2'
142 142
         assert p.mgmt_address == '1.1.1.1/24'
... ...
@@ -144,8 +146,6 @@ class TestParameters(unittest.TestCase):
144 144
         assert '/Common/vlan2' in p.vlans
145 145
 
146 146
 
147
-@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
148
-       return_value=True)
149 147
 class TestManager(unittest.TestCase):
150 148
     def setUp(self):
151 149
         self.spec = ArgumentSpec()
... ...
@@ -161,14 +161,13 @@ class TestManager(unittest.TestCase):
161 161
             user='admin'
162 162
         ))
163 163
 
164
-        client = AnsibleF5Client(
164
+        module = AnsibleModule(
165 165
             argument_spec=self.spec.argument_spec,
166
-            supports_check_mode=self.spec.supports_check_mode,
167
-            f5_product_name=self.spec.f5_product_name
166
+            supports_check_mode=self.spec.supports_check_mode
168 167
         )
169 168
 
170 169
         # Override methods to force specific logic in the module to happen
171
-        mm = ModuleManager(client)
170
+        mm = ModuleManager(module=module)
172 171
         mm.create_on_device = Mock(return_value=True)
173 172
         mm.exists = Mock(return_value=False)
174 173
         mm.is_deployed = Mock(side_effect=[False, True, True, True, True])
... ...
@@ -17,20 +17,22 @@ if sys.version_info < (2, 7):
17 17
 from ansible.compat.tests import unittest
18 18
 from ansible.compat.tests.mock import Mock
19 19
 from ansible.compat.tests.mock import patch
20
-from ansible.module_utils.f5_utils import AnsibleF5Client
20
+from ansible.module_utils.basic import AnsibleModule
21 21
 
22 22
 try:
23 23
     from library.bigip_virtual_address import Parameters
24 24
     from library.bigip_virtual_address import ModuleManager
25 25
     from library.bigip_virtual_address import ArgumentSpec
26
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
26
+    from library.module_utils.network.f5.common import F5ModuleError
27
+    from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
27 28
     from test.unit.modules.utils import set_module_args
28 29
 except ImportError:
29 30
     try:
30 31
         from ansible.modules.network.f5.bigip_virtual_address import Parameters
31 32
         from ansible.modules.network.f5.bigip_virtual_address import ModuleManager
32 33
         from ansible.modules.network.f5.bigip_virtual_address import ArgumentSpec
33
-        from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
34
+        from ansible.module_utils.network.f5.common import F5ModuleError
35
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
34 36
         from units.modules.utils import set_module_args
35 37
     except ImportError:
36 38
         raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
... ...
@@ -70,7 +72,7 @@ class TestParameters(unittest.TestCase):
70 70
             advertise_route='always',
71 71
             use_route_advertisement='yes'
72 72
         )
73
-        p = Parameters(args)
73
+        p = Parameters(params=args)
74 74
         assert p.state == 'present'
75 75
         assert p.address == '1.1.1.1'
76 76
         assert p.netmask == '2.2.2.2'
... ...
@@ -83,7 +85,7 @@ class TestParameters(unittest.TestCase):
83 83
 
84 84
     def test_api_parameters(self):
85 85
         args = load_fixture('load_ltm_virtual_address_default.json')
86
-        p = Parameters(args)
86
+        p = Parameters(params=args)
87 87
         assert p.name == '1.1.1.1'
88 88
         assert p.address == '1.1.1.1'
89 89
         assert p.arp_state == 'enabled'
... ...
@@ -99,56 +101,56 @@ class TestParameters(unittest.TestCase):
99 99
         args = dict(
100 100
             advertise_route='when_all_available'
101 101
         )
102
-        p = Parameters(args)
102
+        p = Parameters(params=args)
103 103
         assert p.advertise_route == 'all'
104 104
 
105 105
     def test_module_parameters_advertise_route_any(self):
106 106
         args = dict(
107 107
             advertise_route='when_any_available'
108 108
         )
109
-        p = Parameters(args)
109
+        p = Parameters(params=args)
110 110
         assert p.advertise_route == 'any'
111 111
 
112 112
     def test_module_parameters_icmp_echo_disabled(self):
113 113
         args = dict(
114 114
             icmp_echo='disabled'
115 115
         )
116
-        p = Parameters(args)
116
+        p = Parameters(params=args)
117 117
         assert p.icmp_echo == 'disabled'
118 118
 
119 119
     def test_module_parameters_icmp_echo_selective(self):
120 120
         args = dict(
121 121
             icmp_echo='selective'
122 122
         )
123
-        p = Parameters(args)
123
+        p = Parameters(params=args)
124 124
         assert p.icmp_echo == 'selective'
125 125
 
126 126
     def test_module_parameters_auto_delete_disabled(self):
127 127
         args = dict(
128 128
             auto_delete='disabled'
129 129
         )
130
-        p = Parameters(args)
130
+        p = Parameters(params=args)
131 131
         assert p.auto_delete is False
132 132
 
133 133
     def test_module_parameters_arp_state_disabled(self):
134 134
         args = dict(
135 135
             arp_state='disabled'
136 136
         )
137
-        p = Parameters(args)
137
+        p = Parameters(params=args)
138 138
         assert p.arp_state == 'disabled'
139 139
 
140 140
     def test_module_parameters_use_route_advert_disabled(self):
141 141
         args = dict(
142 142
             use_route_advertisement='no'
143 143
         )
144
-        p = Parameters(args)
144
+        p = Parameters(params=args)
145 145
         assert p.use_route_advertisement == 'disabled'
146 146
 
147 147
     def test_module_parameters_state_present(self):
148 148
         args = dict(
149 149
             state='present'
150 150
         )
151
-        p = Parameters(args)
151
+        p = Parameters(params=args)
152 152
         assert p.state == 'present'
153 153
         assert p.enabled == 'yes'
154 154
 
... ...
@@ -156,14 +158,14 @@ class TestParameters(unittest.TestCase):
156 156
         args = dict(
157 157
             state='absent'
158 158
         )
159
-        p = Parameters(args)
159
+        p = Parameters(params=args)
160 160
         assert p.state == 'absent'
161 161
 
162 162
     def test_module_parameters_state_enabled(self):
163 163
         args = dict(
164 164
             state='enabled'
165 165
         )
166
-        p = Parameters(args)
166
+        p = Parameters(params=args)
167 167
         assert p.state == 'enabled'
168 168
         assert p.enabled == 'yes'
169 169
 
... ...
@@ -171,13 +173,11 @@ class TestParameters(unittest.TestCase):
171 171
         args = dict(
172 172
             state='disabled'
173 173
         )
174
-        p = Parameters(args)
174
+        p = Parameters(params=args)
175 175
         assert p.state == 'disabled'
176 176
         assert p.enabled == 'no'
177 177
 
178 178
 
179
-@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
180
-       return_value=True)
181 179
 class TestManager(unittest.TestCase):
182 180
 
183 181
     def setUp(self):
... ...
@@ -199,12 +199,11 @@ class TestManager(unittest.TestCase):
199 199
             user='admin',
200 200
         ))
201 201
 
202
-        client = AnsibleF5Client(
202
+        module = AnsibleModule(
203 203
             argument_spec=self.spec.argument_spec,
204
-            supports_check_mode=self.spec.supports_check_mode,
205
-            f5_product_name=self.spec.f5_product_name
204
+            supports_check_mode=self.spec.supports_check_mode
206 205
         )
207
-        mm = ModuleManager(client)
206
+        mm = ModuleManager(module=module)
208 207
 
209 208
         # Override methods to force specific logic in the module to happen
210 209
         mm.exists = Mock(side_effect=[False, True])
... ...
@@ -222,12 +221,11 @@ class TestManager(unittest.TestCase):
222 222
             user='admin',
223 223
         ))
224 224
 
225
-        client = AnsibleF5Client(
225
+        module = AnsibleModule(
226 226
             argument_spec=self.spec.argument_spec,
227
-            supports_check_mode=self.spec.supports_check_mode,
228
-            f5_product_name=self.spec.f5_product_name
227
+            supports_check_mode=self.spec.supports_check_mode
229 228
         )
230
-        mm = ModuleManager(client)
229
+        mm = ModuleManager(module=module)
231 230
 
232 231
         # Override methods to force specific logic in the module to happen
233 232
         mm.exists = Mock(side_effect=[True, False])
... ...
@@ -17,28 +17,24 @@ if sys.version_info < (2, 7):
17 17
 from ansible.compat.tests import unittest
18 18
 from ansible.compat.tests.mock import Mock
19 19
 from ansible.compat.tests.mock import patch
20
-from ansible.module_utils.f5_utils import AnsibleF5Client
20
+from ansible.module_utils.basic import AnsibleModule
21 21
 
22 22
 try:
23
-    from library.bigip_virtual_server import VirtualAddressParameters
24
-    from library.bigip_virtual_server import VirtualServerModuleParameters
25
-    from library.bigip_virtual_server import VirtualServerApiParameters
23
+    from library.bigip_virtual_server import ModuleParameters
24
+    from library.bigip_virtual_server import ApiParameters
26 25
     from library.bigip_virtual_server import ModuleManager
27
-    from library.bigip_virtual_server import VirtualServerManager
28
-    from library.bigip_virtual_server import VirtualAddressManager
29 26
     from library.bigip_virtual_server import ArgumentSpec
30
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
27
+    from library.module_utils.network.f5.common import F5ModuleError
28
+    from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
31 29
     from test.unit.modules.utils import set_module_args
32 30
 except ImportError:
33 31
     try:
34
-        from ansible.modules.network.f5.bigip_virtual_server import VirtualAddressParameters
35
-        from ansible.modules.network.f5.bigip_virtual_server import VirtualServerApiParameters
36
-        from ansible.modules.network.f5.bigip_virtual_server import VirtualServerModuleParameters
32
+        from ansible.modules.network.f5.bigip_virtual_server import ApiParameters
33
+        from ansible.modules.network.f5.bigip_virtual_server import ModuleParameters
37 34
         from ansible.modules.network.f5.bigip_virtual_server import ModuleManager
38
-        from ansible.modules.network.f5.bigip_virtual_server import VirtualServerManager
39
-        from ansible.modules.network.f5.bigip_virtual_server import VirtualAddressManager
40 35
         from ansible.modules.network.f5.bigip_virtual_server import ArgumentSpec
41
-        from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
36
+        from ansible.module_utils.network.f5.common import F5ModuleError
37
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
42 38
         from units.modules.utils import set_module_args
43 39
     except ImportError:
44 40
         raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
... ...
@@ -70,14 +66,14 @@ class TestParameters(unittest.TestCase):
70 70
         args = dict(
71 71
             destination='1.1.1.1'
72 72
         )
73
-        p = VirtualServerApiParameters(args)
73
+        p = ApiParameters(params=args)
74 74
         assert p.destination_tuple.ip == '1.1.1.1'
75 75
 
76 76
     def test_destination_mutex_2(self):
77 77
         args = dict(
78 78
             destination='1.1.1.1%2'
79 79
         )
80
-        p = VirtualServerApiParameters(args)
80
+        p = ApiParameters(params=args)
81 81
         assert p.destination_tuple.ip == '1.1.1.1'
82 82
         assert p.destination_tuple.route_domain == 2
83 83
 
... ...
@@ -85,7 +81,7 @@ class TestParameters(unittest.TestCase):
85 85
         args = dict(
86 86
             destination='1.1.1.1:80'
87 87
         )
88
-        p = VirtualServerApiParameters(args)
88
+        p = ApiParameters(params=args)
89 89
         assert p.destination_tuple.ip == '1.1.1.1'
90 90
         assert p.destination_tuple.port == 80
91 91
 
... ...
@@ -93,7 +89,7 @@ class TestParameters(unittest.TestCase):
93 93
         args = dict(
94 94
             destination='1.1.1.1%2:80'
95 95
         )
96
-        p = VirtualServerApiParameters(args)
96
+        p = ApiParameters(params=args)
97 97
         assert p.destination_tuple.ip == '1.1.1.1'
98 98
         assert p.destination_tuple.port == 80
99 99
         assert p.destination_tuple.route_domain == 2
... ...
@@ -102,14 +98,14 @@ class TestParameters(unittest.TestCase):
102 102
         args = dict(
103 103
             destination='/Common/1.1.1.1'
104 104
         )
105
-        p = VirtualServerApiParameters(args)
105
+        p = ApiParameters(params=args)
106 106
         assert p.destination_tuple.ip == '1.1.1.1'
107 107
 
108 108
     def test_api_destination_mutex_6(self):
109 109
         args = dict(
110 110
             destination='/Common/1.1.1.1%2'
111 111
         )
112
-        p = VirtualServerApiParameters(args)
112
+        p = ApiParameters(params=args)
113 113
         assert p.destination_tuple.ip == '1.1.1.1'
114 114
         assert p.destination_tuple.route_domain == 2
115 115
 
... ...
@@ -117,7 +113,7 @@ class TestParameters(unittest.TestCase):
117 117
         args = dict(
118 118
             destination='/Common/1.1.1.1:80'
119 119
         )
120
-        p = VirtualServerApiParameters(args)
120
+        p = ApiParameters(params=args)
121 121
         assert p.destination_tuple.ip == '1.1.1.1'
122 122
         assert p.destination_tuple.port == 80
123 123
 
... ...
@@ -125,7 +121,7 @@ class TestParameters(unittest.TestCase):
125 125
         args = dict(
126 126
             destination='/Common/1.1.1.1%2:80'
127 127
         )
128
-        p = VirtualServerApiParameters(args)
128
+        p = ApiParameters(params=args)
129 129
         assert p.destination_tuple.ip == '1.1.1.1'
130 130
         assert p.destination_tuple.port == 80
131 131
         assert p.destination_tuple.route_domain == 2
... ...
@@ -134,14 +130,14 @@ class TestParameters(unittest.TestCase):
134 134
         args = dict(
135 135
             destination='2700:bc00:1f10:101::6'
136 136
         )
137
-        p = VirtualServerApiParameters(args)
137
+        p = ApiParameters(params=args)
138 138
         assert p.destination_tuple.ip == '2700:bc00:1f10:101::6'
139 139
 
140 140
     def test_destination_mutex_10(self):
141 141
         args = dict(
142 142
             destination='2700:bc00:1f10:101::6%2'
143 143
         )
144
-        p = VirtualServerApiParameters(args)
144
+        p = ApiParameters(params=args)
145 145
         assert p.destination_tuple.ip == '2700:bc00:1f10:101::6'
146 146
         assert p.destination_tuple.route_domain == 2
147 147
 
... ...
@@ -149,7 +145,7 @@ class TestParameters(unittest.TestCase):
149 149
         args = dict(
150 150
             destination='2700:bc00:1f10:101::6.80'
151 151
         )
152
-        p = VirtualServerApiParameters(args)
152
+        p = ApiParameters(params=args)
153 153
         assert p.destination_tuple.ip == '2700:bc00:1f10:101::6'
154 154
         assert p.destination_tuple.port == 80
155 155
 
... ...
@@ -157,26 +153,11 @@ class TestParameters(unittest.TestCase):
157 157
         args = dict(
158 158
             destination='2700:bc00:1f10:101::6%2.80'
159 159
         )
160
-        p = VirtualServerApiParameters(args)
160
+        p = ApiParameters(params=args)
161 161
         assert p.destination_tuple.ip == '2700:bc00:1f10:101::6'
162 162
         assert p.destination_tuple.port == 80
163 163
         assert p.destination_tuple.route_domain == 2
164 164
 
165
-#
166
-#    def test_destination_mutex_6(self):
167
-#        args = dict(
168
-#            destination='/Common/2700:bc00:1f10:101::6'
169
-#        )
170
-#        p = VirtualServerParameters(args)
171
-#        assert p.destination_tuple.ip == '2700:bc00:1f10:101::6'
172
-#
173
-#    def test_destination_mutex_5(self):
174
-#        args = dict(
175
-#            destination='/Common/2700:bc00:1f10:101::6'
176
-#        )
177
-#        p = VirtualServerParameters(args)
178
-#        assert p.destination_tuple.ip == '2700:bc00:1f10:101::6'
179
-
180 165
     def test_module_no_partition_prefix_parameters(self):
181 166
         args = dict(
182 167
             server='localhost',
... ...
@@ -198,7 +179,7 @@ class TestParameters(unittest.TestCase):
198 198
             ],
199 199
             enabled_vlans=['vlan2']
200 200
         )
201
-        p = VirtualServerModuleParameters(args)
201
+        p = ModuleParameters(params=args)
202 202
         assert p.name == 'my-virtual-server'
203 203
         assert p.partition == 'Common'
204 204
         assert p.port == 443
... ...
@@ -235,7 +216,7 @@ class TestParameters(unittest.TestCase):
235 235
             ],
236 236
             enabled_vlans=['/Common/vlan2']
237 237
         )
238
-        p = VirtualServerModuleParameters(args)
238
+        p = ModuleParameters(params=args)
239 239
         assert p.name == 'my-virtual-server'
240 240
         assert p.partition == 'Common'
241 241
         assert p.port == 443
... ...
@@ -342,7 +323,7 @@ class TestParameters(unittest.TestCase):
342 342
                 ]
343 343
             }
344 344
         }
345
-        p = VirtualServerApiParameters(args)
345
+        p = ApiParameters(params=args)
346 346
         assert p.name == 'my-virtual-server'
347 347
         assert p.partition == 'Common'
348 348
         assert p.port == 443
... ...
@@ -358,8 +339,6 @@ class TestParameters(unittest.TestCase):
358 358
         assert '/Common/net1' in p.vlans
359 359
 
360 360
 
361
-@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
362
-       return_value=True)
363 361
 class TestManager(unittest.TestCase):
364 362
 
365 363
     def setUp(self):
... ...
@@ -388,19 +367,15 @@ class TestManager(unittest.TestCase):
388 388
             validate_certs="no"
389 389
         ))
390 390
 
391
-        client = AnsibleF5Client(
391
+        module = AnsibleModule(
392 392
             argument_spec=self.spec.argument_spec,
393
-            supports_check_mode=self.spec.supports_check_mode,
394
-            f5_product_name=self.spec.f5_product_name
393
+            supports_check_mode=self.spec.supports_check_mode
395 394
         )
396 395
 
397 396
         # Override methods to force specific logic in the module to happen
398
-        vsm = VirtualServerManager(client)
399
-        vsm.exists = Mock(return_value=False)
400
-        vsm.create_on_device = Mock(return_value=True)
401
-
402
-        mm = ModuleManager(client)
403
-        mm.get_manager = Mock(return_value=vsm)
397
+        mm = ModuleManager(module=module)
398
+        mm.exists = Mock(return_value=False)
399
+        mm.create_on_device = Mock(return_value=True)
404 400
         results = mm.exec_module()
405 401
 
406 402
         assert results['changed'] is True
... ...
@@ -423,18 +398,14 @@ class TestManager(unittest.TestCase):
423 423
             validate_certs="no"
424 424
         ))
425 425
 
426
-        client = AnsibleF5Client(
426
+        module = AnsibleModule(
427 427
             argument_spec=self.spec.argument_spec,
428
-            supports_check_mode=self.spec.supports_check_mode,
429
-            f5_product_name=self.spec.f5_product_name
428
+            supports_check_mode=self.spec.supports_check_mode
430 429
         )
431 430
 
432 431
         # Override methods to force specific logic in the module to happen
433
-        vsm = VirtualServerManager(client)
434
-        vsm.exists = Mock(return_value=False)
435
-
436
-        mm = ModuleManager(client)
437
-        mm.get_manager = Mock(return_value=vsm)
432
+        mm = ModuleManager(module=module)
433
+        mm.exists = Mock(return_value=False)
438 434
 
439 435
         results = mm.exec_module()
440 436
 
... ...
@@ -460,26 +431,22 @@ class TestManager(unittest.TestCase):
460 460
 
461 461
         # Configure the parameters that would be returned by querying the
462 462
         # remote device
463
-        current = VirtualServerApiParameters(
463
+        current = ApiParameters(
464 464
             dict(
465 465
                 agent_status_traps='disabled'
466 466
             )
467 467
         )
468 468
 
469
-        client = AnsibleF5Client(
469
+        module = AnsibleModule(
470 470
             argument_spec=self.spec.argument_spec,
471
-            supports_check_mode=self.spec.supports_check_mode,
472
-            f5_product_name=self.spec.f5_product_name
471
+            supports_check_mode=self.spec.supports_check_mode
473 472
         )
474 473
 
475 474
         # Override methods to force specific logic in the module to happen
476
-        vsm = VirtualServerManager(client)
477
-        vsm.exists = Mock(return_value=False)
478
-        vsm.update_on_device = Mock(return_value=True)
479
-        vsm.read_current_from_device = Mock(return_value=current)
480
-
481
-        mm = ModuleManager(client)
482
-        mm.get_manager = Mock(return_value=vsm)
475
+        mm = ModuleManager(module=module)
476
+        mm.exists = Mock(return_value=False)
477
+        mm.update_on_device = Mock(return_value=True)
478
+        mm.read_current_from_device = Mock(return_value=current)
483 479
         results = mm.exec_module()
484 480
 
485 481
         assert results['changed'] is False
... ...
@@ -498,22 +465,18 @@ class TestManager(unittest.TestCase):
498 498
 
499 499
         # Configure the parameters that would be returned by querying the
500 500
         # remote device
501
-        current = VirtualServerApiParameters(load_fixture('load_ltm_virtual_1.json'))
501
+        current = ApiParameters(params=load_fixture('load_ltm_virtual_1.json'))
502 502
 
503
-        client = AnsibleF5Client(
503
+        module = AnsibleModule(
504 504
             argument_spec=self.spec.argument_spec,
505
-            supports_check_mode=self.spec.supports_check_mode,
506
-            f5_product_name=self.spec.f5_product_name
505
+            supports_check_mode=self.spec.supports_check_mode
507 506
         )
508 507
 
509 508
         # Override methods to force specific logic in the module to happen
510
-        vsm = VirtualServerManager(client)
511
-        vsm.exists = Mock(return_value=True)
512
-        vsm.read_current_from_device = Mock(return_value=current)
513
-        vsm.update_on_device = Mock(return_value=True)
514
-
515
-        mm = ModuleManager(client)
516
-        mm.get_manager = Mock(return_value=vsm)
509
+        mm = ModuleManager(module=module)
510
+        mm.exists = Mock(return_value=True)
511
+        mm.read_current_from_device = Mock(return_value=current)
512
+        mm.update_on_device = Mock(return_value=True)
517 513
         results = mm.exec_module()
518 514
 
519 515
         assert results['changed'] is True
... ...
@@ -532,21 +495,17 @@ class TestManager(unittest.TestCase):
532 532
 
533 533
         # Configure the parameters that would be returned by querying the
534 534
         # remote device
535
-        current = VirtualServerApiParameters(load_fixture('load_ltm_virtual_1.json'))
535
+        current = ApiParameters(params=load_fixture('load_ltm_virtual_1.json'))
536 536
 
537
-        client = AnsibleF5Client(
537
+        module = AnsibleModule(
538 538
             argument_spec=self.spec.argument_spec,
539
-            supports_check_mode=self.spec.supports_check_mode,
540
-            f5_product_name=self.spec.f5_product_name
539
+            supports_check_mode=self.spec.supports_check_mode
541 540
         )
542 541
 
543 542
         # Override methods to force specific logic in the module to happen
544
-        vsm = VirtualServerManager(client)
545
-        vsm.exists = Mock(return_value=True)
546
-        vsm.read_current_from_device = Mock(return_value=current)
547
-
548
-        mm = ModuleManager(client)
549
-        mm.get_manager = Mock(return_value=vsm)
543
+        mm = ModuleManager(module=module)
544
+        mm.exists = Mock(return_value=True)
545
+        mm.read_current_from_device = Mock(return_value=current)
550 546
         results = mm.exec_module()
551 547
 
552 548
         assert results['changed'] is False
... ...
@@ -567,21 +526,17 @@ class TestManager(unittest.TestCase):
567 567
 
568 568
         # Configure the parameters that would be returned by querying the
569 569
         # remote device
570
-        current = VirtualServerApiParameters(load_fixture('load_ltm_virtual_2.json'))
570
+        current = ApiParameters(params=load_fixture('load_ltm_virtual_2.json'))
571 571
 
572
-        client = AnsibleF5Client(
572
+        module = AnsibleModule(
573 573
             argument_spec=self.spec.argument_spec,
574
-            supports_check_mode=self.spec.supports_check_mode,
575
-            f5_product_name=self.spec.f5_product_name
574
+            supports_check_mode=self.spec.supports_check_mode
576 575
         )
577 576
 
578 577
         # Override methods to force specific logic in the module to happen
579
-        vsm = VirtualServerManager(client)
580
-        vsm.exists = Mock(return_value=True)
581
-        vsm.read_current_from_device = Mock(return_value=current)
582
-
583
-        mm = ModuleManager(client)
584
-        mm.get_manager = Mock(return_value=vsm)
578
+        mm = ModuleManager(module=module)
579
+        mm.exists = Mock(return_value=True)
580
+        mm.read_current_from_device = Mock(return_value=current)
585 581
 
586 582
         results = mm.exec_module()
587 583
 
... ...
@@ -603,22 +558,18 @@ class TestManager(unittest.TestCase):
603 603
 
604 604
         # Configure the parameters that would be returned by querying the
605 605
         # remote device
606
-        current = VirtualServerApiParameters(load_fixture('load_ltm_virtual_2.json'))
606
+        current = ApiParameters(params=load_fixture('load_ltm_virtual_2.json'))
607 607
 
608
-        client = AnsibleF5Client(
608
+        module = AnsibleModule(
609 609
             argument_spec=self.spec.argument_spec,
610
-            supports_check_mode=self.spec.supports_check_mode,
611
-            f5_product_name=self.spec.f5_product_name
610
+            supports_check_mode=self.spec.supports_check_mode
612 611
         )
613 612
 
614 613
         # Override methods to force specific logic in the module to happen
615
-        vsm = VirtualServerManager(client)
616
-        vsm.exists = Mock(return_value=True)
617
-        vsm.read_current_from_device = Mock(return_value=current)
618
-        vsm.update_on_device = Mock(return_value=True)
619
-
620
-        mm = ModuleManager(client)
621
-        mm.get_manager = Mock(return_value=vsm)
614
+        mm = ModuleManager(module=module)
615
+        mm.exists = Mock(return_value=True)
616
+        mm.read_current_from_device = Mock(return_value=current)
617
+        mm.update_on_device = Mock(return_value=True)
622 618
 
623 619
         results = mm.exec_module()
624 620
 
... ...
@@ -674,22 +625,18 @@ class TestManager(unittest.TestCase):
674 674
 
675 675
         # Configure the parameters that would be returned by querying the
676 676
         # remote device
677
-        current = VirtualServerApiParameters(load_fixture('load_ltm_virtual_3.json'))
677
+        current = ApiParameters(params=load_fixture('load_ltm_virtual_3.json'))
678 678
 
679
-        client = AnsibleF5Client(
679
+        module = AnsibleModule(
680 680
             argument_spec=self.spec.argument_spec,
681
-            supports_check_mode=self.spec.supports_check_mode,
682
-            f5_product_name=self.spec.f5_product_name
681
+            supports_check_mode=self.spec.supports_check_mode
683 682
         )
684 683
 
685 684
         # Override methods to force specific logic in the module to happen
686
-        vsm = VirtualServerManager(client)
687
-        vsm.exists = Mock(return_value=True)
688
-        vsm.read_current_from_device = Mock(return_value=current)
689
-        vsm.update_on_device = Mock(return_value=True)
690
-
691
-        mm = ModuleManager(client)
692
-        mm.get_manager = Mock(return_value=vsm)
685
+        mm = ModuleManager(module=module)
686
+        mm.exists = Mock(return_value=True)
687
+        mm.read_current_from_device = Mock(return_value=current)
688
+        mm.update_on_device = Mock(return_value=True)
693 689
 
694 690
         results = mm.exec_module()
695 691
 
... ...
@@ -727,47 +674,3 @@ class TestManager(unittest.TestCase):
727 727
         assert 'context' in results['profiles'][1]
728 728
         assert results['profiles'][1]['name'] == 'clientssl'
729 729
         assert results['profiles'][1]['context'] == 'clientside'
730
-
731
-
732
-@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
733
-       return_value=True)
734
-class TestDeprecatedAnsible24Manager(unittest.TestCase):
735
-    def setUp(self):
736
-        self.spec = ArgumentSpec()
737
-
738
-    def test_modify_port_idempotent(self, *args):
739
-        set_module_args(dict(
740
-            destination="10.10.10.10",
741
-            name="my-virtual-server",
742
-            route_advertisement_state="enabled",
743
-            partition="Common",
744
-            password="secret",
745
-            port="443",
746
-            server="localhost",
747
-            state="present",
748
-            user="admin",
749
-            validate_certs="no"
750
-        ))
751
-
752
-        client = AnsibleF5Client(
753
-            argument_spec=self.spec.argument_spec,
754
-            supports_check_mode=self.spec.supports_check_mode,
755
-            f5_product_name=self.spec.f5_product_name
756
-        )
757
-
758
-        vsm_current = VirtualServerApiParameters(load_fixture('load_ltm_virtual_1.json'))
759
-        vam_current = VirtualAddressParameters(load_fixture('load_ltm_virtual_1_address.json'))
760
-
761
-        vsm = VirtualServerManager(client)
762
-        vsm.exists = Mock(return_value=True)
763
-        vsm.read_current_from_device = Mock(return_value=vsm_current)
764
-        vam = VirtualAddressManager(client)
765
-        vam.exists = Mock(return_value=True)
766
-        vam.read_current_from_device = Mock(return_value=vam_current)
767
-
768
-        mm = ModuleManager(client)
769
-        mm.get_manager = Mock(side_effect=[vsm, vam])
770
-
771
-        results = mm.exec_module()
772
-
773
-        assert results['changed'] is False
... ...
@@ -8,7 +8,6 @@ __metaclass__ = type
8 8
 
9 9
 import os
10 10
 import json
11
-import pytest
12 11
 import sys
13 12
 
14 13
 from nose.plugins.skip import SkipTest
... ...
@@ -18,21 +17,24 @@ if sys.version_info < (2, 7):
18 18
 from ansible.compat.tests import unittest
19 19
 from ansible.compat.tests.mock import Mock
20 20
 from ansible.compat.tests.mock import patch
21
-from ansible.module_utils.f5_utils import AnsibleF5Client
22
-from ansible.module_utils.f5_utils import F5ModuleError
21
+from ansible.module_utils.basic import AnsibleModule
23 22
 
24 23
 try:
25
-    from library.bigip_vlan import Parameters
24
+    from library.bigip_vlan import ApiParameters
25
+    from library.bigip_vlan import ModuleParameters
26 26
     from library.bigip_vlan import ModuleManager
27 27
     from library.bigip_vlan import ArgumentSpec
28
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
28
+    from library.module_utils.network.f5.common import F5ModuleError
29
+    from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
29 30
     from test.unit.modules.utils import set_module_args
30 31
 except ImportError:
31 32
     try:
32
-        from ansible.modules.network.f5.bigip_vlan import Parameters
33
+        from ansible.modules.network.f5.bigip_vlan import ApiParameters
34
+        from ansible.modules.network.f5.bigip_vlan import ModuleParameters
33 35
         from ansible.modules.network.f5.bigip_vlan import ModuleManager
34 36
         from ansible.modules.network.f5.bigip_vlan import ArgumentSpec
35
-        from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
37
+        from ansible.module_utils.network.f5.common import F5ModuleError
38
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
36 39
         from units.modules.utils import set_module_args
37 40
     except ImportError:
38 41
         raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
... ...
@@ -65,13 +67,6 @@ class BigIpObj(object):
65 65
 
66 66
 
67 67
 class TestParameters(unittest.TestCase):
68
-
69
-    def setUp(self):
70
-        self.loaded_ifcs = []
71
-        ifcs_json = load_fixture('load_net_interfaces.json')
72
-        for item in ifcs_json:
73
-            self.loaded_ifcs.append(BigIpObj(**item))
74
-
75 68
     def test_module_parameters(self):
76 69
         args = dict(
77 70
             name='somevlan',
... ...
@@ -79,9 +74,7 @@ class TestParameters(unittest.TestCase):
79 79
             description='fakevlan',
80 80
             untagged_interfaces=['1.1'],
81 81
         )
82
-        with patch.object(Parameters, '_get_interfaces_from_device') as obj:
83
-            obj.return_value = self.loaded_ifcs
84
-            p = Parameters(args)
82
+        p = ModuleParameters(params=args)
85 83
 
86 84
         assert p.name == 'somevlan'
87 85
         assert p.tag == 213
... ...
@@ -92,38 +85,20 @@ class TestParameters(unittest.TestCase):
92 92
         args = dict(
93 93
             name='somevlan',
94 94
             description='fakevlan',
95
-            tag=213,
96
-            tagged_interfaces=['1.2']
95
+            tag=213
97 96
         )
98 97
 
99
-        with patch.object(Parameters, '_get_interfaces_from_device') as obj:
100
-            obj.return_value = self.loaded_ifcs
101
-            p = Parameters(args)
98
+        p = ApiParameters(params=args)
102 99
 
103 100
         assert p.name == 'somevlan'
104 101
         assert p.tag == 213
105
-        assert p.interfaces == [{'tagged': True, 'name': '1.2'}]
106 102
         assert p.description == 'fakevlan'
107 103
 
108 104
 
109
-@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
110
-       return_value=True)
111 105
 class TestManager(unittest.TestCase):
112 106
 
113 107
     def setUp(self):
114 108
         self.spec = ArgumentSpec()
115
-        self.loaded_ifcs = []
116
-        self.loaded_vlan_ifc_tag = []
117
-        self.loaded_vlan_ifc_untag = []
118
-        ifcs_tag = load_fixture('load_vlan_tagged_ifcs.json')
119
-        ifcs_untag = load_fixture('load_vlan_untag_ifcs.json')
120
-        ifcs_json = load_fixture('load_net_interfaces.json')
121
-        for item in ifcs_json:
122
-            self.loaded_ifcs.append(BigIpObj(**item))
123
-        for item in ifcs_tag:
124
-            self.loaded_vlan_ifc_tag.append(BigIpObj(**item))
125
-        for item in ifcs_untag:
126
-            self.loaded_vlan_ifc_untag.append(BigIpObj(**item))
127 109
 
128 110
     def test_create_vlan(self, *args):
129 111
         set_module_args(dict(
... ...
@@ -135,24 +110,19 @@ class TestManager(unittest.TestCase):
135 135
             partition='Common'
136 136
         ))
137 137
 
138
-        client = AnsibleF5Client(
138
+        module = AnsibleModule(
139 139
             argument_spec=self.spec.argument_spec,
140
-            supports_check_mode=self.spec.supports_check_mode,
141
-            f5_product_name=self.spec.f5_product_name
140
+            supports_check_mode=self.spec.supports_check_mode
142 141
         )
143 142
 
144 143
         # Override methods to force specific logic in the module to happen
145
-        with patch.object(Parameters, '_get_interfaces_from_device') as obj:
146
-            obj.return_value = self.loaded_ifcs
144
+        mm = ModuleManager(module=module)
145
+        mm.create_on_device = Mock(return_value=True)
146
+        mm.exists = Mock(return_value=False)
147 147
 
148
-            mm = ModuleManager(client)
149
-            mm.create_on_device = Mock(return_value=True)
150
-            mm.exists = Mock(return_value=False)
151
-
152
-            results = mm.exec_module()
148
+        results = mm.exec_module()
153 149
 
154 150
         assert results['changed'] is True
155
-        assert results['name'] == 'somevlan'
156 151
         assert results['description'] == 'fakevlan'
157 152
 
158 153
     def test_create_vlan_tagged_interface(self, *args):
... ...
@@ -166,26 +136,21 @@ class TestManager(unittest.TestCase):
166 166
             partition='Common'
167 167
         ))
168 168
 
169
-        client = AnsibleF5Client(
169
+        module = AnsibleModule(
170 170
             argument_spec=self.spec.argument_spec,
171
-            supports_check_mode=self.spec.supports_check_mode,
172
-            f5_product_name=self.spec.f5_product_name
171
+            supports_check_mode=self.spec.supports_check_mode
173 172
         )
174 173
 
175 174
         # Override methods to force specific logic in the module to happen
176
-        with patch.object(Parameters, '_get_interfaces_from_device') as obj:
177
-            obj.return_value = self.loaded_ifcs
178
-
179
-            mm = ModuleManager(client)
180
-            mm.create_on_device = Mock(return_value=True)
181
-            mm.exists = Mock(return_value=False)
175
+        mm = ModuleManager(module=module)
176
+        mm.create_on_device = Mock(return_value=True)
177
+        mm.exists = Mock(return_value=False)
182 178
 
183
-            results = mm.exec_module()
179
+        results = mm.exec_module()
184 180
 
185 181
         assert results['changed'] is True
186
-        assert results['interfaces'] == [{'tagged': True, 'name': '2.1'}]
182
+        assert results['tagged_interfaces'] == ['2.1']
187 183
         assert results['tag'] == 213
188
-        assert results['name'] == 'somevlan'
189 184
 
190 185
     def test_create_vlan_untagged_interface(self, *args):
191 186
         set_module_args(dict(
... ...
@@ -197,25 +162,20 @@ class TestManager(unittest.TestCase):
197 197
             partition='Common'
198 198
         ))
199 199
 
200
-        client = AnsibleF5Client(
200
+        module = AnsibleModule(
201 201
             argument_spec=self.spec.argument_spec,
202
-            supports_check_mode=self.spec.supports_check_mode,
203
-            f5_product_name=self.spec.f5_product_name
202
+            supports_check_mode=self.spec.supports_check_mode
204 203
         )
205 204
 
206 205
         # Override methods to force specific logic in the module to happen
207
-        with patch.object(Parameters, '_get_interfaces_from_device') as obj:
208
-            obj.return_value = self.loaded_ifcs
206
+        mm = ModuleManager(module=module)
207
+        mm.create_on_device = Mock(return_value=True)
208
+        mm.exists = Mock(return_value=False)
209 209
 
210
-            mm = ModuleManager(client)
211
-            mm.create_on_device = Mock(return_value=True)
212
-            mm.exists = Mock(return_value=False)
213
-
214
-            results = mm.exec_module()
210
+        results = mm.exec_module()
215 211
 
216 212
         assert results['changed'] is True
217
-        assert results['interfaces'] == [{'untagged': True, 'name': '2.1'}]
218
-        assert results['name'] == 'somevlan'
213
+        assert results['untagged_interfaces'] == ['2.1']
219 214
 
220 215
     def test_create_vlan_tagged_interfaces(self, *args):
221 216
         set_module_args(dict(
... ...
@@ -228,27 +188,21 @@ class TestManager(unittest.TestCase):
228 228
             partition='Common'
229 229
         ))
230 230
 
231
-        client = AnsibleF5Client(
231
+        module = AnsibleModule(
232 232
             argument_spec=self.spec.argument_spec,
233
-            supports_check_mode=self.spec.supports_check_mode,
234
-            f5_product_name=self.spec.f5_product_name
233
+            supports_check_mode=self.spec.supports_check_mode
235 234
         )
236 235
 
237 236
         # Override methods to force specific logic in the module to happen
238
-        with patch.object(Parameters, '_get_interfaces_from_device') as obj:
239
-            obj.return_value = self.loaded_ifcs
240
-
241
-            mm = ModuleManager(client)
242
-            mm.create_on_device = Mock(return_value=True)
243
-            mm.exists = Mock(return_value=False)
237
+        mm = ModuleManager(module=module)
238
+        mm.create_on_device = Mock(return_value=True)
239
+        mm.exists = Mock(return_value=False)
244 240
 
245
-            results = mm.exec_module()
241
+        results = mm.exec_module()
246 242
 
247 243
         assert results['changed'] is True
248
-        assert results['interfaces'] == [{'tagged': True, 'name': '2.1'},
249
-                                         {'tagged': True, 'name': '1.1'}]
244
+        assert results['tagged_interfaces'] == ['1.1', '2.1']
250 245
         assert results['tag'] == 213
251
-        assert results['name'] == 'somevlan'
252 246
 
253 247
     def test_create_vlan_untagged_interfaces(self, *args):
254 248
         set_module_args(dict(
... ...
@@ -260,26 +214,20 @@ class TestManager(unittest.TestCase):
260 260
             partition='Common',
261 261
         ))
262 262
 
263
-        client = AnsibleF5Client(
263
+        module = AnsibleModule(
264 264
             argument_spec=self.spec.argument_spec,
265
-            supports_check_mode=self.spec.supports_check_mode,
266
-            f5_product_name=self.spec.f5_product_name
265
+            supports_check_mode=self.spec.supports_check_mode
267 266
         )
268 267
 
269 268
         # Override methods to force specific logic in the module to happen
270
-        with patch.object(Parameters, '_get_interfaces_from_device') as obj:
271
-            obj.return_value = self.loaded_ifcs
269
+        mm = ModuleManager(module=module)
270
+        mm.create_on_device = Mock(return_value=True)
271
+        mm.exists = Mock(return_value=False)
272 272
 
273
-            mm = ModuleManager(client)
274
-            mm.create_on_device = Mock(return_value=True)
275
-            mm.exists = Mock(return_value=False)
276
-
277
-            results = mm.exec_module()
273
+        results = mm.exec_module()
278 274
 
279 275
         assert results['changed'] is True
280
-        assert results['interfaces'] == [{'untagged': True, 'name': '2.1'},
281
-                                         {'untagged': True, 'name': '1.1'}]
282
-        assert results['name'] == 'somevlan'
276
+        assert results['untagged_interfaces'] == ['1.1', '2.1']
283 277
 
284 278
     def test_update_vlan_untag_interface(self, *args):
285 279
         set_module_args(dict(
... ...
@@ -291,32 +239,26 @@ class TestManager(unittest.TestCase):
291 291
             partition='Common',
292 292
         ))
293 293
 
294
-        client = AnsibleF5Client(
294
+        module = AnsibleModule(
295 295
             argument_spec=self.spec.argument_spec,
296
-            supports_check_mode=self.spec.supports_check_mode,
297
-            f5_product_name=self.spec.f5_product_name
296
+            supports_check_mode=self.spec.supports_check_mode
298 297
         )
299
-        ifcs = self.loaded_vlan_ifc_untag
298
+
300 299
         # Override methods to force specific logic in the module to happen
301
-        with patch.object(Parameters, '_get_interfaces_from_device') as obj:
302
-            obj.return_value = self.loaded_ifcs
303
-            mm = ModuleManager(client)
300
+        mm = ModuleManager(module=module)
304 301
 
305
-            current = (
306
-                Parameters(
307
-                    load_fixture('load_vlan.json')
308
-                ),
309
-                ifcs
310
-            )
302
+        current = ApiParameters(params=load_fixture('load_vlan.json'))
303
+        interfaces = load_fixture('load_vlan_interfaces.json')
304
+        current.update({'interfaces': interfaces})
311 305
 
312
-            mm.update_on_device = Mock(return_value=True)
313
-            mm.exists = Mock(return_value=True)
314
-            mm.read_current_from_device = Mock(return_value=current)
306
+        mm.update_on_device = Mock(return_value=True)
307
+        mm.exists = Mock(return_value=True)
308
+        mm.read_current_from_device = Mock(return_value=current)
315 309
 
316
-            results = mm.exec_module()
310
+        results = mm.exec_module()
317 311
 
318 312
         assert results['changed'] is True
319
-        assert results['interfaces'] == [{'untagged': True, 'name': '2.1'}]
313
+        assert results['untagged_interfaces'] == ['2.1']
320 314
 
321 315
     def test_update_vlan_tag_interface(self, *args):
322 316
         set_module_args(dict(
... ...
@@ -328,32 +270,24 @@ class TestManager(unittest.TestCase):
328 328
             partition='Common',
329 329
         ))
330 330
 
331
-        client = AnsibleF5Client(
331
+        module = AnsibleModule(
332 332
             argument_spec=self.spec.argument_spec,
333
-            supports_check_mode=self.spec.supports_check_mode,
334
-            f5_product_name=self.spec.f5_product_name
333
+            supports_check_mode=self.spec.supports_check_mode
335 334
         )
336
-        ifcs = self.loaded_vlan_ifc_tag
335
+
337 336
         # Override methods to force specific logic in the module to happen
338
-        with patch.object(Parameters, '_get_interfaces_from_device') as obj:
339
-            obj.return_value = self.loaded_ifcs
340
-            mm = ModuleManager(client)
337
+        mm = ModuleManager(module=module)
341 338
 
342
-            current = (
343
-                Parameters(
344
-                    load_fixture('load_vlan.json')
345
-                ),
346
-                ifcs
347
-            )
339
+        current = ApiParameters(params=load_fixture('load_vlan.json'))
348 340
 
349
-            mm.update_on_device = Mock(return_value=True)
350
-            mm.exists = Mock(return_value=True)
351
-            mm.read_current_from_device = Mock(return_value=current)
341
+        mm.update_on_device = Mock(return_value=True)
342
+        mm.exists = Mock(return_value=True)
343
+        mm.read_current_from_device = Mock(return_value=current)
352 344
 
353
-            results = mm.exec_module()
345
+        results = mm.exec_module()
354 346
 
355 347
         assert results['changed'] is True
356
-        assert results['interfaces'] == [{'tagged': True, 'name': '2.1'}]
348
+        assert results['tagged_interfaces'] == ['2.1']
357 349
 
358 350
     def test_update_vlan_description(self, *args):
359 351
         set_module_args(dict(
... ...
@@ -365,117 +299,21 @@ class TestManager(unittest.TestCase):
365 365
             partition='Common',
366 366
         ))
367 367
 
368
-        client = AnsibleF5Client(
368
+        module = AnsibleModule(
369 369
             argument_spec=self.spec.argument_spec,
370
-            supports_check_mode=self.spec.supports_check_mode,
371
-            f5_product_name=self.spec.f5_product_name
370
+            supports_check_mode=self.spec.supports_check_mode
372 371
         )
373
-        ifcs = self.loaded_vlan_ifc_tag
372
+
374 373
         # Override methods to force specific logic in the module to happen
375
-        with patch.object(Parameters, '_get_interfaces_from_device') as obj:
376
-            obj.return_value = self.loaded_ifcs
377
-            mm = ModuleManager(client)
374
+        mm = ModuleManager(module=module)
378 375
 
379
-            current = (
380
-                Parameters(
381
-                    load_fixture('update_vlan_description.json')
382
-                ),
383
-                ifcs
384
-            )
376
+        current = ApiParameters(params=load_fixture('update_vlan_description.json'))
385 377
 
386
-            mm.update_on_device = Mock(return_value=True)
387
-            mm.exists = Mock(return_value=True)
388
-            mm.read_current_from_device = Mock(return_value=current)
378
+        mm.update_on_device = Mock(return_value=True)
379
+        mm.exists = Mock(return_value=True)
380
+        mm.read_current_from_device = Mock(return_value=current)
389 381
 
390
-            results = mm.exec_module()
382
+        results = mm.exec_module()
391 383
 
392 384
         assert results['changed'] is True
393 385
         assert results['description'] == 'changed_that'
394
-
395
-    def test_untagged_ifc_raises(self, *args):
396
-        set_module_args(dict(
397
-            name='somevlan',
398
-            untagged_interface=['10.2'],
399
-            server='localhost',
400
-            password='password',
401
-            user='admin',
402
-            partition='Common'
403
-        ))
404
-
405
-        client = AnsibleF5Client(
406
-            argument_spec=self.spec.argument_spec,
407
-            supports_check_mode=self.spec.supports_check_mode,
408
-            f5_product_name=self.spec.f5_product_name
409
-        )
410
-        msg = 'The specified interface "10.2" was not found'
411
-        # Override methods to force specific logic in the module to happen
412
-        with patch.object(Parameters, '_get_interfaces_from_device') as obj:
413
-            obj.return_value = self.loaded_ifcs
414
-
415
-            mm = ModuleManager(client)
416
-            mm.create_on_device = Mock(return_value=True)
417
-            mm.exists = Mock(return_value=False)
418
-
419
-            with pytest.raises(F5ModuleError) as err:
420
-                mm.exec_module()
421
-
422
-        assert str(err.value) == msg
423
-
424
-    def test_tagged_ifc_raises(self, *args):
425
-        set_module_args(dict(
426
-            name='somevlan',
427
-            tagged_interface=['10.2'],
428
-            tag=213,
429
-            server='localhost',
430
-            password='password',
431
-            user='admin',
432
-            partition='Common'
433
-        ))
434
-
435
-        client = AnsibleF5Client(
436
-            argument_spec=self.spec.argument_spec,
437
-            supports_check_mode=self.spec.supports_check_mode,
438
-            f5_product_name=self.spec.f5_product_name
439
-        )
440
-        msg = 'The specified interface "10.2" was not found'
441
-        # Override methods to force specific logic in the module to happen
442
-        with patch.object(Parameters, '_get_interfaces_from_device') as obj:
443
-            obj.return_value = self.loaded_ifcs
444
-
445
-            mm = ModuleManager(client)
446
-            mm.create_on_device = Mock(return_value=True)
447
-            mm.exists = Mock(return_value=False)
448
-
449
-            with pytest.raises(F5ModuleError) as err:
450
-                mm.exec_module()
451
-
452
-        assert str(err.value) == msg
453
-
454
-    def test_parse_return_ifcs_raises(self, *args):
455
-        set_module_args(dict(
456
-            name='somevlan',
457
-            untagged_interface=['1.2'],
458
-            server='localhost',
459
-            password='password',
460
-            user='admin',
461
-            partition='Common'
462
-        ))
463
-
464
-        client = AnsibleF5Client(
465
-            argument_spec=self.spec.argument_spec,
466
-            supports_check_mode=self.spec.supports_check_mode,
467
-            f5_product_name=self.spec.f5_product_name
468
-        )
469
-        msg = 'No interfaces were found'
470
-        # Override methods to force specific logic in the module to happen
471
-        with patch.object(Parameters, '_get_interfaces_from_device') as obj:
472
-            obj.return_value = []
473
-
474
-            mm = ModuleManager(client)
475
-            mm.create_on_device = Mock(return_value=True)
476
-            mm.exists = Mock(return_value=False)
477
-
478
-            with pytest.raises(F5ModuleError) as err:
479
-                mm.exec_module()
480
-
481
-        assert str(err.value) == msg
... ...
@@ -18,23 +18,22 @@ if sys.version_info < (2, 7):
18 18
 from ansible.compat.tests import unittest
19 19
 from ansible.compat.tests.mock import Mock
20 20
 from ansible.compat.tests.mock import patch
21
-from ansible.module_utils.f5_utils import AnsibleF5Client
22
-from ansible.module_utils.f5_utils import F5ModuleError
21
+from ansible.module_utils.basic import AnsibleModule
23 22
 
24 23
 try:
25 24
     from library.bigip_wait import Parameters
26 25
     from library.bigip_wait import ModuleManager
27 26
     from library.bigip_wait import ArgumentSpec
28
-    from library.bigip_wait import AnsibleF5ClientStub
29
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
27
+    from library.module_utils.network.f5.common import F5ModuleError
28
+    from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
30 29
     from test.unit.modules.utils import set_module_args
31 30
 except ImportError:
32 31
     try:
33 32
         from ansible.modules.network.f5.bigip_wait import Parameters
34 33
         from ansible.modules.network.f5.bigip_wait import ModuleManager
35 34
         from ansible.modules.network.f5.bigip_wait import ArgumentSpec
36
-        from ansible.modules.network.f5.bigip_wait import AnsibleF5ClientStub
37
-        from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
35
+        from ansible.module_utils.network.f5.common import F5ModuleError
36
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
38 37
         from units.modules.utils import set_module_args
39 38
     except ImportError:
40 39
         raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
... ...
@@ -70,7 +69,7 @@ class TestParameters(unittest.TestCase):
70 70
             msg='We timed out during waiting for BIG-IP :-('
71 71
         )
72 72
 
73
-        p = Parameters(args)
73
+        p = Parameters(params=args)
74 74
         assert p.delay == 3
75 75
         assert p.timeout == 500
76 76
         assert p.sleep == 10
... ...
@@ -84,15 +83,13 @@ class TestParameters(unittest.TestCase):
84 84
             msg='We timed out during waiting for BIG-IP :-('
85 85
         )
86 86
 
87
-        p = Parameters(args)
87
+        p = Parameters(params=args)
88 88
         assert p.delay == 3
89 89
         assert p.timeout == 500
90 90
         assert p.sleep == 10
91 91
         assert p.msg == 'We timed out during waiting for BIG-IP :-('
92 92
 
93 93
 
94
-@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
95
-       return_value=True)
96 94
 class TestManager(unittest.TestCase):
97 95
     def setUp(self):
98 96
         self.spec = ArgumentSpec()
... ...
@@ -104,14 +101,13 @@ class TestManager(unittest.TestCase):
104 104
             user='admin'
105 105
         ))
106 106
 
107
-        client = AnsibleF5ClientStub(
107
+        module = AnsibleModule(
108 108
             argument_spec=self.spec.argument_spec,
109
-            supports_check_mode=self.spec.supports_check_mode,
110
-            f5_product_name=self.spec.f5_product_name
109
+            supports_check_mode=self.spec.supports_check_mode
111 110
         )
112 111
 
113 112
         # Override methods to force specific logic in the module to happen
114
-        mm = ModuleManager(client)
113
+        mm = ModuleManager(module=module)
115 114
         mm._connect_to_device = Mock(return_value=True)
116 115
         mm._device_is_rebooting = Mock(return_value=False)
117 116
         mm._is_mprov_running_on_device = Mock(return_value=False)
... ...
@@ -18,15 +18,15 @@ if sys.version_info < (2, 7):
18 18
 from ansible.compat.tests import unittest
19 19
 from ansible.compat.tests.mock import Mock
20 20
 from ansible.compat.tests.mock import patch
21
-from ansible.module_utils.f5_utils import AnsibleF5Client
22
-from ansible.module_utils.f5_utils import F5ModuleError
21
+from ansible.module_utils.basic import AnsibleModule
23 22
 
24 23
 try:
25 24
     from library.bigiq_regkey_license import ModuleParameters
26 25
     from library.bigiq_regkey_license import ApiParameters
27 26
     from library.bigiq_regkey_license import ModuleManager
28 27
     from library.bigiq_regkey_license import ArgumentSpec
29
-    from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
28
+    from library.module_utils.network.f5.common import F5ModuleError
29
+    from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
30 30
     from test.unit.modules.utils import set_module_args
31 31
 except ImportError:
32 32
     try:
... ...
@@ -34,7 +34,8 @@ except ImportError:
34 34
         from ansible.modules.network.f5.bigiq_regkey_license import ApiParameters
35 35
         from ansible.modules.network.f5.bigiq_regkey_license import ModuleManager
36 36
         from ansible.modules.network.f5.bigiq_regkey_license import ArgumentSpec
37
-        from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
37
+        from ansible.module_utils.network.f5.common import F5ModuleError
38
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
38 39
         from units.modules.utils import set_module_args
39 40
     except ImportError:
40 41
         raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
... ...
@@ -70,7 +71,7 @@ class TestParameters(unittest.TestCase):
70 70
             description='this is a description'
71 71
         )
72 72
 
73
-        p = ModuleParameters(args)
73
+        p = ModuleParameters(params=args)
74 74
         assert p.regkey_pool == 'foo'
75 75
         assert p.license_key == 'XXXX-XXXX-XXXX-XXXX-XXXX'
76 76
         assert p.accept_eula is True
... ...
@@ -79,12 +80,10 @@ class TestParameters(unittest.TestCase):
79 79
     def test_api_parameters(self):
80 80
         args = load_fixture('load_regkey_license_key.json')
81 81
 
82
-        p = ApiParameters(args)
82
+        p = ApiParameters(params=args)
83 83
         assert p.description == 'foo bar baz'
84 84
 
85 85
 
86
-@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
87
-       return_value=True)
88 86
 class TestManager(unittest.TestCase):
89 87
 
90 88
     def setUp(self):
... ...
@@ -101,12 +100,11 @@ class TestManager(unittest.TestCase):
101 101
             user='admin'
102 102
         ))
103 103
 
104
-        client = AnsibleF5Client(
104
+        module = AnsibleModule(
105 105
             argument_spec=self.spec.argument_spec,
106
-            supports_check_mode=self.spec.supports_check_mode,
107
-            f5_product_name=self.spec.f5_product_name
106
+            supports_check_mode=self.spec.supports_check_mode
108 107
         )
109
-        mm = ModuleManager(client)
108
+        mm = ModuleManager(module=module)
110 109
 
111 110
         # Override methods to force specific logic in the module to happen
112 111
         mm.exists = Mock(side_effect=[False, True])
... ...
@@ -18,14 +18,15 @@ if sys.version_info < (2, 7):
18 18
 from ansible.compat.tests import unittest
19 19
 from ansible.compat.tests.mock import Mock
20 20
 from ansible.compat.tests.mock import patch
21
-from ansible.module_utils.f5_utils import AnsibleF5Client
22
-from ansible.module_utils.f5_utils import F5ModuleError
21
+from ansible.module_utils.basic import AnsibleModule
23 22
 
24 23
 try:
25 24
     from library.bigiq_regkey_pool import ModuleParameters
26 25
     from library.bigiq_regkey_pool import ApiParameters
27 26
     from library.bigiq_regkey_pool import ModuleManager
28 27
     from library.bigiq_regkey_pool import ArgumentSpec
28
+    from library.module_utils.network.f5.common import F5ModuleError
29
+    from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
29 30
     from test.unit.modules.utils import set_module_args
30 31
 except ImportError:
31 32
     try:
... ...
@@ -33,6 +34,8 @@ except ImportError:
33 33
         from ansible.modules.network.f5.bigiq_regkey_pool import ApiParameters
34 34
         from ansible.modules.network.f5.bigiq_regkey_pool import ModuleManager
35 35
         from ansible.modules.network.f5.bigiq_regkey_pool import ArgumentSpec
36
+        from ansible.module_utils.network.f5.common import F5ModuleError
37
+        from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
36 38
         from units.modules.utils import set_module_args
37 39
     except ImportError:
38 40
         raise SkipTest("F5 Ansible modules require the f5-sdk Python library")
... ...
@@ -65,18 +68,16 @@ class TestParameters(unittest.TestCase):
65 65
             description='this is a description'
66 66
         )
67 67
 
68
-        p = ModuleParameters(args)
68
+        p = ModuleParameters(params=args)
69 69
         assert p.description == 'this is a description'
70 70
 
71 71
     def test_api_parameters(self):
72 72
         args = load_fixture('load_regkey_license_pool.json')
73 73
 
74
-        p = ApiParameters(args)
74
+        p = ApiParameters(params=args)
75 75
         assert p.description == 'this is a description'
76 76
 
77 77
 
78
-@patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root',
79
-       return_value=True)
80 78
 class TestManager(unittest.TestCase):
81 79
 
82 80
     def setUp(self):
... ...
@@ -91,14 +92,13 @@ class TestManager(unittest.TestCase):
91 91
             user='admin'
92 92
         ))
93 93
 
94
-        client = AnsibleF5Client(
94
+        module = AnsibleModule(
95 95
             argument_spec=self.spec.argument_spec,
96
-            supports_check_mode=self.spec.supports_check_mode,
97
-            f5_product_name=self.spec.f5_product_name
96
+            supports_check_mode=self.spec.supports_check_mode
98 97
         )
99 98
 
100 99
         # Override methods in the specific type of manager
101
-        mm = ModuleManager(client)
100
+        mm = ModuleManager(module=module)
102 101
         mm.exists = Mock(return_value=False)
103 102
         mm.create_on_device = Mock(return_value=True)
104 103