1
0
Fork 0
mirror of https://github.com/ansible-collections/community.general.git synced 2024-09-14 20:13:21 +02:00

Various fixes for f5 modules (#44734)

A number of bugfixes for the remaining 2.7 work on the F5 modules.
This commit is contained in:
Tim Rupp 2018-08-27 14:09:03 -07:00 committed by GitHub
parent 0d5390a919
commit 0dacc606b4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 560 additions and 199 deletions

View file

@ -207,6 +207,7 @@ from ansible.module_utils.network.common.utils import to_list
from ansible.module_utils.six import string_types from ansible.module_utils.six import string_types
from collections import deque from collections import deque
try: try:
from library.module_utils.network.f5.bigip import HAS_F5SDK from library.module_utils.network.f5.bigip import HAS_F5SDK
from library.module_utils.network.f5.bigip import F5Client from library.module_utils.network.f5.bigip import F5Client
@ -239,6 +240,10 @@ except ImportError:
HAS_CLI_TRANSPORT = False HAS_CLI_TRANSPORT = False
if HAS_F5SDK:
from f5.sdk_exception import LazyAttributesRequired
class NoChangeReporter(object): class NoChangeReporter(object):
stdout_re = [ stdout_re = [
# A general error when a resource already exists # A general error when a resource already exists
@ -635,6 +640,10 @@ class V2Manager(BaseManager):
responses.append(output.strip()) responses.append(output.strip())
except F5ModuleError: except F5ModuleError:
raise raise
except LazyAttributesRequired:
# This can happen if there is no "commandResult" attribute in
# the output variable above.
pass
return responses return responses

View file

@ -11127,7 +11127,7 @@ class VirtualServersParameters(BaseParameters):
@property @property
def enabled(self): def enabled(self):
if self._values['enabled'] is None: if self._values['enabled'] is None:
return None return 'no'
elif self._values['enabled'] is True: elif self._values['enabled'] is True:
return 'yes' return 'yes'
return 'no' return 'no'

View file

@ -29,6 +29,7 @@ notes:
- Best run as a local_action in your playbook - Best run as a local_action in your playbook
- Tested with manager and above account privilege level - Tested with manager and above account privilege level
- C(provision) facts were added in 2.2 - C(provision) facts were added in 2.2
- This module is deprecated. Use the C(bigip_device_facts) module instead.
requirements: requirements:
- bigsuds - bigsuds
options: options:
@ -75,7 +76,9 @@ EXAMPLES = r'''
server: lb.mydomain.com server: lb.mydomain.com
user: admin user: admin
password: secret password: secret
include: interface,vlan include:
- interface
- vlan
delegate_to: localhost delegate_to: localhost
''' '''

View file

@ -374,11 +374,7 @@ class ModuleManager(object):
response = self.client.api.delete(uri) response = self.client.api.delete(uri)
if response.status == 200: if response.status == 200:
return True return True
if 'code' in response and response['code'] == 400: raise F5ModuleError(response.content)
if 'message' in response:
raise F5ModuleError(response['message'])
else:
raise F5ModuleError(response.content)
def read_current_from_device(self): def read_current_from_device(self):
uri = "https://{0}:{1}/mgmt/tm/security/firewall/policy/{2}/?expandSubcollections=true".format( uri = "https://{0}:{1}/mgmt/tm/security/firewall/policy/{2}/?expandSubcollections=true".format(

View file

@ -31,8 +31,8 @@ options:
versions it will simply be ignored. versions it will simply be ignored.
state: state:
description: description:
- When C(state) is C(present), ensures that the policy exists. - When C(state) is C(present), ensures that the rule list exists.
- When C(state) is C(absent), ensures that the policy is removed. - When C(state) is C(absent), ensures that the rule list is removed.
choices: choices:
- present - present
- absent - absent

View file

@ -372,6 +372,26 @@ class Parameters(AnsibleF5Parameters):
# This seems to happen only on 12.0.0 # This seems to happen only on 12.0.0
elif tmp['value'] == 'none': elif tmp['value'] == 'none':
tmp['value'] = '' tmp['value'] = ''
elif tmp['value'] == 'True':
tmp['value'] = 'yes'
elif tmp['value'] == 'False':
tmp['value'] = 'no'
elif isinstance(tmp['value'], bool):
if tmp['value'] is True:
tmp['value'] = 'yes'
else:
tmp['value'] = 'no'
if tmp['encrypted'] == 'True':
tmp['encrypted'] = 'yes'
elif tmp['encrypted'] == 'False':
tmp['encrypted'] = 'no'
elif isinstance(tmp['encrypted'], bool):
if tmp['encrypted'] is True:
tmp['encrypted'] = 'yes'
else:
tmp['encrypted'] = 'no'
result.append(tmp) result.append(tmp)
result = sorted(result, key=lambda k: k['name']) result = sorted(result, key=lambda k: k['name'])
return result return result
@ -390,6 +410,17 @@ class Parameters(AnsibleF5Parameters):
# BIG-IP removes empty values entries, so mimic this behavior # BIG-IP removes empty values entries, so mimic this behavior
# for user-supplied values. # for user-supplied values.
tmp['value'] = [str(x) for x in list['value']] tmp['value'] = [str(x) for x in list['value']]
if tmp['encrypted'] == 'True':
tmp['encrypted'] = 'yes'
elif tmp['encrypted'] == 'False':
tmp['encrypted'] = 'no'
elif isinstance(tmp['encrypted'], bool):
if tmp['encrypted'] is True:
tmp['encrypted'] = 'yes'
else:
tmp['encrypted'] = 'no'
result.append(tmp) result.append(tmp)
result = sorted(result, key=lambda k: k['name']) result = sorted(result, key=lambda k: k['name'])
return result return result

View file

@ -85,7 +85,6 @@ RETURN = r'''
''' '''
import os import os
import subprocess
import time import time
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule

View file

@ -419,7 +419,7 @@ class ApiParameters(Parameters):
@property @property
def state(self): def state(self):
if self._values['state'] in ['user-up', 'unchecked', 'fqdn-up-no-addr'] and self._values['session'] in ['user-enabled']: if self._values['state'] in ['user-up', 'unchecked', 'fqdn-up-no-addr', 'fqdn-up'] and self._values['session'] in ['user-enabled']:
return 'present' return 'present'
elif self._values['state'] in ['down', 'up'] and self._values['session'] == 'monitor-enabled': elif self._values['state'] in ['down', 'up'] and self._values['session'] == 'monitor-enabled':
return 'present' return 'present'
@ -476,7 +476,7 @@ class ReportableChanges(Changes):
@property @property
def state(self): def state(self):
if self._values['state'] in ['user-up', 'unchecked', 'fqdn-up-no-addr'] and self._values['session'] in ['user-enabled']: if self._values['state'] in ['user-up', 'unchecked', 'fqdn-up-no-addr', 'fqdn-up'] and self._values['session'] in ['user-enabled']:
return 'present' return 'present'
elif self._values['state'] in ['down', 'up'] and self._values['session'] == 'monitor-enabled': elif self._values['state'] in ['down', 'up'] and self._values['session'] == 'monitor-enabled':
return 'present' return 'present'

View file

@ -592,12 +592,7 @@ class ModuleManager(object):
response = self.client.api.delete(uri) response = self.client.api.delete(uri)
if response.status == 200: if response.status == 200:
return True return True
raise F5ModuleError(response.content)
if 'code' in response and response['code'] == 400:
if 'message' in response:
raise F5ModuleError(response['message'])
else:
raise F5ModuleError(response.content)
def read_current_from_device(self): def read_current_from_device(self):
uri = "https://{0}:{1}/mgmt/tm/ltm/profile/http/{2}".format( uri = "https://{0}:{1}/mgmt/tm/ltm/profile/http/{2}".format(

View file

@ -18,9 +18,8 @@ module: bigip_user
short_description: Manage user accounts and user attributes on a BIG-IP short_description: Manage user accounts and user attributes on a BIG-IP
description: description:
- Manage user accounts and user attributes on a BIG-IP. Typically this - Manage user accounts and user attributes on a BIG-IP. Typically this
module operates only on the REST API users and not the CLI users. There module operates only on the REST API users and not the CLI users.
is one exception though and that is if you specify the C(username_credential) When specifying C(root), you may only change the password.
of C(root). When specifying C(root), you may only change the password.
Your other parameters will be ignored in this case. Changing the C(root) Your other parameters will be ignored in this case. Changing the C(root)
password is not an idempotent operation. Therefore, it will change it password is not an idempotent operation. Therefore, it will change it
every time this module attempts to change it. every time this module attempts to change it.
@ -31,8 +30,8 @@ options:
- Full name of the user. - Full name of the user.
username_credential: username_credential:
description: description:
- Name of the user to create, remove or modify. There is a special case - Name of the user to create, remove or modify.
that exists for the user C(root). - The C(root) user may not be removed.
required: True required: True
aliases: aliases:
- name - name

View file

@ -48,9 +48,23 @@ options:
both ARP and ICMP Echo must be disabled in order for forwarding both ARP and ICMP Echo must be disabled in order for forwarding
virtual servers using that virtual address to forward ICMP packets. virtual servers using that virtual address to forward ICMP packets.
If (enabled), then the packets are dropped. If (enabled), then the packets are dropped.
- Deprecated. Use the C(arp) parameter instead.
- When creating a new virtual address, if this parameter is not specified,
the default value is C(enabled).
choices: choices:
- enabled - enabled
- disabled - disabled
arp:
description:
- Specifies whether the system accepts ARP requests.
- When C(no), specifies that the system does not accept ARP requests.
- When C(yes), then the packets are dropped.
- Note that both ARP and ICMP Echo must be disabled in order for forwarding
virtual servers using that virtual address to forward ICMP packets.
- When creating a new virtual address, if this parameter is not specified,
the default value is C(yes).
type: bool
version_added: 2.7
auto_delete: auto_delete:
description: description:
- Specifies whether the system automatically deletes the virtual - Specifies whether the system automatically deletes the virtual
@ -58,9 +72,9 @@ options:
When C(disabled), specifies that the system leaves the virtual When C(disabled), specifies that the system leaves the virtual
address even when all associated virtual servers have been deleted. address even when all associated virtual servers have been deleted.
When creating the virtual address, the default value is C(enabled). When creating the virtual address, the default value is C(enabled).
choices: - C(enabled) and C(disabled) are deprecated and will be removed in
- enabled Ansible 2.11. Instead, use known Ansible booleans such as C(yes) and
- disabled C(no)
icmp_echo: icmp_echo:
description: description:
- Specifies how the systems sends responses to (ICMP) echo requests - Specifies how the systems sends responses to (ICMP) echo requests
@ -157,12 +171,22 @@ options:
- The route domain of the C(address) that you want to use. - The route domain of the C(address) that you want to use.
- This value cannot be modified after it is set. - This value cannot be modified after it is set.
version_added: 2.6 version_added: 2.6
notes: spanning:
- Requires the netaddr Python package on the host. This is as easy as pip description:
install netaddr. - Enables all BIG-IP systems in a device group to listen for and process traffic
on the same virtual address.
- Spanning for a virtual address occurs when you enable the C(spanning) option on a
device and then sync the virtual address to the other members of the device group.
- Spanning also relies on the upstream router to distribute application flows to the
BIG-IP systems using ECMP routes. ECMP defines a route to the virtual address using
distinct Floating self-IP addresses configured on each BIG-IP system.
- You must also configure MAC masquerade addresses and disable C(arp) on the virtual
address when Spanning is enabled.
- When creating a new virtual address, if this parameter is not specified, the default
valus is C(no).
version_added: 2.7
type: bool
extends_documentation_fragment: f5 extends_documentation_fragment: f5
requirements:
- netaddr
author: author:
- Tim Rupp (@caphrim007) - Tim Rupp (@caphrim007)
''' '''
@ -215,11 +239,11 @@ netmask:
returned: created returned: created
type: int type: int
sample: 2345 sample: 2345
arp_state: arp:
description: The new way the virtual address handles ARP requests. description: The new way the virtual address handles ARP requests.
returned: changed returned: changed
type: string type: bool
sample: disabled sample: yes
address: address:
description: The address of the virtual address. description: The address of the virtual address.
returned: created returned: created
@ -230,6 +254,11 @@ state:
returned: changed returned: changed
type: string type: string
sample: disabled sample: disabled
spanning:
description: Whether spanning is enabled or not
returned: changed
type: string
sample: disabled
''' '''
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
@ -246,6 +275,7 @@ try:
from library.module_utils.network.f5.common import cleanup_tokens from library.module_utils.network.f5.common import cleanup_tokens
from library.module_utils.network.f5.common import fq_name from library.module_utils.network.f5.common import fq_name
from library.module_utils.network.f5.common import f5_argument_spec from library.module_utils.network.f5.common import f5_argument_spec
from library.module_utils.network.f5.ipaddress import is_valid_ip
try: try:
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
except ImportError: except ImportError:
@ -258,17 +288,12 @@ except ImportError:
from ansible.module_utils.network.f5.common import cleanup_tokens from ansible.module_utils.network.f5.common import cleanup_tokens
from ansible.module_utils.network.f5.common import fq_name from ansible.module_utils.network.f5.common import fq_name
from ansible.module_utils.network.f5.common import f5_argument_spec from ansible.module_utils.network.f5.common import f5_argument_spec
from ansible.module_utils.network.f5.ipaddress import is_valid_ip
try: try:
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
except ImportError: except ImportError:
HAS_F5SDK = False HAS_F5SDK = False
try:
import netaddr
HAS_NETADDR = True
except ImportError:
HAS_NETADDR = False
class Parameters(AnsibleF5Parameters): class Parameters(AnsibleF5Parameters):
api_map = { api_map = {
@ -278,23 +303,47 @@ class Parameters(AnsibleF5Parameters):
'connectionLimit': 'connection_limit', 'connectionLimit': 'connection_limit',
'serverScope': 'availability_calculation', 'serverScope': 'availability_calculation',
'mask': 'netmask', 'mask': 'netmask',
'arp': 'arp_state',
'trafficGroup': 'traffic_group', 'trafficGroup': 'traffic_group',
} }
updatables = [ updatables = [
'route_advertisement_type', 'auto_delete', 'icmp_echo', 'connection_limit', 'route_advertisement_type',
'arp_state', 'enabled', 'availability_calculation', 'traffic_group' 'auto_delete',
'icmp_echo',
'connection_limit',
'arp',
'enabled',
'availability_calculation',
'traffic_group',
'spanning',
] ]
returnables = [ returnables = [
'route_advertisement_type', 'auto_delete', 'icmp_echo', 'connection_limit', 'route_advertisement_type',
'netmask', 'arp_state', 'address', 'state', 'traffic_group', 'route_domain' 'auto_delete',
'icmp_echo',
'connection_limit',
'netmask',
'arp',
'address',
'state',
'traffic_group',
'route_domain',
'spanning',
] ]
api_attributes = [ api_attributes = [
'routeAdvertisement', 'autoDelete', 'icmpEcho', 'connectionLimit', 'routeAdvertisement',
'advertiseRoute', 'arp', 'mask', 'enabled', 'serverScope', 'trafficGroup' 'autoDelete',
'icmpEcho',
'connectionLimit',
'advertiseRoute',
'arp',
'mask',
'enabled',
'serverScope',
'trafficGroup',
'spanning',
] ]
@property @property
@ -331,10 +380,9 @@ class Parameters(AnsibleF5Parameters):
def netmask(self): def netmask(self):
if self._values['netmask'] is None: if self._values['netmask'] is None:
return None return None
try: if is_valid_ip(self._values['netmask']):
ip = netaddr.IPAddress(self._values['netmask']) return self._values['netmask']
return str(ip) else:
except netaddr.core.AddrFormatError:
raise F5ModuleError( raise F5ModuleError(
"The provided 'netmask' is not a valid IP address" "The provided 'netmask' is not a valid IP address"
) )
@ -414,18 +462,41 @@ class Parameters(AnsibleF5Parameters):
class ApiParameters(Parameters): class ApiParameters(Parameters):
pass @property
def arp(self):
if self._values['arp'] is None:
return None
elif self._values['arp'] == 'enabled':
return True
return False
@property
def spanning(self):
if self._values['spanning'] is None:
return None
if self._values['spanning'] == 'enabled':
return True
return False
class ModuleParameters(Parameters): class ModuleParameters(Parameters):
@property
def arp(self):
if self._values['arp'] is None:
if self.arp_state and self.arp_state == 'enabled':
return True
elif self.arp_state and self.arp_state == 'disabled':
return False
else:
return self._values['arp']
@property @property
def address(self): def address(self):
if self._values['address'] is None: if self._values['address'] is None:
return None return None
try: if is_valid_ip(self._values['address']):
ip = netaddr.IPAddress(self._values['address']) return self._values['address']
return str(ip) else:
except netaddr.core.AddrFormatError:
raise F5ModuleError( raise F5ModuleError(
"The provided 'address' is not a valid IP address" "The provided 'address' is not a valid IP address"
) )
@ -479,9 +550,31 @@ class UsableChanges(Changes):
result = "{0}%{1}".format(self._values['address'], self._values['route_domain']) result = "{0}%{1}".format(self._values['address'], self._values['route_domain'])
return result return result
@property
def arp(self):
if self._values['arp'] is None:
return None
elif self._values['arp'] is True:
return 'enabled'
elif self._values['arp'] is False:
return 'disabled'
@property
def spanning(self):
if self._values['spanning'] is None:
return None
if self._values['spanning']:
return 'enabled'
return 'disabled'
class ReportableChanges(Changes): class ReportableChanges(Changes):
pass @property
def arp(self):
if self._values['arp'] == 'disabled':
return 'no'
elif self._values['arp'] == 'enabled':
return 'yes'
class Difference(object): class Difference(object):
@ -510,6 +603,20 @@ class Difference(object):
if self.want.traffic_group != self.have.traffic_group: if self.want.traffic_group != self.have.traffic_group:
return self.want.traffic_group return self.want.traffic_group
@property
def spanning(self):
if self.want.spanning is None:
return None
if self.want.spanning != self.have.spanning:
return self.want.spanning
@property
def arp_state(self):
if self.want.arp_state is None:
return None
if self.want.arp_state != self.have.arp_state:
return self.want.arp_state
class ModuleManager(object): class ModuleManager(object):
def __init__(self, *args, **kwargs): def __init__(self, *args, **kwargs):
@ -617,6 +724,11 @@ class ModuleManager(object):
"The address cannot be changed. Delete and recreate " "The address cannot be changed. Delete and recreate "
"the virtual address if you need to do this." "the virtual address if you need to do this."
) )
if self.changes.arp and self.changes.spanning:
raise F5ModuleError(
"'arp' and 'spanning' cannot both be enabled on virtual address."
)
if not self.should_update(): if not self.should_update():
return False return False
if self.module.check_mode: if self.module.check_mode:
@ -636,8 +748,18 @@ class ModuleManager(object):
def create(self): def create(self):
self._set_changed_options() self._set_changed_options()
if self.want.traffic_group is None: if self.want.traffic_group is None:
self.want.update({'traffic_group': '/Common/traffic-group-1'}) self.want.update({'traffic_group': '/Common/traffic-group-1'})
if self.want.arp is None:
self.want.update({'arp': True})
if self.want.spanning is None:
self.want.update({'spanning': False})
if self.want.arp and self.want.spanning:
raise F5ModuleError(
"'arp' and 'spanning' cannot both be enabled on virtual address."
)
if self.module.check_mode: if self.module.check_mode:
return True return True
self.create_on_device() self.create_on_device()
@ -690,12 +812,8 @@ class ArgumentSpec(object):
connection_limit=dict( connection_limit=dict(
type='int' type='int'
), ),
arp_state=dict(
choices=['enabled', 'disabled'], auto_delete=dict(),
),
auto_delete=dict(
choices=['enabled', 'disabled'],
),
icmp_echo=dict( icmp_echo=dict(
choices=['enabled', 'disabled', 'selective'], choices=['enabled', 'disabled', 'selective'],
), ),
@ -703,6 +821,15 @@ class ArgumentSpec(object):
choices=['always', 'when_all_available', 'when_any_available'], choices=['always', 'when_all_available', 'when_any_available'],
aliases=['advertise_route'] aliases=['advertise_route']
), ),
traffic_group=dict(),
partition=dict(
default='Common',
fallback=(env_fallback, ['F5_PARTITION'])
),
route_domain=dict(),
spanning=dict(type='bool'),
# Deprecated pair - route advertisement
use_route_advertisement=dict( use_route_advertisement=dict(
type='bool', type='bool',
removed_in_version=2.9, removed_in_version=2.9,
@ -717,12 +844,13 @@ class ArgumentSpec(object):
'all', 'all',
] ]
), ),
traffic_group=dict(),
partition=dict( # Deprecated pair - ARP
default='Common', arp_state=dict(
fallback=(env_fallback, ['F5_PARTITION']) choices=['enabled', 'disabled'],
removed_in_version=2.11,
), ),
route_domain=dict() arp=dict(type='bool'),
) )
self.argument_spec = {} self.argument_spec = {}
self.argument_spec.update(f5_argument_spec) self.argument_spec.update(f5_argument_spec)
@ -731,7 +859,8 @@ class ArgumentSpec(object):
['name', 'address'] ['name', 'address']
] ]
self.mutually_exclusive = [ self.mutually_exclusive = [
['use_route_advertisement', 'route_advertisement'] ['use_route_advertisement', 'route_advertisement'],
['arp_state', 'arp']
] ]
@ -744,8 +873,6 @@ def main():
) )
if not HAS_F5SDK: if not HAS_F5SDK:
module.fail_json(msg="The python f5-sdk module is required") module.fail_json(msg="The python f5-sdk module is required")
if not HAS_NETADDR:
module.fail_json(msg="The python netaddr module is required")
try: try:
client = F5Client(**module.params) client = F5Client(**module.params)

