mirror of
				https://github.com/ansible-collections/community.general.git
				synced 2025-10-24 21:14:00 -07:00 
			
		
		
		
	Adds module which allows users to manage partitions on a BIG-IP (#30577)
This commit is contained in:
		
					parent
					
						
							
								f8230d961d
							
						
					
				
			
			
				commit
				
					
						0eb0d96286
					
				
			
		
					 9 changed files with 621 additions and 124 deletions
				
			
		
							
								
								
									
										392
									
								
								lib/ansible/modules/network/f5/bigip_partition.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										392
									
								
								lib/ansible/modules/network/f5/bigip_partition.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,392 @@ | |||
| #!/usr/bin/python | ||||
| # -*- coding: utf-8 -*- | ||||
| # | ||||
| # Copyright 2017 F5 Networks Inc. | ||||
| # | ||||
| # This file is part of Ansible | ||||
| # | ||||
| # Ansible is free software: you can redistribute it and/or modify | ||||
| # it under the terms of the GNU General Public License as published by | ||||
| # the Free Software Foundation, either version 3 of the License, or | ||||
| # (at your option) any later version. | ||||
| # | ||||
| # Ansible is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| # GNU General Public License for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with Ansible.  If not, see <http://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| ANSIBLE_METADATA = { | ||||
|     'status': ['preview'], | ||||
|     'supported_by': 'community', | ||||
|     'metadata_version': '1.1' | ||||
| } | ||||
| 
 | ||||
| DOCUMENTATION = ''' | ||||
| --- | ||||
| module: bigip_partition | ||||
| short_description: Manage BIG-IP partitions. | ||||
| description: | ||||
|   - Manage BIG-IP partitions. | ||||
| version_added: "2.5" | ||||
| options: | ||||
|   description: | ||||
|     description: | ||||
|       - The description to attach to the Partition. | ||||
|   route_domain: | ||||
|     description: | ||||
|       - The default Route Domain to assign to the Partition. If no route domain | ||||
|         is specified, then the default route domain for the system (typically | ||||
|         zero) will be used only when creating a new partition. | ||||
|   state: | ||||
|     description: | ||||
|       - Whether the partition should exist or not. | ||||
|     default: present | ||||
|     choices: | ||||
|       - present | ||||
|       - absent | ||||
| notes: | ||||
|   - Requires the f5-sdk Python package on the host. This is as easy as pip | ||||
|     install f5-sdk. | ||||
|   - Requires BIG-IP software version >= 12 | ||||
| requirements: | ||||
|   - f5-sdk >= 2.2.3 | ||||
| extends_documentation_fragment: f5 | ||||
| author: | ||||
|   - Tim Rupp (@caphrim007) | ||||
| ''' | ||||
| 
 | ||||
| EXAMPLES = ''' | ||||
| - name: Create partition "foo" using the default route domain | ||||
|   bigip_partition: | ||||
|       name: "foo" | ||||
|       password: "secret" | ||||
|       server: "lb.mydomain.com" | ||||
|       user: "admin" | ||||
|   delegate_to: localhost | ||||
| 
 | ||||
| - name: Create partition "bar" using a custom route domain | ||||
|   bigip_partition: | ||||
|       name: "bar" | ||||
|       route_domain: 3 | ||||
|       password: "secret" | ||||
|       server: "lb.mydomain.com" | ||||
|       user: "admin" | ||||
|   delegate_to: localhost | ||||
| 
 | ||||
| - name: Change route domain of partition "foo" | ||||
|   bigip_partition: | ||||
|       name: "foo" | ||||
|       route_domain: 8 | ||||
|       password: "secret" | ||||
|       server: "lb.mydomain.com" | ||||
|       user: "admin" | ||||
|   delegate_to: localhost | ||||
| 
 | ||||
| - name: Set a description for partition "foo" | ||||
|   bigip_partition: | ||||
|       name: "foo" | ||||
|       description: "Tenant CompanyA" | ||||
|       password: "secret" | ||||
|       server: "lb.mydomain.com" | ||||
|       user: "admin" | ||||
|   delegate_to: localhost | ||||
| 
 | ||||
| - name: Delete the "foo" partition | ||||
|   bigip_partition: | ||||
|       name: "foo" | ||||
|       password: "secret" | ||||
|       server: "lb.mydomain.com" | ||||
|       user: "admin" | ||||
|       state: "absent" | ||||
|   delegate_to: localhost | ||||
| ''' | ||||
| 
 | ||||
