mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
deprecates the old module name (#53972)
adds ha order, ha group and ha load as failover types refactors main() function and module manager to accomodate new patterns updates docs refactors unit tests
This commit is contained in:
parent
cd1ff016ef
commit
dcf40d43ea
4 changed files with 383 additions and 45 deletions
1
lib/ansible/modules/network/f5/_bigip_traffic_group.py
Symbolic link
1
lib/ansible/modules/network/f5/_bigip_traffic_group.py
Symbolic link
|
@ -0,0 +1 @@
|
|||
bigip_device_traffic_group.py
|
|
@ -14,7 +14,7 @@ ANSIBLE_METADATA = {'metadata_version': '1.1',
|
|||
|
||||
DOCUMENTATION = r'''
|
||||
---
|
||||
module: bigip_traffic_group
|
||||
module: bigip_device_traffic_group
|
||||
short_description: Manages traffic groups on BIG-IP
|
||||
description:
|
||||
- Supports managing traffic groups and their attributes on a BIG-IP.
|
||||
|
@ -23,19 +23,8 @@ options:
|
|||
name:
|
||||
description:
|
||||
- The name of the traffic group.
|
||||
type: str
|
||||
required: True
|
||||
partition:
|
||||
description:
|
||||
- Device partition to manage resources on.
|
||||
default: Common
|
||||
state:
|
||||
description:
|
||||
- When C(present), ensures that the traffic group exists.
|
||||
- When C(absent), ensures the traffic group is removed.
|
||||
default: present
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
mac_address:
|
||||
description:
|
||||
- Specifies the floating Media Access Control (MAC) address associated with the floating IP addresses
|
||||
|
@ -47,7 +36,66 @@ options:
|
|||
- Without a MAC masquerade address, the sending host must learn the MAC address for a newly-active device,
|
||||
either by sending an ARP request or by relying on the gratuitous ARP from the newly-active device.
|
||||
- To unset the MAC address, specify an empty value (C("")) to this parameter.
|
||||
type: str
|
||||
version_added: 2.6
|
||||
ha_order:
|
||||
description:
|
||||
- Specifies order in which you would like to assign devices for failover.
|
||||
- If you configure this setting, you must configure the setting on every traffic group in the device group.
|
||||
- The values should be device names of the devices that belong to the failover group configured beforehand.
|
||||
- The order in which the devices are placed as arguments to this parameter, determines their HA order
|
||||
on the device, in other words changing the order of the same elements will cause a change on the unit.
|
||||
- To disable an HA order failover method , specify an empty string value (C("")) to this parameter.
|
||||
- Disabling HA order will revert the device back to using Load Aware method as it is the default,
|
||||
unless C(ha_group) setting is also configured.
|
||||
- Device names will be prepended by a partition by the module, so you can provide either the full path format
|
||||
name C(/Common/bigip1) or just the name string C(bigip1).
|
||||
type: list
|
||||
version_added: 2.8
|
||||
ha_group:
|
||||
description:
|
||||
- Specifies a configured C(HA group) to be associated with the traffic group.
|
||||
- Once you create an HA group on a device and associate the HA group with a traffic group,
|
||||
you must create an HA group and associate it with that same traffic group on every device in the device group.
|
||||
- To disable an HA group failover method , specify an empty string value (C("")) to this parameter.
|
||||
- Disabling HA group will revert the device back to using C(Load Aware) method as it is the default,
|
||||
unless C(ha_order) setting is also configured.
|
||||
- The C(auto_failback) and C(auto_failback_time) are not compatible with C(ha_group).
|
||||
type: str
|
||||
version_added: 2.8
|
||||
ha_load_factor:
|
||||
description:
|
||||
- The value of the load the traffic-group presents the system relative to other traffic groups.
|
||||
- This parameter only takes effect when C(Load Aware) failover method is in use.
|
||||
- The correct value range is C(1 - 1000) inclusive.
|
||||
type: int
|
||||
version_added: 2.8
|
||||
auto_failback:
|
||||
description:
|
||||
- Specifies whether the traffic group fails back to the initial device specified in C(ha_order).
|
||||
type: bool
|
||||
version_added: 2.8
|
||||
auto_failback_time:
|
||||
description:
|
||||
- Specifies the number of seconds the system delays before failing back to the initial device
|
||||
specified in C(ha_order).
|
||||
- The correct value range is C(0 - 300) inclusive.
|
||||
type: int
|
||||
version_added: 2.8
|
||||
partition:
|
||||
description:
|
||||
- Device partition to manage resources on.
|
||||
type: str
|
||||
default: Common
|
||||
state:
|
||||
description:
|
||||
- When C(present), ensures that the traffic group exists.
|
||||
- When C(absent), ensures the traffic group is removed.
|
||||
type: str
|
||||
choices:
|
||||
- present
|
||||
- absent
|
||||
default: present
|
||||
extends_documentation_fragment: f5
|
||||
author:
|
||||
- Tim Rupp (@caphrim007)
|
||||
|
@ -56,18 +104,96 @@ author:
|
|||
|
||||
EXAMPLES = r'''
|
||||
- name: Create a traffic group
|
||||
bigip_traffic_group:
|
||||
name: foo
|
||||
bigip_device_traffic_group:
|
||||
name: foo1
|
||||
state: present
|
||||
provider:
|
||||
user: admin
|
||||
password: secret
|
||||
server: lb.mydomain.com
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Create a traffic group with ha_group failover
|
||||
bigip_device_traffic_group:
|
||||
name: foo2
|
||||
state: present
|
||||
ha_group: foo_HA_grp
|
||||
provider:
|
||||
user: admin
|
||||
password: secret
|
||||
server: lb.mydomain.com
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Create a traffic group with ha_order failover
|
||||
bigip_device_traffic_group:
|
||||
name: foo3
|
||||
state: present
|
||||
ha_order:
|
||||
- /Common/bigip1.lab.local
|
||||
- /Common/bigip2.lab.local
|
||||
auto_failback: yes
|
||||
auto_failback_time: 40
|
||||
provider:
|
||||
user: admin
|
||||
password: secret
|
||||
server: lb.mydomain.com
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Change traffic group ha_order to ha_group
|
||||
bigip_device_traffic_group:
|
||||
name: foo3
|
||||
state: present
|
||||
ha_group: foo_HA_grp
|
||||
ha_order: ""
|
||||
auto_failback: no
|
||||
provider:
|
||||
user: admin
|
||||
password: secret
|
||||
server: lb.mydomain.com
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Remove traffic group
|
||||
bigip_device_traffic_group:
|
||||
name: foo
|
||||
state: absent
|
||||
provider:
|
||||
user: admin
|
||||
password: secret
|
||||
server: lb.mydomain.com
|
||||
delegate_to: localhost
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
# only common fields returned
|
||||
mac_address:
|
||||
description: The MAC masquerade address
|
||||
returned: changed
|
||||
type: str
|
||||
sample: "02:01:d7:93:35:08"
|
||||
ha_group:
|
||||
description: The configured HA group associated with traffic group
|
||||
returned: changed
|
||||
type: str
|
||||
sample: foo_HA_grp
|
||||
ha_order:
|
||||
description: Specifies the order in which the devices will failover
|
||||
returned: changed
|
||||
type: list
|
||||
sample: ['/Common/bigip1', '/Common/bigip2']
|
||||
ha_load_factor:
|
||||
description: The value of the load the traffic-group presents the system relative to other traffic groups
|
||||
returned: changed
|
||||
type: int
|
||||
sample: 20
|
||||
auto_failback:
|
||||
description: Specifies whether the traffic group fails back to the initial device specified in ha_order
|
||||
returned: changed
|
||||
type: bool
|
||||
sample: yes
|
||||
auto_failback_time:
|
||||
description: Specifies the number of seconds the system delays before failing back
|
||||
returned: changed
|
||||
type: int
|
||||
sample: 60
|
||||
'''
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
@ -77,37 +203,56 @@ try:
|
|||
from library.module_utils.network.f5.bigip import F5RestClient
|
||||
from library.module_utils.network.f5.common import F5ModuleError
|
||||
from library.module_utils.network.f5.common import AnsibleF5Parameters
|
||||
from library.module_utils.network.f5.common import cleanup_tokens
|
||||
from library.module_utils.network.f5.common import f5_argument_spec
|
||||
from library.module_utils.network.f5.common import fq_name
|
||||
from library.module_utils.network.f5.common import transform_name
|
||||
from library.module_utils.network.f5.common import exit_json
|
||||
from library.module_utils.network.f5.common import fail_json
|
||||
from library.module_utils.network.f5.common import flatten_boolean
|
||||
except ImportError:
|
||||
from ansible.module_utils.network.f5.bigip import F5RestClient
|
||||
from ansible.module_utils.network.f5.common import F5ModuleError
|
||||
from ansible.module_utils.network.f5.common import AnsibleF5Parameters
|
||||
from ansible.module_utils.network.f5.common import cleanup_tokens
|
||||
from ansible.module_utils.network.f5.common import f5_argument_spec
|
||||
from ansible.module_utils.network.f5.common import fq_name
|
||||
from ansible.module_utils.network.f5.common import transform_name
|
||||
from ansible.module_utils.network.f5.common import exit_json
|
||||
from ansible.module_utils.network.f5.common import fail_json
|
||||
from ansible.module_utils.network.f5.common import flatten_boolean
|
||||
|
||||
|
||||
class Parameters(AnsibleF5Parameters):
|
||||
api_map = {
|
||||
'mac': 'mac_address',
|
||||
'haGroup': 'ha_group',
|
||||
'haOrder': 'ha_order',
|
||||
'haLoadFactor': 'ha_load_factor',
|
||||
'autoFailbackTime': 'auto_failback_time',
|
||||
'autoFailbackEnabled': 'auto_failback',
|
||||
}
|
||||
|
||||
api_attributes = [
|
||||
'mac',
|
||||
'haGroup',
|
||||
'haOrder',
|
||||
'haLoadFactor',
|
||||
'autoFailbackTime',
|
||||
'autoFailbackEnabled',
|
||||
|
||||
]
|
||||
|
||||
returnables = [
|
||||
'mac_address',
|
||||
'ha_group',
|
||||
'ha_order',
|
||||
'ha_load_factor',
|
||||
'auto_failback_time',
|
||||
'auto_failback',
|
||||
]
|
||||
|
||||
updatables = [
|
||||
'mac_address',
|
||||
'ha_group',
|
||||
'ha_order',
|
||||
'ha_load_factor',
|
||||
'auto_failback_time',
|
||||
'auto_failback',
|
||||
]
|
||||
|
||||
|
||||
|
@ -124,6 +269,60 @@ class ModuleParameters(Parameters):
|
|||
return 'none'
|
||||
return self._values['mac_address']
|
||||
|
||||
@property
|
||||
def ha_group(self):
|
||||
if self._values['ha_group'] is None:
|
||||
return None
|
||||
if self._values['ha_group'] == '':
|
||||
return 'none'
|
||||
if self.auto_failback == 'true':
|
||||
raise F5ModuleError(
|
||||
"The auto_failback cannot be enabled when ha_group is specified."
|
||||
)
|
||||
return self._values['ha_group']
|
||||
|
||||
@property
|
||||
def ha_load_factor(self):
|
||||
if self._values['ha_load_factor'] is None:
|
||||
return None
|
||||
value = self._values['ha_load_factor']
|
||||
if value < 1 or value > 1000:
|
||||
raise F5ModuleError(
|
||||
"Invalid ha_load_factor value, correct range is 1 - 1000, specified value: {0}.".format(value))
|
||||
return value
|
||||
|
||||
@property
|
||||
def auto_failback_time(self):
|
||||
if self._values['auto_failback_time'] is None:
|
||||
return None
|
||||
value = self._values['auto_failback_time']
|
||||
if value < 0 or value > 300:
|
||||
raise F5ModuleError(
|
||||
"Invalid auto_failback_time value, correct range is 0 - 300, specified value: {0}.".format(value))
|
||||
return value
|
||||
|
||||
@property
|
||||
def auto_failback(self):
|
||||
result = flatten_boolean(self._values['auto_failback'])
|
||||
if result == 'yes':
|
||||
return 'true'
|
||||
if result == 'no':
|
||||
return 'false'
|
||||
return None
|
||||
|
||||
@property
|
||||
def ha_order(self):
|
||||
if self._values['ha_order'] is None:
|
||||
return None
|
||||
if len(self._values['ha_order']) == 1 and self._values['ha_order'][0] == '':
|
||||
if self.auto_failback == 'true':
|
||||
raise F5ModuleError(
|
||||
'Cannot enable auto failback when HA order list is empty, at least one device must be specified.'
|
||||
)
|
||||
return 'none'
|
||||
result = [fq_name(self.partition, value) for value in self._values['ha_order']]
|
||||
return result
|
||||
|
||||
|
||||
class Changes(Parameters):
|
||||
def to_return(self):
|
||||
|
@ -139,7 +338,39 @@ class UsableChanges(Changes):
|
|||
|
||||
|
||||
class ReportableChanges(Changes):
|
||||
pass
|
||||
|
||||
@property
|
||||
def mac_address(self):
|
||||
if self._values['mac_address'] is None:
|
||||
return None
|
||||
if self._values['mac_address'] == 'none':
|
||||
return ''
|
||||
return self._values['mac_address']
|
||||
|
||||
@property
|
||||
def ha_group(self):
|
||||
if self._values['ha_group'] is None:
|
||||
return None
|
||||
if self._values['ha_group'] == 'none':
|
||||
return ''
|
||||
return self._values['ha_group']
|
||||
|
||||
@property
|
||||
def auto_failback(self):
|
||||
result = self._values['auto_failback']
|
||||
if result == 'true':
|
||||
return 'yes'
|
||||
if result == 'false':
|
||||
return 'no'
|
||||
return None
|
||||
|
||||
@property
|
||||
def ha_order(self):
|
||||
if self._values['ha_order'] is None:
|
||||
return None
|
||||
if self._values['ha_order'] == 'none':
|
||||
return ''
|
||||
return self._values['ha_order']
|
||||
|
||||
|
||||
class Difference(object):
|
||||
|
@ -163,6 +394,31 @@ class Difference(object):
|
|||
except AttributeError:
|
||||
return attr1
|
||||
|
||||
@property
|
||||
def ha_group(self):
|
||||
if self.want.ha_group is None:
|
||||
return None
|
||||
if self.have.ha_group is None and self.want.ha_group == 'none':
|
||||
return None
|
||||
if self.want.ha_group != self.have.ha_group:
|
||||
if self.have.auto_failback == 'true' and self.want.auto_failback != 'false':
|
||||
raise F5ModuleError(
|
||||
"The auto_failback parameter on the device must disabled to use ha_group failover method."
|
||||
)
|
||||
return self.want.ha_group
|
||||
|
||||
@property
|
||||
def ha_order(self):
|
||||
# Device order is literally derived from the order in the array,
|
||||
# hence lists with the same elements but in different order cannot be equal, so cmp_simple_list
|
||||
# function will not work here.
|
||||
if self.want.ha_order is None:
|
||||
return None
|
||||
if self.have.ha_order is None and self.want.ha_order == 'none':
|
||||
return None
|
||||
if self.want.ha_order != self.have.ha_order:
|
||||
return self.want.ha_order
|
||||
|
||||
@property
|
||||
def partition(self):
|
||||
raise F5ModuleError(
|
||||
|
@ -173,7 +429,7 @@ class Difference(object):
|
|||
class ModuleManager(object):
|
||||
def __init__(self, *args, **kwargs):
|
||||
self.module = kwargs.get('module', None)
|
||||
self.client = kwargs.get('client', None)
|
||||
self.client = F5RestClient(**self.module.params)
|
||||
self.have = None
|
||||
self.want = ModuleParameters(params=self.module.params)
|
||||
self.changes = UsableChanges()
|
||||
|
@ -367,12 +623,29 @@ class ArgumentSpec(object):
|
|||
self.supports_check_mode = True
|
||||
argument_spec = dict(
|
||||
name=dict(required=True),
|
||||
state=dict(default='present', choices=['absent', 'present']),
|
||||
mac_address=dict(),
|
||||
ha_order=dict(
|
||||
type='list'
|
||||
),
|
||||
ha_group=dict(),
|
||||
ha_load_factor=dict(
|
||||
type='int'
|
||||
),
|
||||
auto_failback=dict(
|
||||
type='bool',
|
||||
),
|
||||
auto_failback_time=dict(
|
||||
type='int'
|
||||
),
|
||||
state=dict(
|
||||
default='present',
|
||||
choices=['absent', 'present']
|
||||
),
|
||||
partition=dict(
|
||||
default='Common',
|
||||
fallback=(env_fallback, ['F5_PARTITION'])
|
||||
),
|
||||
mac_address=dict()
|
||||
|
||||
)
|
||||
self.argument_spec = {}
|
||||
self.argument_spec.update(f5_argument_spec)
|
||||
|
@ -384,19 +657,15 @@ def main():
|
|||
|
||||
module = AnsibleModule(
|
||||
argument_spec=spec.argument_spec,
|
||||
supports_check_mode=spec.supports_check_mode
|
||||
supports_check_mode=spec.supports_check_mode,
|
||||
)
|
||||
|
||||
client = F5RestClient(**module.params)
|
||||
|
||||
try:
|
||||
mm = ModuleManager(module=module, client=client)
|
||||
mm = ModuleManager(module=module)
|
||||
results = mm.exec_module()
|
||||
cleanup_tokens(client)
|
||||
exit_json(module, results, client)
|
||||
module.exit_json(**results)
|
||||
except F5ModuleError as ex:
|
||||
cleanup_tokens(client)
|
||||
fail_json(module, ex, client)
|
||||
module.fail_json(msg=str(ex))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
22
test/units/modules/network/f5/fixtures/load_tg_ha_order.json
Normal file
22
test/units/modules/network/f5/fixtures/load_tg_ha_order.json
Normal file
|
@ -0,0 +1,22 @@
|
|||
{
|
||||
"kind": "tm:cm:traffic-group:traffic-groupstate",
|
||||
"name": "traffic-group-2",
|
||||
"partition": "Common",
|
||||
"fullPath": "/Common/traffic-group-2",
|
||||
"generation": 227,
|
||||
"selfLink": "https://localhost/mgmt/tm/cm/traffic-group/~Common~traffic-group-2?ver=12.1.4",
|
||||
"autoFailbackEnabled": "true",
|
||||
"autoFailbackTime": 60,
|
||||
"haLoadFactor": 1,
|
||||
"isFloating": "true",
|
||||
"mac": "none",
|
||||
"unitId": 1,
|
||||
"haOrder": [
|
||||
"/Common/v12-1.ansible.local"
|
||||
],
|
||||
"haOrderReference": [
|
||||
{
|
||||
"link": "https://localhost/mgmt/tm/cm/device/~Common~v12-1.ansible.local?ver=12.1.4"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -17,10 +17,10 @@ if sys.version_info < (2, 7):
|
|||
from ansible.module_utils.basic import AnsibleModule
|
||||
|
||||
try:
|
||||
from library.modules.bigip_traffic_group import ApiParameters
|
||||
from library.modules.bigip_traffic_group import ModuleParameters
|
||||
from library.modules.bigip_traffic_group import ModuleManager
|
||||
from library.modules.bigip_traffic_group import ArgumentSpec
|
||||
from library.modules.bigip_device_traffic_group import ApiParameters
|
||||
from library.modules.bigip_device_traffic_group import ModuleParameters
|
||||
from library.modules.bigip_device_traffic_group import ModuleManager
|
||||
from library.modules.bigip_device_traffic_group import ArgumentSpec
|
||||
|
||||
# In Ansible 2.8, Ansible changed import paths.
|
||||
from test.units.compat import unittest
|
||||
|
@ -29,10 +29,10 @@ try:
|
|||
|
||||
from test.units.modules.utils import set_module_args
|
||||
except ImportError:
|
||||
from ansible.modules.network.f5.bigip_traffic_group import ApiParameters
|
||||
from ansible.modules.network.f5.bigip_traffic_group import ModuleParameters
|
||||
from ansible.modules.network.f5.bigip_traffic_group import ModuleManager
|
||||
from ansible.modules.network.f5.bigip_traffic_group import ArgumentSpec
|
||||
from ansible.modules.network.f5.bigip_device_traffic_group import ApiParameters
|
||||
from ansible.modules.network.f5.bigip_device_traffic_group import ModuleParameters
|
||||
from ansible.modules.network.f5.bigip_device_traffic_group import ModuleManager
|
||||
from ansible.modules.network.f5.bigip_device_traffic_group import ArgumentSpec
|
||||
|
||||
# Ansible 2.8 imports
|
||||
from units.compat import unittest
|
||||
|
@ -83,6 +83,22 @@ class TestParameters(unittest.TestCase):
|
|||
p = ModuleParameters(params=args)
|
||||
assert p.mac_address == '00:00:00:00:00:02'
|
||||
|
||||
def test_module_parameters_3(self):
|
||||
args = dict(
|
||||
name='foo',
|
||||
ha_order=['bigip1'],
|
||||
ha_group='',
|
||||
auto_failback='yes',
|
||||
auto_failback_time=40
|
||||
)
|
||||
|
||||
p = ModuleParameters(params=args)
|
||||
assert p.name == 'foo'
|
||||
assert p.ha_order == ['/Common/bigip1']
|
||||
assert p.ha_group == 'none'
|
||||
assert p.auto_failback == 'true'
|
||||
assert p.auto_failback_time == 40
|
||||
|
||||
def test_api_parameters_1(self):
|
||||
args = load_fixture('load_tm_cm_traffic_group_1.json')
|
||||
|
||||
|
@ -104,9 +120,11 @@ class TestManager(unittest.TestCase):
|
|||
def test_create(self, *args):
|
||||
set_module_args(dict(
|
||||
name='foo',
|
||||
server='localhost',
|
||||
password='password',
|
||||
user='admin'
|
||||
provider=dict(
|
||||
server='localhost',
|
||||
password='password',
|
||||
user='admin'
|
||||
)
|
||||
))
|
||||
|
||||
module = AnsibleModule(
|
||||
|
@ -121,3 +139,31 @@ class TestManager(unittest.TestCase):
|
|||
results = mm.exec_module()
|
||||
|
||||
assert results['changed'] is True
|
||||
|
||||
def test_modify_ha_order(self, *args):
|
||||
set_module_args(dict(
|
||||
name='traffic-group-2',
|
||||
ha_order=['v12-2.ansible.local', 'v12-1.ansible.local'],
|
||||
provider=dict(
|
||||
server='localhost',
|
||||
password='password',
|
||||
user='admin'
|
||||
)
|
||||
))
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=self.spec.argument_spec,
|
||||
supports_check_mode=self.spec.supports_check_mode,
|
||||
)
|
||||
|
||||
current = ApiParameters(params=load_fixture('load_tg_ha_order.json'))
|
||||
|
||||
mm = ModuleManager(module=module)
|
||||
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['ha_order'] == ['/Common/v12-2.ansible.local', '/Common/v12-1.ansible.local']
|
Loading…
Reference in a new issue