View file

@ -637,35 +637,31 @@ from ansible.module_utils.six import iteritems
from collections import namedtuple from collections import namedtuple
try: try:
from library.module_utils.network.f5.bigip import HAS_F5SDK from library.module_utils.network.f5.bigip import F5RestClient
from library.module_utils.network.f5.bigip import F5Client
from library.module_utils.network.f5.common import F5ModuleError 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 AnsibleF5Parameters
from library.module_utils.network.f5.common import cleanup_tokens from library.module_utils.network.f5.common import cleanup_tokens
from library.module_utils.network.f5.common import fq_name from library.module_utils.network.f5.common import fq_name
from library.module_utils.network.f5.common import f5_argument_spec from library.module_utils.network.f5.common import f5_argument_spec
from library.module_utils.network.f5.common import fail_json
from library.module_utils.network.f5.common import exit_json
from library.module_utils.network.f5.common import transform_name
from library.module_utils.network.f5.ipaddress import is_valid_ip from library.module_utils.network.f5.ipaddress import is_valid_ip
from library.module_utils.network.f5.ipaddress import ip_interface from library.module_utils.network.f5.ipaddress import ip_interface
from library.module_utils.network.f5.ipaddress import validate_ip_v6_address from library.module_utils.network.f5.ipaddress import validate_ip_v6_address
try:
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
except ImportError:
HAS_F5SDK = False
except ImportError: except ImportError:
from ansible.module_utils.network.f5.bigip import HAS_F5SDK from ansible.module_utils.network.f5.bigip import F5RestClient
from ansible.module_utils.network.f5.bigip import F5Client
from ansible.module_utils.network.f5.common import F5ModuleError 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 AnsibleF5Parameters
from ansible.module_utils.network.f5.common import cleanup_tokens from ansible.module_utils.network.f5.common import cleanup_tokens
from ansible.module_utils.network.f5.common import fq_name from ansible.module_utils.network.f5.common import fq_name
from ansible.module_utils.network.f5.common import f5_argument_spec from ansible.module_utils.network.f5.common import f5_argument_spec
from ansible.module_utils.network.f5.common import fail_json
from ansible.module_utils.network.f5.common import exit_json
from ansible.module_utils.network.f5.common import transform_name
from ansible.module_utils.network.f5.ipaddress import is_valid_ip from ansible.module_utils.network.f5.ipaddress import is_valid_ip
from ansible.module_utils.network.f5.ipaddress import ip_interface from ansible.module_utils.network.f5.ipaddress import ip_interface
from ansible.module_utils.network.f5.ipaddress import validate_ip_v6_address from ansible.module_utils.network.f5.ipaddress import validate_ip_v6_address
try:
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
except ImportError:
HAS_F5SDK = False
class Parameters(AnsibleF5Parameters): class Parameters(AnsibleF5Parameters):
@ -913,20 +909,85 @@ class Parameters(AnsibleF5Parameters):
return False return False
def _read_current_message_routing_profiles_from_device(self): def _read_current_message_routing_profiles_from_device(self):
collection1 = self.client.api.tm.ltm.profile.diameters.get_collection() result = []
collection2 = self.client.api.tm.ltm.profile.sips.get_collection() result += self._read_diameter_profiles_from_device()
result = [x.name for x in collection1] result += self._read_sip_profiles_from_device()
result += [x.name for x in collection2] return result
def _read_diameter_profiles_from_device(self):
uri = "https://{0}:{1}/mgmt/tm/ltm/profile/diameter/".format(
self.client.provider['server'],
self.client.provider['server_port'],
)
resp = self.client.api.get(uri)
try:
response = resp.json()
except ValueError as ex:
raise F5ModuleError(str(ex))
if 'code' in response and response['code'] == 400:
if 'message' in response:
raise F5ModuleError(response['message'])
else:
raise F5ModuleError(resp.content)
result = [x['name'] for x in response['items']]
return result
def _read_sip_profiles_from_device(self):
uri = "https://{0}:{1}/mgmt/tm/ltm/profile/sip/".format(
self.client.provider['server'],
self.client.provider['server_port'],
)
resp = self.client.api.get(uri)
try:
response = resp.json()
except ValueError as ex:
raise F5ModuleError(str(ex))
if 'code' in response and response['code'] == 400:
if 'message' in response:
raise F5ModuleError(response['message'])
else:
raise F5ModuleError(resp.content)
result = [x['name'] for x in response['items']]
return result return result
def _read_current_fastl4_profiles_from_device(self): def _read_current_fastl4_profiles_from_device(self):
collection = self.client.api.tm.ltm.profile.fastl4s.get_collection() uri = "https://{0}:{1}/mgmt/tm/ltm/profile/fastl4/".format(
result = [x.name for x in collection] self.client.provider['server'],
self.client.provider['server_port'],
)
resp = self.client.api.get(uri)
try:
response = resp.json()
except ValueError as ex:
raise F5ModuleError(str(ex))
if 'code' in response and response['code'] == 400:
if 'message' in response:
raise F5ModuleError(response['message'])
else:
raise F5ModuleError(resp.content)
result = [x['name'] for x in response['items']]
return result return result
def _read_current_fasthttp_profiles_from_device(self): def _read_current_fasthttp_profiles_from_device(self):
collection = self.client.api.tm.ltm.profile.fasthttps.get_collection() uri = "https://{0}:{1}/mgmt/tm/ltm/profile/fasthttp/".format(
result = [x.name for x in collection] self.client.provider['server'],
self.client.provider['server_port'],
)
resp = self.client.api.get(uri)
try:
response = resp.json()
except ValueError as ex:
raise F5ModuleError(str(ex))
if 'code' in response and response['code'] == 400:
if 'message' in response:
raise F5ModuleError(response['message'])
else:
raise F5ModuleError(resp.content)
result = [x['name'] for x in response['items']]
return result return result
@ -1246,6 +1307,12 @@ class ApiParameters(Parameters):
return None return None
return self._values['security_nat_policy']['policy'] return self._values['security_nat_policy']['policy']
@property
def irules(self):
if self._values['irules'] is None:
return []
return self._values['irules']
class ModuleParameters(Parameters): class ModuleParameters(Parameters):
services_map = { services_map = {
@ -2268,25 +2335,104 @@ class VirtualServerValidator(object):
) )
def read_dhcp_profiles_from_device(self): def read_dhcp_profiles_from_device(self):
collection = self.client.api.tm.ltm.profile.dhcpv4s.get_collection() result = []
result = [fq_name(self.want.partition, x.name) for x in collection] result += self.read_dhcpv4_profiles_from_device()
collection = self.client.api.tm.ltm.profile.dhcpv6s.get_collection() result += self.read_dhcpv6_profiles_from_device()
result += [fq_name(self.want.partition, x.name) for x in collection] return result
def read_dhcpv4_profiles_from_device(self):
uri = "https://{0}:{1}/mgmt/tm/ltm/profile/dhcpv4/".format(
self.client.provider['server'],
self.client.provider['server_port'],
)
resp = self.client.api.get(uri)
try:
response = resp.json()
except ValueError as ex:
raise F5ModuleError(str(ex))
if 'code' in response and response['code'] == 400:
if 'message' in response:
raise F5ModuleError(response['message'])
else:
raise F5ModuleError(resp.content)
result = [fq_name(self.want.partition, x['name']) for x in response['items']]
return result
def read_dhcpv6_profiles_from_device(self):
uri = "https://{0}:{1}/mgmt/tm/ltm/profile/dhcpv6/".format(
self.client.provider['server'],
self.client.provider['server_port'],
)
resp = self.client.api.get(uri)
try:
response = resp.json()
except ValueError as ex:
raise F5ModuleError(str(ex))
if 'code' in response and response['code'] == 400:
if 'message' in response:
raise F5ModuleError(response['message'])
else:
raise F5ModuleError(resp.content)
result = [fq_name(self.want.partition, x['name']) for x in response['items']]
return result return result
def read_fastl4_profiles_from_device(self): def read_fastl4_profiles_from_device(self):
collection = self.client.api.tm.ltm.profile.fastl4s.get_collection() uri = "https://{0}:{1}/mgmt/tm/ltm/profile/fastl4/".format(
result = [fq_name(self.want.partition, x.name) for x in collection] self.client.provider['server'],
self.client.provider['server_port'],
)
resp = self.client.api.get(uri)
try:
response = resp.json()
except ValueError as ex:
raise F5ModuleError(str(ex))
if 'code' in response and response['code'] == 400:
if 'message' in response:
raise F5ModuleError(response['message'])
else:
raise F5ModuleError(resp.content)
result = [fq_name(self.want.partition, x['name']) for x in response['items']]
return result return result
def read_fasthttp_profiles_from_device(self): def read_fasthttp_profiles_from_device(self):
collection = self.client.api.tm.ltm.profile.fasthttps.get_collection() uri = "https://{0}:{1}/mgmt/tm/ltm/profile/fasthttp/".format(
result = [fq_name(self.want.partition, x.name) for x in collection] self.client.provider['server'],
self.client.provider['server_port'],
)
resp = self.client.api.get(uri)
try:
response = resp.json()
except ValueError as ex:
raise F5ModuleError(str(ex))
if 'code' in response and response['code'] == 400:
if 'message' in response:
raise F5ModuleError(response['message'])
else:
raise F5ModuleError(resp.content)
result = [fq_name(self.want.partition, x['name']) for x in response['items']]
return result return result
def read_udp_profiles_from_device(self): def read_udp_profiles_from_device(self):
collection = self.client.api.tm.ltm.profile.udps.get_collection() uri = "https://{0}:{1}/mgmt/tm/ltm/profile/udp/".format(
result = [fq_name(self.want.partition, x.name) for x in collection] self.client.provider['server'],
self.client.provider['server_port'],
)
resp = self.client.api.get(uri)
try:
response = resp.json()
except ValueError as ex:
raise F5ModuleError(str(ex))
if 'code' in response and response['code'] == 400:
if 'message' in response:
raise F5ModuleError(response['message'])
else:
raise F5ModuleError(resp.content)
result = [fq_name(self.want.partition, x['name']) for x in response['items']]
return result return result
@ -2637,13 +2783,10 @@ class ModuleManager(object):
result = dict() result = dict()
state = self.want.state state = self.want.state
try: if state in ['present', 'enabled', 'disabled']:
if state in ['present', 'enabled', 'disabled']: changed = self.present()
changed = self.present() elif state == "absent":
elif state == "absent": changed = self.absent()
changed = self.absent()
except iControlUnexpectedHTTPError as e:
raise F5ModuleError(str(e))
reportable = ReportableChanges(params=self.changes.to_return()) reportable = ReportableChanges(params=self.changes.to_return())
changes = reportable.to_return() changes = reportable.to_return()
@ -2664,7 +2807,9 @@ class ModuleManager(object):
def update(self): def update(self):
self.have = self.read_current_from_device() self.have = self.read_current_from_device()
validator = VirtualServerValidator(module=self.module, client=self.client, have=self.have, want=self.want) validator = VirtualServerValidator(
module=self.module, client=self.client, have=self.have, want=self.want
)
validator.check_update() validator.check_update()
if not self.should_update(): if not self.should_update():
@ -2719,14 +2864,24 @@ class ModuleManager(object):
return False return False
def exists(self): def exists(self):
result = self.client.api.tm.ltm.virtuals.virtual.exists( uri = "https://{0}:{1}/mgmt/tm/ltm/virtual/{2}".format(
name=self.want.name, self.client.provider['server'],
partition=self.want.partition self.client.provider['server_port'],
transform_name(self.want.partition, self.want.name)
) )
return result resp = self.client.api.get(uri)
try:
response = resp.json()
except ValueError:
return False
if resp.status == 404 or 'code' in response and response['code'] == 404:
return False
return True
def create(self): def create(self):
validator = VirtualServerValidator(module=self.module, client=self.client, have=self.have, want=self.want) validator = VirtualServerValidator(
module=self.module, client=self.client, have=self.have, want=self.want
)
validator.check_create() validator.check_create()
self._set_changed_options() self._set_changed_options()
@ -2737,42 +2892,73 @@ class ModuleManager(object):
def update_on_device(self): def update_on_device(self):
params = self.changes.api_params() params = self.changes.api_params()
resource = self.client.api.tm.ltm.virtuals.virtual.load( uri = "https://{0}:{1}/mgmt/tm/ltm/virtual/{2}".format(
name=self.want.name, self.client.provider['server'],
partition=self.want.partition self.client.provider['server_port'],
transform_name(self.want.partition, self.want.name)
) )
resource.modify(**params) resp = self.client.api.patch(uri, json=params)
try:
response = resp.json()
except ValueError as ex:
raise F5ModuleError(str(ex))
if 'code' in response and response['code'] == 400:
if 'message' in response:
raise F5ModuleError(response['message'])
else:
raise F5ModuleError(resp.content)
def read_current_from_device(self): def read_current_from_device(self):
result = self.client.api.tm.ltm.virtuals.virtual.load( uri = "https://{0}:{1}/mgmt/tm/ltm/virtual/{2}?expandSubcollections=true".format(
name=self.want.name, self.client.provider['server'],
partition=self.want.partition, self.client.provider['server_port'],
requests_params=dict( transform_name(self.want.partition, self.want.name)
params=dict(
expandSubcollections='true'
)
)
) )
params = result.attrs resp = self.client.api.get(uri)
params.update(dict(kind=result.to_dict().get('kind', None))) try:
result = ApiParameters(params=params, client=self.client) response = resp.json()
return result except ValueError as ex:
raise F5ModuleError(str(ex))
if 'code' in response and response['code'] == 400:
if 'message' in response:
raise F5ModuleError(response['message'])
else:
raise F5ModuleError(resp.content)
return ApiParameters(params=response, client=self.client)
def create_on_device(self): def create_on_device(self):
params = self.changes.api_params() params = self.changes.api_params()
self.client.api.tm.ltm.virtuals.virtual.create( params['name'] = self.want.name
name=self.want.name, params['partition'] = self.want.partition
partition=self.want.partition, uri = "https://{0}:{1}/mgmt/tm/ltm/virtual/".format(
**params self.client.provider['server'],
self.client.provider['server_port']
) )
resp = self.client.api.post(uri, json=params)
try:
response = resp.json()
except ValueError as ex:
raise F5ModuleError(str(ex))
if 'code' in response and response['code'] in [400, 403]:
if 'message' in response:
raise F5ModuleError(response['message'])
else:
raise F5ModuleError(resp.content)
def remove_from_device(self): def remove_from_device(self):
resource = self.client.api.tm.ltm.virtuals.virtual.load( uri = "https://{0}:{1}/mgmt/tm/ltm/virtual/{2}".format(
name=self.want.name, self.client.provider['server'],
partition=self.want.partition self.client.provider['server_port'],
transform_name(self.want.partition, self.want.name)
) )
if resource: response = self.client.api.delete(uri)
resource.delete() if response.status == 200:
return True
raise F5ModuleError(response.content)
class ArgumentSpec(object): class ArgumentSpec(object):
@ -2868,18 +3054,16 @@ def main():
supports_check_mode=spec.supports_check_mode, supports_check_mode=spec.supports_check_mode,
mutually_exclusive=spec.mutually_exclusive mutually_exclusive=spec.mutually_exclusive
) )
if not HAS_F5SDK:
module.fail_json(msg="The python f5-sdk module is required")
try: try:
client = F5Client(**module.params) client = F5RestClient(**module.params)
mm = ModuleManager(module=module, client=client) mm = ModuleManager(module=module, client=client)
results = mm.exec_module() results = mm.exec_module()
exit_json(module, results, client)
cleanup_tokens(client) cleanup_tokens(client)
module.exit_json(**results)
except F5ModuleError as ex: except F5ModuleError as ex:
cleanup_tokens(client) cleanup_tokens(client)
module.fail_json(msg=str(ex)) fail_json(module, ex, client)
if __name__ == '__main__': if __name__ == '__main__':