| RETURN = ''' | ||||
| route_domain: | ||||
|     description: Name of the route domain associated with the partition. | ||||
|     returned: changed and success | ||||
|     type: int | ||||
|     sample: 0 | ||||
| description: | ||||
|     description: The description of the partition. | ||||
|     returned: changed and success | ||||
|     type: string | ||||
|     sample: "Example partition" | ||||
| ''' | ||||
| 
 | ||||
| from ansible.module_utils.f5_utils import AnsibleF5Client | ||||
| from ansible.module_utils.f5_utils import AnsibleF5Parameters | ||||
| from ansible.module_utils.f5_utils import F5ModuleError | ||||
| from ansible.module_utils.f5_utils import iteritems | ||||
| from ansible.module_utils.f5_utils import defaultdict | ||||
| 
 | ||||
| try: | ||||
|     from ansible.module_utils.f5_utils import HAS_F5SDK | ||||
|     from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError | ||||
| except ImportError: | ||||
|     HAS_F5SDK = False | ||||
| 
 | ||||
| 
 | ||||
| class Parameters(AnsibleF5Parameters): | ||||
|     api_map = { | ||||
|         'defaultRouteDomain': 'route_domain', | ||||
|     } | ||||
| 
 | ||||
|     api_attributes = [ | ||||
|         'description', 'defaultRouteDomain' | ||||
|     ] | ||||
| 
 | ||||
|     returnables = [ | ||||
|         'description', 'route_domain' | ||||
|     ] | ||||
| 
 | ||||
|     updatables = [ | ||||
|         'description', 'route_domain' | ||||
|     ] | ||||
| 
 | ||||
|     def __init__(self, params=None): | ||||
|         self._values = defaultdict(lambda: None) | ||||
|         self._values['__warnings'] = [] | ||||
|         if params: | ||||
|             self.update(params=params) | ||||
| 
 | ||||
|     def update(self, params=None): | ||||
|         if params: | ||||
|             for k, v in iteritems(params): | ||||
|                 if self.api_map is not None and k in self.api_map: | ||||
|                     map_key = self.api_map[k] | ||||
|                 else: | ||||
|                     map_key = k | ||||
| 
 | ||||
|                 # Handle weird API parameters like `dns.proxy.__iter__` by | ||||
|                 # using a map provided by the module developer | ||||
|                 class_attr = getattr(type(self), map_key, None) | ||||
|                 if isinstance(class_attr, property): | ||||
|                     # There is a mapped value for the api_map key | ||||
|                     if class_attr.fset is None: | ||||
|                         # If the mapped value does not have | ||||
|                         # an associated setter | ||||
|                         self._values[map_key] = v | ||||
|                     else: | ||||
|                         # The mapped value has a setter | ||||
|                         setattr(self, map_key, v) | ||||
|                 else: | ||||
|                     # If the mapped value is not a @property | ||||
|                     self._values[map_key] = v | ||||
| 
 | ||||
|     def to_return(self): | ||||
|         result = {} | ||||
|         try: | ||||
|             for returnable in self.returnables: | ||||
|                 result[returnable] = getattr(self, returnable) | ||||
|             result = self._filter_params(result) | ||||
|             return result | ||||
|         except Exception: | ||||
|             return result | ||||
| 
 | ||||
|     def api_params(self): | ||||
|         result = {} | ||||
|         for api_attribute in self.api_attributes: | ||||
|             if self.api_map is not None and api_attribute in self.api_map: | ||||
|                 result[api_attribute] = getattr(self, self.api_map[api_attribute]) | ||||
|             else: | ||||
|                 result[api_attribute] = getattr(self, api_attribute) | ||||
|         result = self._filter_params(result) | ||||
|         return result | ||||
| 
 | ||||
|     @property | ||||
|     def partition(self): | ||||
|         # Cannot create a partition in a partition, so nullify this | ||||
|         return None | ||||
| 
 | ||||
|     @property | ||||
|     def route_domain(self): | ||||
|         if self._values['route_domain'] is None: | ||||
|             return None | ||||
|         return int(self._values['route_domain']) | ||||
| 
 | ||||
