From 96a6011b3f93c9ca8cdf44e016cab5f2e4d02f1c Mon Sep 17 00:00:00 2001 From: Tim Rupp Date: Mon, 13 Aug 2018 15:14:23 -0700 Subject: [PATCH] Update f5 module_utils from downstream (#44092) Upstreaming fixes and features for f5 module_utils as part of 2.7 dev cycle --- lib/ansible/module_utils/network/f5/common.py | 87 ++++++++++--------- .../module_utils/network/f5/icontrol.py | 39 ++++++++- .../module_utils/network/f5/ipaddress.py | 22 ++++- 3 files changed, 105 insertions(+), 43 deletions(-) diff --git a/lib/ansible/module_utils/network/f5/common.py b/lib/ansible/module_utils/network/f5/common.py index 7320d592533..ad0ffbdeff0 100644 --- a/lib/ansible/module_utils/network/f5/common.py +++ b/lib/ansible/module_utils/network/f5/common.py @@ -448,62 +448,71 @@ class F5BaseClient(object): """ self._client = None + @staticmethod + def validate_params(key, store): + if key in store and store[key] is not None: + return True + else: + return False + def merge_provider_params(self): result = dict() provider = self.params.get('provider', {}) - if provider.get('server', None): - result['server'] = provider.get('server', None) - elif self.params.get('server', None): - result['server'] = self.params.get('server', None) - elif os.environ.get('F5_SERVER', None): - result['server'] = os.environ.get('F5_SERVER', None) - - if provider.get('server_port', None): - result['server_port'] = provider.get('server_port', None) - elif self.params.get('server_port', None): - result['server_port'] = self.params.get('server_port', None) - elif os.environ.get('F5_SERVER_PORT', None): - result['server_port'] = os.environ.get('F5_SERVER_PORT', None) + if self.validate_params('server', provider): + result['server'] = provider['server'] + elif self.validate_params('server', self.params): + result['server'] = self.params['server'] + elif self.validate_params('F5_SERVER', os.environ): + result['server'] = os.environ['F5_SERVER'] + else: + raise F5ModuleError('Server parameter cannot be None or missing, please provide a valid value') + + if self.validate_params('server_port', provider): + result['server_port'] = provider['server_port'] + elif self.validate_params('server_port', self.params): + result['server_port'] = self.params['server_port'] + elif self.validate_params('F5_SERVER_PORT', os.environ): + result['server_port'] = os.environ['F5_SERVER_PORT'] else: result['server_port'] = 443 - if provider.get('validate_certs', None) is not None: - result['validate_certs'] = provider.get('validate_certs', None) - elif self.params.get('validate_certs', None) is not None: - result['validate_certs'] = self.params.get('validate_certs', None) - elif os.environ.get('F5_VALIDATE_CERTS', None) is not None: - result['validate_certs'] = os.environ.get('F5_VALIDATE_CERTS', None) + if self.validate_params('validate_certs', provider): + result['validate_certs'] = provider['validate_certs'] + elif self.validate_params('validate_certs', self.params): + result['validate_certs'] = self.params['validate_certs'] + elif self.validate_params('F5_VALIDATE_CERTS', os.environ): + result['validate_certs'] = os.environ['F5_VALIDATE_CERTS'] else: result['validate_certs'] = True - if provider.get('auth_provider', None): - result['auth_provider'] = provider.get('auth_provider', None) - elif self.params.get('auth_provider', None): - result['auth_provider'] = self.params.get('auth_provider', None) + if self.validate_params('auth_provider', provider): + result['auth_provider'] = provider['auth_provider'] + elif self.validate_params('auth_provider', self.params): + result['auth_provider'] = self.params['auth_provider'] else: result['auth_provider'] = None - if provider.get('user', None): - result['user'] = provider.get('user', None) - elif self.params.get('user', None): - result['user'] = self.params.get('user', None) - elif os.environ.get('F5_USER', None): - result['user'] = os.environ.get('F5_USER', None) - elif os.environ.get('ANSIBLE_NET_USERNAME', None): - result['user'] = os.environ.get('ANSIBLE_NET_USERNAME', None) + if self.validate_params('user', provider): + result['user'] = provider['user'] + elif self.validate_params('user', self.params): + result['user'] = self.params['user'] + elif self.validate_params('F5_USER', os.environ): + result['user'] = os.environ.get('F5_USER') + elif self.validate_params('ANSIBLE_NET_USERNAME', os.environ): + result['user'] = os.environ.get('ANSIBLE_NET_USERNAME') else: result['user'] = None - if provider.get('password', None): - result['password'] = provider.get('password', None) - elif self.params.get('user', None): - result['password'] = self.params.get('password', None) - elif os.environ.get('F5_PASSWORD', None): - result['password'] = os.environ.get('F5_PASSWORD', None) - elif os.environ.get('ANSIBLE_NET_PASSWORD', None): - result['password'] = os.environ.get('ANSIBLE_NET_PASSWORD', None) + if self.validate_params('password', provider): + result['password'] = provider['password'] + elif self.validate_params('password', self.params): + result['password'] = self.params['password'] + elif self.validate_params('F5_PASSWORD', os.environ): + result['password'] = os.environ.get('F5_PASSWORD') + elif self.validate_params('ANSIBLE_NET_PASSWORD', os.environ): + result['password'] = os.environ.get('ANSIBLE_NET_PASSWORD') else: result['password'] = None diff --git a/lib/ansible/module_utils/network/f5/icontrol.py b/lib/ansible/module_utils/network/f5/icontrol.py index f40bfd60d96..0b942ca87d8 100644 --- a/lib/ansible/module_utils/network/f5/icontrol.py +++ b/lib/ansible/module_utils/network/f5/icontrol.py @@ -19,7 +19,10 @@ from ansible.module_utils.urls import urllib_error from ansible.module_utils._text import to_native from ansible.module_utils.six import PY3 -import json as _json +try: + import json as _json +except ImportError: + import simplejson as _json try: from library.module_utils.network.f5.common import F5ModuleError @@ -174,6 +177,18 @@ class Response(object): def json(self): return _json.loads(self._content) + @property + def ok(self): + if self.status is not None and int(self.status) > 400: + return False + try: + response = self.json() + if 'code' in response and response['code'] > 400: + return False + except ValueError: + pass + return True + class iControlRestSession(object): """Represents a session that communicates with a BigIP. @@ -385,11 +400,33 @@ def download_file(client, url, dest): def upload_file(client, url, dest): """Upload a file to an arbitrary URL. + This method is responsible for correctly chunking an upload request to an + arbitrary file worker URL. + Arguments: client (object): The F5RestClient connection object. url (string): The URL to upload a file to. dest (string): The file to be uploaded. + Examples: + The ``dest`` may be either an absolute or relative path. The basename + of the path is used as the remote file name upon upload. For instance, + in the example below, ``BIGIP-13.1.0.8-0.0.3.iso`` would be the name + of the remote file. + + The specified URL should be the full URL to where you want to upload a + file. BIG-IP has many different URLs that can be used to handle different + types of files. This is why a full URL is required. + + >>> from ansible.module_utils.network.f5.icontrol import upload_client + >>> url = 'https://{0}:{1}/mgmt/cm/autodeploy/software-image-uploads'.format( + ... self.client.provider['server'], + ... self.client.provider['server_port'] + ... ) + >>> dest = '/path/to/BIGIP-13.1.0.8-0.0.3.iso' + >>> upload_file(self.client, url, dest) + True + Returns: bool: True on success. False otherwise. diff --git a/lib/ansible/module_utils/network/f5/ipaddress.py b/lib/ansible/module_utils/network/f5/ipaddress.py index 77144739229..389f4e3df78 100644 --- a/lib/ansible/module_utils/network/f5/ipaddress.py +++ b/lib/ansible/module_utils/network/f5/ipaddress.py @@ -7,7 +7,23 @@ from __future__ import absolute_import, division, print_function __metaclass__ = type from ansible.module_utils.network.common.utils import validate_ip_address -from ansible.module_utils.network.common.utils import validate_ip_v6_address + +try: + # Ansible 2.6 and later + from ansible.module_utils.network.common.utils import validate_ip_v6_address +except ImportError: + import socket + + # Ansible 2.5 and earlier + # + # This method is simply backported from the 2.6 source code. + def validate_ip_v6_address(address): + try: + socket.inet_pton(socket.AF_INET6, address) + except socket.error: + return False + return True + try: from library.module_utils.compat.ipaddress import ip_interface @@ -63,7 +79,7 @@ def ipv6_netmask_to_cidr(mask): def is_valid_ip_network(address): try: - ip_network(address) + ip_network(u'{0}'.format(address)) return True except ValueError: return False @@ -71,7 +87,7 @@ def is_valid_ip_network(address): def is_valid_ip_interface(address): try: - ip_interface(address) + ip_interface(u'{0}'.format(address)) return True except ValueError: return False