View file

@ -81,25 +81,19 @@ import time
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
try: try:
from library.module_utils.network.f5.bigip import HAS_F5SDK from library.module_utils.network.f5.bigip import F5RestClient
from library.module_utils.network.f5.bigip import F5Client
from library.module_utils.network.f5.common import F5ModuleError 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 AnsibleF5Parameters
from library.module_utils.network.f5.common import f5_argument_spec from library.module_utils.network.f5.common import f5_argument_spec
try: from library.module_utils.network.f5.common import exit_json
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError from library.module_utils.network.f5.common import fail_json
except ImportError:
HAS_F5SDK = False
except ImportError: except ImportError:
from ansible.module_utils.network.f5.bigip import HAS_F5SDK from ansible.module_utils.network.f5.bigip import F5RestClient
from ansible.module_utils.network.f5.bigip import F5Client
from ansible.module_utils.network.f5.common import F5ModuleError 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 AnsibleF5Parameters
from ansible.module_utils.network.f5.common import f5_argument_spec from ansible.module_utils.network.f5.common import f5_argument_spec
try: from ansible.module_utils.network.f5.common import exit_json
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError from ansible.module_utils.network.f5.common import fail_json
except ImportError:
HAS_F5SDK = False
def hard_timeout(module, want, start): def hard_timeout(module, want, start):
@ -158,10 +152,7 @@ class ModuleManager(object):
def exec_module(self): def exec_module(self):
result = dict() result = dict()
try: changed = self.execute()
changed = self.execute()
except iControlUnexpectedHTTPError as e:
raise F5ModuleError(str(e))
changes = self.changes.to_return() changes = self.changes.to_return()
result.update(**changes) result.update(**changes)
@ -178,7 +169,7 @@ class ModuleManager(object):
) )
def _get_client_connection(self): def _get_client_connection(self):
return F5Client(**self.module.params) return F5RestClient(**self.module.params)
def execute(self): def execute(self):
signal.signal( signal.signal(
@ -210,7 +201,7 @@ class ModuleManager(object):
if self._is_mprov_running_on_device(): if self._is_mprov_running_on_device():
self._wait_for_module_provisioning() self._wait_for_module_provisioning()
break break
except Exception: except Exception as ex:
# The types of exception's we're handling here are "REST API is not # The types of exception's we're handling here are "REST API is not
# ready" exceptions. # ready" exceptions.
# #
@ -248,15 +239,28 @@ class ModuleManager(object):
return False return False
def _device_is_rebooting(self): def _device_is_rebooting(self):
output = self.client.api.tm.util.bash.exec_cmd( params = {
'run', "command": "run",
utilCmdArgs='-c "runlevel"' "utilCmdArgs": '-c "runlevel"'
}
uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
self.client.provider['server'],
self.client.provider['server_port']
) )
resp = self.client.api.post(uri, json=params)
try: try:
if '6' in output.commandResult: response = resp.json()
return True except ValueError as ex:
except AttributeError: raise F5ModuleError(str(ex))
return False if 'code' in response and response['code'] in [400, 403]:
if 'message' in response:
raise F5ModuleError(response['message'])
else:
raise F5ModuleError(resp.content)
if 'commandResult' in response and '6' in response['commandResult']:
return True
return False
def _wait_for_module_provisioning(self): def _wait_for_module_provisioning(self):
# To prevent things from running forever, the hack is to check # To prevent things from running forever, the hack is to check
@ -271,17 +275,32 @@ class ModuleManager(object):
nops += 1 nops += 1
else: else:
nops = 0 nops = 0
except Exception: except Exception as ex:
# This can be caused by restjavad restarting. # This can be caused by restjavad restarting.
pass pass
time.sleep(10) time.sleep(10)
def _is_mprov_running_on_device(self): def _is_mprov_running_on_device(self):
output = self.client.api.tm.util.bash.exec_cmd( params = {
'run', "command": "run",
utilCmdArgs='-c "ps aux | grep \'[m]prov\'"' "utilCmdArgs": '-c "ps aux | grep \'[m]prov\'"'
}
uri = "https://{0}:{1}/mgmt/tm/util/bash".format(
self.client.provider['server'],
self.client.provider['server_port']
) )
if hasattr(output, 'commandResult'): resp = self.client.api.post(uri, json=params)
try:
response = resp.json()
except ValueError as ex:
raise F5ModuleError(str(ex))
if 'code' in response and response['code'] in [400, 403]:
if 'message' in response:
raise F5ModuleError(response['message'])
else:
raise F5ModuleError(resp.content)
if 'commandResult' in response:
return True return True
return False return False
@ -307,15 +326,14 @@ def main():
argument_spec=spec.argument_spec, argument_spec=spec.argument_spec,
supports_check_mode=spec.supports_check_mode supports_check_mode=spec.supports_check_mode
) )
if not HAS_F5SDK:
module.fail_json(msg="The python f5-sdk module is required")
try: try:
mm = ModuleManager(module=module) client = F5RestClient(**module.params)
mm = ModuleManager(module=module, client=client)
results = mm.exec_module() results = mm.exec_module()
module.exit_json(**results) exit_json(module, results, client)
except F5ModuleError as e: except F5ModuleError as ex:
module.fail_json(msg=str(e)) fail_json(module, ex, client)
if __name__ == '__main__': if __name__ == '__main__':