| 
 | ||||
| class Difference(object): | ||||
|     def __init__(self, want, have=None): | ||||
|         self.want = want | ||||
|         self.have = have | ||||
| 
 | ||||
|     def compare(self, param): | ||||
|         try: | ||||
|             result = getattr(self, param) | ||||
|             return result | ||||
|         except AttributeError: | ||||
|             result = self.__default(param) | ||||
|             return result | ||||
| 
 | ||||
|     def __default(self, param): | ||||
|         attr1 = getattr(self.want, param) | ||||
|         try: | ||||
|             attr2 = getattr(self.have, param) | ||||
|             if attr1 != attr2: | ||||
|                 return attr1 | ||||
|         except AttributeError: | ||||
|             return attr1 | ||||
| 
 | ||||
| 
 | ||||
| class ModuleManager(object): | ||||
|     def __init__(self, client): | ||||
|         self.client = client | ||||
|         self.have = None | ||||
|         self.want = Parameters(self.client.module.params) | ||||
|         self.changes = Parameters() | ||||
| 
 | ||||
|     def _set_changed_options(self): | ||||
|         changed = {} | ||||
|         for key in Parameters.returnables: | ||||
|             if getattr(self.want, key) is not None: | ||||
|                 changed[key] = getattr(self.want, key) | ||||
|         if changed: | ||||
|             self.changes = Parameters(changed) | ||||
| 
 | ||||
|     def _update_changed_options(self): | ||||
|         diff = Difference(self.want, self.have) | ||||
|         updatables = Parameters.updatables | ||||
|         changed = dict() | ||||
|         for k in updatables: | ||||
|             change = diff.compare(k) | ||||
|             if change is None: | ||||
|                 continue | ||||
|             else: | ||||
|                 changed[k] = change | ||||
|         if changed: | ||||
|             self.changes = Parameters(changed) | ||||
|             return True | ||||
|         return False | ||||
| 
 | ||||
|     def exec_module(self): | ||||
|         changed = False | ||||
|         result = dict() | ||||
|         state = self.want.state | ||||
| 
 | ||||
|         try: | ||||
|             if state == "present": | ||||
|                 changed = self.present() | ||||
|             elif state == "absent": | ||||
|                 changed = self.absent() | ||||
|         except iControlUnexpectedHTTPError as e: | ||||
|             raise F5ModuleError(str(e)) | ||||
| 
 | ||||
|         changes = self.changes.to_return() | ||||
|         result.update(**changes) | ||||
|         result.update(dict(changed=changed)) | ||||
|         return result | ||||
| 
 | ||||
|     def present(self): | ||||
|         if self.exists(): | ||||
|             return self.update() | ||||
|         else: | ||||
|             return self.create() | ||||
| 
 | ||||
|     def create(self): | ||||
|         if self.client.check_mode: | ||||
|             return True | ||||
|         self.create_on_device() | ||||
|         if not self.exists(): | ||||
|             raise F5ModuleError("Failed to create the partition.") | ||||
|         return True | ||||
| 
 | ||||
|     def should_update(self): | ||||
|         result = self._update_changed_options() | ||||
|         if result: | ||||
|             return True | ||||
|         return False | ||||
| 
 | ||||
|     def update(self): | ||||
|         self.have = self.read_current_from_device() | ||||
|         if not self.should_update(): | ||||
|             return False | ||||
|         if self.client.check_mode: | ||||
|             return True | ||||
|         self.update_on_device() | ||||
|         return True | ||||
| 
 | ||||
|     def absent(self): | ||||
|         if self.exists(): | ||||
|             return self.remove() | ||||
|         return False | ||||
| 
 | ||||
|     def remove(self): | ||||
|         if self.client.check_mode: | ||||
|             return True | ||||
|         self.remove_from_device() | ||||
|         if self.exists(): | ||||
|             raise F5ModuleError("Failed to delete the partition.") | ||||
|         return True | ||||
| 
 | ||||
|     def read_current_from_device(self): | ||||
|         resource = self.client.api.tm.auth.partitions.partition.load( | ||||
|             name=self.want.name | ||||
|         ) | ||||
|         result = resource.attrs | ||||
|         return Parameters(result) | ||||
| 
 | ||||
