Adds refactors for more f5 modules (#34824)

The main patch is to remove the traceback generating code. There are
other small fixes that were made in addition to doing that.

* Removed re-def of cleanup_tokens.
* Changed parameter args to be keywords.
* Changed imports to include new module_util locations.
* Imports also include developing (sideband) module_util locations.
* Changed to using F5Client and plain AnsibleModule to prevent tracebacks caused by missing libraries.
* Removed init and update methods from most Parameter classes (optimization) as its now included in module_utils.
* Changed module and module param references to take into account the new self.module arg.
* Minor bug fixes made during this refactor.
This commit is contained in:
Tim Rupp
2018-01-12 21:49:12 -08:00
committed by GitHub
parent 0e4e7de000
commit a10aee0fc3
28 changed files with 1327 additions and 1593 deletions

View File

@@ -37,12 +37,7 @@ options:
- daily
- monthly
- weekly
notes:
- Requires the f5-sdk Python package on the host This is as easy as
C(pip install f5-sdk)
extends_documentation_fragment: f5
requirements:
- f5-sdk >= 3.0.6
author:
- Tim Rupp (@caphrim007)
'''
@@ -86,17 +81,37 @@ frequency:
sample: weekly
'''
from ansible.module_utils.f5_utils import AnsibleF5Client
from ansible.module_utils.f5_utils import AnsibleF5Parameters
from ansible.module_utils.f5_utils import HAS_F5SDK
from ansible.module_utils.f5_utils import F5ModuleError
from ansible.module_utils.six import iteritems
from collections import defaultdict
from ansible.module_utils.basic import AnsibleModule
HAS_DEVEL_IMPORTS = False
try:
from ansible.module_utils.f5_utils import iControlUnexpectedHTTPError
# Sideband repository used for dev
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.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 fqdn_name
from library.module_utils.network.f5.common import f5_argument_spec
try:
from library.module_utils.network.f5.common import iControlUnexpectedHTTPError
except ImportError:
HAS_F5SDK = False
HAS_DEVEL_IMPORTS = True
except ImportError:
HAS_F5SDK = False
# Upstream Ansible
from ansible.module_utils.network.f5.bigip import HAS_F5SDK
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 AnsibleF5Parameters
from ansible.module_utils.network.f5.common import cleanup_tokens
from ansible.module_utils.network.f5.common import fqdn_name
from ansible.module_utils.network.f5.common import f5_argument_spec
try:
from ansible.module_utils.network.f5.common import iControlUnexpectedHTTPError
except ImportError:
HAS_F5SDK = False
class Parameters(AnsibleF5Parameters):
@@ -117,46 +132,6 @@ class Parameters(AnsibleF5Parameters):
'auto_check', 'auto_phone_home', 'frequency'
]
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 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
class ApiParameters(Parameters):
@property
@@ -241,10 +216,11 @@ class Difference(object):
class ModuleManager(object):
def __init__(self, client):
self.client = client
def __init__(self, *args, **kwargs):
self.module = kwargs.get('module', None)
self.client = kwargs.get('client', None)
self.have = None
self.want = ModuleParameters(self.client.module.params)
self.want = ModuleParameters(params=self.module.params)
self.changes = UsableChanges()
def exec_module(self):
@@ -255,7 +231,7 @@ class ModuleManager(object):
except iControlUnexpectedHTTPError as e:
raise F5ModuleError(str(e))
reportable = ReportableChanges(self.changes.to_return())
reportable = ReportableChanges(params=self.changes.to_return())
changes = reportable.to_return()
result.update(**changes)
result.update(dict(changed=changed))
@@ -265,7 +241,7 @@ class ModuleManager(object):
def _announce_deprecations(self, result):
warnings = result.pop('__warnings', [])
for warning in warnings:
self.client.module.deprecate(
self.module.deprecate(
msg=warning['msg'],
version=warning['version']
)
@@ -284,7 +260,7 @@ class ModuleManager(object):
else:
changed[k] = change
if changed:
self.changes = UsableChanges(changed)
self.changes = UsableChanges(params=changed)
return True
return False
@@ -298,7 +274,7 @@ class ModuleManager(object):
self.have = self.read_current_from_device()
if not self.should_update():
return False
if self.client.check_mode:
if self.module.check_mode:
return True
self.update_on_device()
return True
@@ -311,13 +287,13 @@ class ModuleManager(object):
def read_current_from_device(self):
resource = self.client.api.tm.sys.software.update.load()
result = resource.attrs
return ApiParameters(result)
return ApiParameters(params=result)
class ArgumentSpec(object):
def __init__(self):
self.supports_check_mode = True
self.argument_spec = dict(
argument_spec = dict(
auto_check=dict(
type='bool'
),
@@ -328,39 +304,30 @@ class ArgumentSpec(object):
choices=['daily', 'monthly', 'weekly']
)
)
self.f5_product_name = 'bigip'
def cleanup_tokens(client):
try:
resource = client.api.shared.authz.tokens_s.token.load(
name=client.api.icrs.token
)
resource.delete()
except Exception:
pass
self.argument_spec = {}
self.argument_spec.update(f5_argument_spec)
self.argument_spec.update(argument_spec)
def main():
if not HAS_F5SDK:
raise F5ModuleError("The python f5-sdk module is required")
spec = ArgumentSpec()
client = AnsibleF5Client(
module = AnsibleModule(
argument_spec=spec.argument_spec,
supports_check_mode=spec.supports_check_mode,
f5_product_name=spec.f5_product_name
supports_check_mode=spec.supports_check_mode
)
if not HAS_F5SDK:
module.fail_json(msg="The python f5-sdk module is required")
try:
mm = ModuleManager(client)
client = F5Client(**module.params)
mm = ModuleManager(module=module, client=client)
results = mm.exec_module()
cleanup_tokens(client)
client.module.exit_json(**results)
except F5ModuleError as e:
module.exit_json(**results)
except F5ModuleError as ex:
cleanup_tokens(client)
client.module.fail_json(msg=str(e))
module.fail_json(msg=str(ex))
if __name__ == '__main__':