View file

@ -56,7 +56,7 @@ options:
- This parameter is required when creating a new application. - This parameter is required when creating a new application.
netmask: netmask:
description: description:
- Specifies the netmask to associate with the given C(destination). - Specifies the netmask to associate with the given C(address).
- This parameter is required when creating a new application. - This parameter is required when creating a new application.
port: port:
description: description:
@ -80,7 +80,7 @@ options:
- This parameter is required when creating a new application. - This parameter is required when creating a new application.
netmask: netmask:
description: description:
- Specifies the netmask to associate with the given C(destination). - Specifies the netmask to associate with the given C(address).
- This parameter is required when creating a new application. - This parameter is required when creating a new application.
port: port:
description: description:
@ -130,8 +130,8 @@ options:
- Passphrases are encrypted on the remote BIG-IP device. - Passphrases are encrypted on the remote BIG-IP device.
service_environment: service_environment:
description: description:
- Specifies the name of service environment or the hostname of the BIG-IP that the application will be - Specifies the name of service environment or the hostname of the BIG-IP that
deployed to. the application will be deployed to.
- When creating a new application, this parameter is required. - When creating a new application, this parameter is required.
add_analytics: add_analytics:
description: description:

View file

@ -20,7 +20,7 @@ from ansible.compat.tests.mock import patch
from ansible.module_utils.basic import AnsibleModule from ansible.module_utils.basic import AnsibleModule
try: try:
from library.modules.bigip_virtual_address import Parameters from library.modules.bigip_virtual_address import ApiParameters
from library.modules.bigip_virtual_address import ModuleParameters from library.modules.bigip_virtual_address import ModuleParameters
from library.modules.bigip_virtual_address import ModuleManager from library.modules.bigip_virtual_address import ModuleManager
from library.modules.bigip_virtual_address import ArgumentSpec from library.modules.bigip_virtual_address import ArgumentSpec
@ -29,7 +29,7 @@ try:
from test.unit.modules.utils import set_module_args from test.unit.modules.utils import set_module_args
except ImportError: except ImportError:
try: try:
from ansible.modules.network.f5.bigip_virtual_address import Parameters from ansible.modules.network.f5.bigip_virtual_address import ApiParameters
from ansible.modules.network.f5.bigip_virtual_address import ModuleParameters from ansible.modules.network.f5.bigip_virtual_address import ModuleParameters
from ansible.modules.network.f5.bigip_virtual_address import ModuleManager from ansible.modules.network.f5.bigip_virtual_address import ModuleManager
from ansible.modules.network.f5.bigip_virtual_address import ArgumentSpec from ansible.modules.network.f5.bigip_virtual_address import ArgumentSpec
@ -79,7 +79,7 @@ class TestParameters(unittest.TestCase):
assert p.address == '1.1.1.1' assert p.address == '1.1.1.1'
assert p.netmask == '2.2.2.2' assert p.netmask == '2.2.2.2'
assert p.connection_limit == 10 assert p.connection_limit == 10
assert p.arp_state == 'enabled' assert p.arp is True
assert p.auto_delete is True assert p.auto_delete is True
assert p.icmp_echo == 'enabled' assert p.icmp_echo == 'enabled'
assert p.availability_calculation == 'none' assert p.availability_calculation == 'none'
@ -87,10 +87,10 @@ class TestParameters(unittest.TestCase):
def test_api_parameters(self): def test_api_parameters(self):
args = load_fixture('load_ltm_virtual_address_default.json') args = load_fixture('load_ltm_virtual_address_default.json')
p = Parameters(params=args) p = ApiParameters(params=args)
assert p.name == '1.1.1.1' assert p.name == '1.1.1.1'
assert p.address == '1.1.1.1' assert p.address == '1.1.1.1'
assert p.arp_state == 'enabled' assert p.arp is True
assert p.auto_delete is True assert p.auto_delete is True
assert p.connection_limit == 0 assert p.connection_limit == 0
assert p.state == 'enabled' assert p.state == 'enabled'
@ -103,42 +103,42 @@ class TestParameters(unittest.TestCase):
args = dict( args = dict(
availability_calculation='when_all_available' availability_calculation='when_all_available'
) )
p = Parameters(params=args) p = ModuleParameters(params=args)
assert p.availability_calculation == 'all' assert p.availability_calculation == 'all'
def test_module_parameters_advertise_route_any(self): def test_module_parameters_advertise_route_any(self):
args = dict( args = dict(
availability_calculation='when_any_available' availability_calculation='when_any_available'
) )
p = Parameters(params=args) p = ModuleParameters(params=args)
assert p.availability_calculation == 'any' assert p.availability_calculation == 'any'
def test_module_parameters_icmp_echo_disabled(self): def test_module_parameters_icmp_echo_disabled(self):
args = dict( args = dict(
icmp_echo='disabled' icmp_echo='disabled'
) )
p = Parameters(params=args) p = ModuleParameters(params=args)
assert p.icmp_echo == 'disabled' assert p.icmp_echo == 'disabled'
def test_module_parameters_icmp_echo_selective(self): def test_module_parameters_icmp_echo_selective(self):
args = dict( args = dict(
icmp_echo='selective' icmp_echo='selective'
) )
p = Parameters(params=args) p = ModuleParameters(params=args)
assert p.icmp_echo == 'selective' assert p.icmp_echo == 'selective'
def test_module_parameters_auto_delete_disabled(self): def test_module_parameters_auto_delete_disabled(self):
args = dict( args = dict(
auto_delete='disabled' auto_delete='disabled'
) )
p = Parameters(params=args) p = ModuleParameters(params=args)
assert p.auto_delete is False assert p.auto_delete is False
def test_module_parameters_arp_state_disabled(self): def test_module_parameters_arp_state_disabled(self):
args = dict( args = dict(
arp_state='disabled' arp_state='disabled'
) )
p = Parameters(params=args) p = ModuleParameters(params=args)
assert p.arp_state == 'disabled' assert p.arp_state == 'disabled'
def test_module_parameters_use_route_advert_disabled(self): def test_module_parameters_use_route_advert_disabled(self):
@ -152,7 +152,7 @@ class TestParameters(unittest.TestCase):
args = dict( args = dict(
state='present' state='present'
) )
p = Parameters(params=args) p = ModuleParameters(params=args)
assert p.state == 'present' assert p.state == 'present'
assert p.enabled == 'yes' assert p.enabled == 'yes'
@ -160,14 +160,14 @@ class TestParameters(unittest.TestCase):
args = dict( args = dict(
state='absent' state='absent'
) )
p = Parameters(params=args) p = ModuleParameters(params=args)
assert p.state == 'absent' assert p.state == 'absent'
def test_module_parameters_state_enabled(self): def test_module_parameters_state_enabled(self):
args = dict( args = dict(
state='enabled' state='enabled'
) )
p = Parameters(params=args) p = ModuleParameters(params=args)
assert p.state == 'enabled' assert p.state == 'enabled'
assert p.enabled == 'yes' assert p.enabled == 'yes'
@ -175,7 +175,7 @@ class TestParameters(unittest.TestCase):
args = dict( args = dict(
state='disabled' state='disabled'
) )
p = Parameters(params=args) p = ModuleParameters(params=args)
assert p.state == 'disabled' assert p.state == 'disabled'
assert p.enabled == 'no' assert p.enabled == 'no'