|     def exists(self): | ||||
|         result = self.client.api.tm.auth.partitions.partition.exists( | ||||
|             name=self.want.name | ||||
|         ) | ||||
|         return result | ||||
| 
 | ||||
|     def update_on_device(self): | ||||
|         params = self.want.api_params() | ||||
|         result = self.client.api.tm.auth.partitions.partition.load( | ||||
|             name=self.want.name | ||||
|         ) | ||||
|         result.modify(**params) | ||||
| 
 | ||||
|     def create_on_device(self): | ||||
|         params = self.want.api_params() | ||||
|         self.client.api.tm.auth.partitions.partition.create( | ||||
|             name=self.want.name, | ||||
|             **params | ||||
|         ) | ||||
| 
 | ||||
|     def remove_from_device(self): | ||||
|         result = self.client.api.tm.auth.partitions.partition.load( | ||||
|             name=self.want.name | ||||
|         ) | ||||
|         if result: | ||||
|             result.delete() | ||||
| 
 | ||||
| 
 | ||||
| class ArgumentSpec(object): | ||||
|     def __init__(self): | ||||
|         self.supports_check_mode = True | ||||
|         self.argument_spec = dict( | ||||
|             name=dict(required=True), | ||||
|             description=dict(), | ||||
|             route_domain=dict(type='int'), | ||||
|         ) | ||||
|         self.f5_product_name = 'bigip' | ||||
| 
 | ||||
| 
 | ||||
| def main(): | ||||
|     try: | ||||
|         spec = ArgumentSpec() | ||||
| 
 | ||||
|         client = AnsibleF5Client( | ||||
|             argument_spec=spec.argument_spec, | ||||
|             supports_check_mode=spec.supports_check_mode, | ||||
|             f5_product_name=spec.f5_product_name | ||||
|         ) | ||||
| 
 | ||||
|         if not HAS_F5SDK: | ||||
|             raise F5ModuleError("The python f5-sdk module is required") | ||||
| 
 | ||||
|         mm = ModuleManager(client) | ||||
|         results = mm.exec_module() | ||||
|         client.module.exit_json(**results) | ||||
|     except F5ModuleError as e: | ||||
|         client.module.fail_json(msg=str(e)) | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     main() | ||||
|  | @ -1,3 +0,0 @@ | |||
| --- | ||||
| 
 | ||||
| device_group: "sdbt_sync_failover_dev_group" | ||||
|  | @ -1,16 +0,0 @@ | |||
| --- | ||||
| 
 | ||||
| # In this task list, the 0th item is the Active unit and the 1st item is the | ||||
| # standby unit. | ||||
| 
 | ||||
| - include: setup.yaml | ||||
|   when: ansible_play_batch[0] == inventory_hostname | ||||
| 
 | ||||
| - include: test-device-to-group.yaml | ||||
|   when: ansible_play_batch[0] == inventory_hostname | ||||
| 
 | ||||
| - include: test-pull-recent-device.yaml | ||||
|   when: ansible_play_batch[1] == inventory_hostname | ||||
| 
 | ||||
| - include: teardown.yaml | ||||
|   when: ansible_play_batch[0] == inventory_hostname | ||||
|  | @ -1,13 +0,0 @@ | |||
| --- | ||||
| 
 | ||||
| - name: Create pool | ||||
|   bigip_pool: | ||||
|       lb_method: "round-robin" | ||||
|       name: "cs1.pool" | ||||
|       state: "present" | ||||
|   register: result | ||||
| 
 | ||||
| - name: Assert Create pool | ||||
|   assert: | ||||
|       that: | ||||
|           - result|changed | ||||
|  | @ -1,21 +0,0 @@ | |||
| --- | ||||
| 
 | ||||
| - name: Delete pool - First device | ||||
|   bigip_pool: | ||||
|       name: "{{ item }}" | ||||
|       state: "absent" | ||||
|   with_items: | ||||
|       - "cs1.pool" | ||||
|       - "cs2.pool" | ||||
|   register: result | ||||
| 
 | ||||
| - name: Assert Delete pool | ||||
|   assert: | ||||
|       that: | ||||
|           - result|changed | ||||
| 
 | ||||
| - name: Sync configuration from device to group | ||||
|   bigip_configsync_actions: | ||||
|       device_group: "{{ device_group }}" | ||||
|       sync_device_to_group: yes | ||||
|   register: result | ||||
|  | @ -1,23 +0,0 @@ | |||
| --- | ||||
| 
 | ||||
| - name: Sync configuration from device to group | ||||
|   bigip_configsync_actions: | ||||
|       device_group: "{{ device_group }}" | ||||
|       sync_device_to_group: yes | ||||
|   register: result | ||||
| 
 | ||||
| - name: Sync configuration from device to group | ||||
|   assert: | ||||
|       that: | ||||
|           - result|changed | ||||
| 
 | ||||
| - name: Sync configuration from device to group - Idempotent check | ||||
|   bigip_configsync_actions: | ||||
|       device_group: "{{ device_group }}" | ||||
|       sync_device_to_group: yes | ||||
|   register: result | ||||
| 
 | ||||
| - name: Sync configuration from device to group - Idempotent check | ||||
|   assert: | ||||
|       that: | ||||
|           - not result|changed | ||||
|  | @ -1,48 +0,0 @@ | |||
| --- | ||||
| 
 | ||||
| - name: Create another pool - First device | ||||
|   bigip_pool: | ||||
|       server: "{{ hostvars['bigip1']['ansible_host'] }}" | ||||
|       lb_method: "round_robin" | ||||
|       name: "cs2.pool" | ||||
|       state: "present" | ||||
|   register: result | ||||
| 
 | ||||
| - name: Assert Create another pool - First device | ||||
|   assert: | ||||
|       that: | ||||
|           - result|changed | ||||
| 
 | ||||
| - name: Sync configuration from most recent - Second device | ||||
|   bigip_configsync_actions: | ||||
|       device_group: "{{ device_group }}" | ||||
|       sync_most_recent_to_device: yes | ||||
|   register: result | ||||
| 
 | ||||
| - name: Assert Sync configuration from most recent - Second device | ||||
|   assert: | ||||
|       that: | ||||
|           - result|changed | ||||
| 
 | ||||
| - name: Sync configuration from most recent - Second device - Idempotent check | ||||
|   bigip_configsync_actions: | ||||
|       device_group: "{{ device_group }}" | ||||
|       sync_most_recent_to_device: yes | ||||
|   register: result | ||||
| 
 | ||||
| - name: Assert Sync configuration from most recent - Second device - Idempotent check | ||||
|   assert: | ||||
|       that: | ||||
|           - not result|changed | ||||
| 
 | ||||
| - name: Create another pool again - Second device - ensure it was created in previous sync | ||||
|   bigip_pool: | ||||
|       lb_method: "round_robin" | ||||
|       name: "cs2.pool" | ||||
|       state: "present" | ||||
|   register: result | ||||
| 
 | ||||
| - name: Assert Create another pool again - Second device - ensure it was deleted in previous sync | ||||
|   assert: | ||||
|       that: | ||||
|           - not result|changed | ||||
|  | @ -0,0 +1,9 @@ | |||
| { | ||||
|   "kind": "tm:auth:partition:partitionstate", | ||||
|   "name": "foo", | ||||
|   "fullPath": "foo", | ||||
|   "generation": 212, | ||||
|   "selfLink": "https://localhost/mgmt/tm/auth/partition/foo?ver=13.0.0", | ||||
|   "defaultRouteDomain": 0, | ||||
|   "description": "my description" | ||||
| } | ||||
							
								
								
									
										220
									
								
								test/units/modules/network/f5/test_bigip_partition.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								test/units/modules/network/f5/test_bigip_partition.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,220 @@ | |||
| # -*- coding: utf-8 -*- | ||||
| # | ||||
| # Copyright 2017 F5 Networks Inc. | ||||
| # | ||||
| # This file is part of Ansible | ||||
| # | ||||
| # Ansible is free software: you can redistribute it and/or modify | ||||
| # it under the terms of the GNU General Public License as published by | ||||
| # the Free Software Foundation, either version 3 of the License, or | ||||
| # (at your option) any later version. | ||||
| # | ||||
| # Ansible is distributed in the hope that it will be useful, | ||||
| # but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
| # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the | ||||
| # GNU General Public Liccense for more details. | ||||
| # | ||||
| # You should have received a copy of the GNU General Public License | ||||
| # along with Ansible.  If not, see <http://www.gnu.org/licenses/>. | ||||
| 
 | ||||
| from __future__ import (absolute_import, division, print_function) | ||||
| __metaclass__ = type | ||||
| 
 | ||||
| import os | ||||
| import json | ||||
| import sys | ||||
| 
 | ||||
| from nose.plugins.skip import SkipTest | ||||
| if sys.version_info < (2, 7): | ||||
|     raise SkipTest("F5 Ansible modules require Python >= 2.7") | ||||
| 
 | ||||
| from ansible.compat.tests import unittest | ||||
| from ansible.compat.tests.mock import patch, Mock | ||||
| from ansible.module_utils import basic | ||||
| from ansible.module_utils._text import to_bytes | ||||
| from ansible.module_utils.f5_utils import AnsibleF5Client | ||||
| 
 | ||||
| try: | ||||
|     from library.bigip_partition import Parameters | ||||
|     from library.bigip_partition import ModuleManager | ||||
|     from library.bigip_partition import ArgumentSpec | ||||
| except ImportError: | ||||
|     try: | ||||
|         from ansible.modules.network.f5.bigip_partition import Parameters | ||||
|         from ansible.modules.network.f5.bigip_partition import ModuleManager | ||||
|         from ansible.modules.network.f5.bigip_partition import ArgumentSpec | ||||
|     except ImportError: | ||||
|         raise SkipTest("F5 Ansible modules require the f5-sdk Python library") | ||||
| 
 | ||||
| fixture_path = os.path.join(os.path.dirname(__file__), 'fixtures') | ||||
| fixture_data = {} | ||||
| 
 | ||||
| 
 | ||||
| def set_module_args(args): | ||||
|     args = json.dumps({'ANSIBLE_MODULE_ARGS': args}) | ||||
|     basic._ANSIBLE_ARGS = to_bytes(args) | ||||
| 
 | ||||
| 
 | ||||
| def load_fixture(name): | ||||
|     path = os.path.join(fixture_path, name) | ||||
| 
 | ||||
|     if path in fixture_data: | ||||
|         return fixture_data[path] | ||||
| 
 | ||||
|     with open(path) as f: | ||||
|         data = f.read() | ||||
| 
 | ||||
|     try: | ||||
|         data = json.loads(data) | ||||
|     except Exception: | ||||
|         pass | ||||
| 
 | ||||
|     fixture_data[path] = data | ||||
|     return data | ||||
| 
 | ||||
| 
 | ||||
| class TestParameters(unittest.TestCase): | ||||
|     def test_module_parameters(self): | ||||
|         args = dict( | ||||
|             name='foo', | ||||
|             description='my description', | ||||
|             route_domain=0 | ||||
|         ) | ||||
| 
 | ||||
|         p = Parameters(args) | ||||
|         assert p.name == 'foo' | ||||
|         assert p.description == 'my description' | ||||
|         assert p.route_domain == 0 | ||||
| 
 | ||||
|     def test_module_parameters_string_domain(self): | ||||
|         args = dict( | ||||
|             name='foo', | ||||
|             route_domain='0' | ||||
|         ) | ||||
| 
 | ||||
|         p = Parameters(args) | ||||
|         assert p.name == 'foo' | ||||
|         assert p.route_domain == 0 | ||||
| 
 | ||||
|     def test_api_parameters(self): | ||||
|         args = dict( | ||||
|             name='foo', | ||||
|             description='my description', | ||||
|             defaultRouteDomain=1 | ||||
|         ) | ||||
| 
 | ||||
|         p = Parameters(args) | ||||
|         assert p.name == 'foo' | ||||
|         assert p.description == 'my description' | ||||
|         assert p.route_domain == 1 | ||||
| 
 | ||||
| 
 | ||||
| @patch('ansible.module_utils.f5_utils.AnsibleF5Client._get_mgmt_root', | ||||
|        return_value=True) | ||||
| class TestManagerEcho(unittest.TestCase): | ||||
| 
 | ||||
|     def setUp(self): | ||||
|         self.spec = ArgumentSpec() | ||||
| 
 | ||||
|     def test_create_partition(self, *args): | ||||
|         set_module_args(dict( | ||||
|             name='foo', | ||||
|             description='my description', | ||||
|             server='localhost', | ||||
|             password='password', | ||||
|             user='admin' | ||||
|         )) | ||||
| 
 | ||||
|         client = AnsibleF5Client( | ||||
|             argument_spec=self.spec.argument_spec, | ||||
|             supports_check_mode=self.spec.supports_check_mode, | ||||
|             f5_product_name=self.spec.f5_product_name | ||||
|         ) | ||||
| 
 | ||||
|         # Override methods in the specific type of manager | ||||
|         mm = ModuleManager(client) | ||||
|         mm.exists = Mock(side_effect=[False, True]) | ||||
|         mm.create_on_device = Mock(return_value=True) | ||||
| 
 | ||||
|         results = mm.exec_module() | ||||
| 
 | ||||
|         assert results['changed'] is True | ||||
| 
 | ||||
|     def test_create_partition_idempotent(self, *args): | ||||
|         set_module_args(dict( | ||||
|             name='foo', | ||||
|             description='my description', | ||||
|             server='localhost', | ||||
|             password='password', | ||||
|             user='admin' | ||||
|         )) | ||||
| 
 | ||||
|         current = Parameters(load_fixture('load_tm_auth_partition.json')) | ||||
|         client = AnsibleF5Client( | ||||
|             argument_spec=self.spec.argument_spec, | ||||
|             supports_check_mode=self.spec.supports_check_mode, | ||||
|             f5_product_name=self.spec.f5_product_name | ||||
|         ) | ||||
| 
 | ||||
|         # Override methods in the specific type of manager | ||||
|         mm = ModuleManager(client) | ||||
|         mm.exists = Mock(return_value=True) | ||||
|         mm.read_current_from_device = Mock(return_value=current) | ||||
| 
 | ||||
|         results = mm.exec_module() | ||||
| 
 | ||||
|         assert results['changed'] is False | ||||
| 
 | ||||
|     def test_update_description(self, *args): | ||||
|         set_module_args(dict( | ||||
|             name='foo', | ||||
|             description='another description', | ||||
|             server='localhost', | ||||
|             password='password', | ||||
|             user='admin' | ||||
|         )) | ||||
| 
 | ||||
|         current = Parameters(load_fixture('load_tm_auth_partition.json')) | ||||
|         client = AnsibleF5Client( | ||||
|             argument_spec=self.spec.argument_spec, | ||||
|             supports_check_mode=self.spec.supports_check_mode, | ||||
|             f5_product_name=self.spec.f5_product_name | ||||
|         ) | ||||
| 
 | ||||
|         # Override methods in the specific type of manager | ||||
|         mm = ModuleManager(client) | ||||
|         mm.exists = Mock(return_value=True) | ||||
|         mm.read_current_from_device = Mock(return_value=current) | ||||
|         mm.update_on_device = Mock(return_value=True) | ||||
| 
 | ||||
|         results = mm.exec_module() | ||||
| 
 | ||||
|         assert results['changed'] is True | ||||
|         assert results['description'] == 'another description' | ||||
| 
 | ||||
|     def test_update_route_domain(self, *args): | ||||
|         set_module_args(dict( | ||||
|             name='foo', | ||||
|             route_domain=1, | ||||
|             server='localhost', | ||||
|             password='password', | ||||
|             user='admin' | ||||
|         )) | ||||
| 
 | ||||
|         current = Parameters(load_fixture('load_tm_auth_partition.json')) | ||||
|         client = AnsibleF5Client( | ||||
|             argument_spec=self.spec.argument_spec, | ||||
|             supports_check_mode=self.spec.supports_check_mode, | ||||
|             f5_product_name=self.spec.f5_product_name | ||||
|         ) | ||||
| 
 | ||||
|         # Override methods in the specific type of manager | ||||
|         mm = ModuleManager(client) | ||||
|         mm.exists = Mock(return_value=True) | ||||
|         mm.read_current_from_device = Mock(return_value=current) | ||||
|         mm.update_on_device = Mock(return_value=True) | ||||
| 
 | ||||
|         results = mm.exec_module() | ||||
| 
 | ||||
|         assert results['changed'] is True | ||||
|         assert results['route_domain'] == 1 | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue