mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-02 14:40:19 -07:00
Fixes and additions for f5 modules (#39986)
Small fixes in the f5 module utils. I believe the action plugins now work consistently across types of connections
This commit is contained in:
parent
8654508cbd
commit
00a6b19e58
6 changed files with 172 additions and 162 deletions
|
@ -80,15 +80,15 @@ class F5RestClient(F5BaseClient):
|
|||
payload = {
|
||||
'username': self.provider['user'],
|
||||
'password': self.provider['password'],
|
||||
'loginProviderName': self.provider['auth_provider']
|
||||
'loginProviderName': self.provider['auth_provider'] or 'tmos'
|
||||
}
|
||||
session = iControlRestSession()
|
||||
session.verify = self.provider['validate_certs']
|
||||
response = session.post(url, json=payload)
|
||||
|
||||
if response.status_code not in [200]:
|
||||
raise F5ModuleError('{0} Unexpected Error: {1} for uri: {2}\nText: {3}'.format(
|
||||
response.status_code, response.reason, response.url, response._content
|
||||
if response.status not in [200]:
|
||||
raise F5ModuleError('Status code: {0}. Unexpected Error: {1} for uri: {2}\nText: {3}'.format(
|
||||
response.status, response.reason, response.url, response._content
|
||||
))
|
||||
|
||||
session.headers['X-F5-Auth-Token'] = response.json()['token']['token']
|
||||
|
@ -98,7 +98,7 @@ class F5RestClient(F5BaseClient):
|
|||
exc = ex
|
||||
time.sleep(1)
|
||||
error = 'Unable to connect to {0} on port {1}.'.format(
|
||||
self.params['server'], self.params['server_port']
|
||||
self.provider['server'], self.provider['server_port']
|
||||
)
|
||||
if exc is not None:
|
||||
error += ' The reported error was "{0}".'.format(str(exc))
|
||||
|
|
|
@ -61,35 +61,43 @@ class F5Client(F5BaseClient):
|
|||
|
||||
|
||||
class F5RestClient(F5BaseClient):
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(F5RestClient, self).__init__(*args, **kwargs)
|
||||
self.provider = self.merge_provider_params()
|
||||
|
||||
@property
|
||||
def api(self):
|
||||
ex = None
|
||||
exc = None
|
||||
if self._client:
|
||||
return self._client
|
||||
for x in range(0, 10):
|
||||
try:
|
||||
server = self.params['provider']['server'] or self.params['server']
|
||||
user = self.params['provider']['user'] or self.params['user']
|
||||
password = self.params['provider']['password'] or self.params['password']
|
||||
server_port = self.params['provider']['server_port'] or self.params['server_port'] or 443
|
||||
validate_certs = self.params['provider']['validate_certs'] or self.params['validate_certs']
|
||||
|
||||
# Should we import from module??
|
||||
# self.module.params['server'],
|
||||
result = iControlRestSession(
|
||||
server,
|
||||
user,
|
||||
password,
|
||||
port=server_port,
|
||||
verify=validate_certs,
|
||||
auth_provider='local',
|
||||
debug=is_ansible_debug(self.module)
|
||||
url = "https://{0}:{1}/mgmt/shared/authn/login".format(
|
||||
self.provider['server'], self.provider['server_port']
|
||||
)
|
||||
self._client = result
|
||||
payload = {
|
||||
'username': self.provider['user'],
|
||||
'password': self.provider['password'],
|
||||
'loginProviderName': self.provider['auth_provider'] or 'local'
|
||||
}
|
||||
session = iControlRestSession()
|
||||
session.verify = self.provider['validate_certs']
|
||||
response = session.post(url, json=payload)
|
||||
|
||||
if response.status not in [200]:
|
||||
raise F5ModuleError('Status code: {0}. Unexpected Error: {1} for uri: {2}\nText: {3}'.format(
|
||||
response.status, response.reason, response.url, response._content
|
||||
))
|
||||
|
||||
session.headers['X-F5-Auth-Token'] = response.json()['token']['token']
|
||||
self._client = session
|
||||
return self._client
|
||||
except Exception as ex:
|
||||
exc = ex
|
||||
time.sleep(1)
|
||||
error = 'Unable to connect to {0} on port {1}.'.format(self.params['server'], self.params['server_port'])
|
||||
if ex is not None:
|
||||
error += ' The reported error was "{0}".'.format(str(ex))
|
||||
error = 'Unable to connect to {0} on port {1}.'.format(
|
||||
self.provider['server'], self.provider['server_port']
|
||||
)
|
||||
if exc is not None:
|
||||
error += ' The reported error was "{0}".'.format(str(exc))
|
||||
raise F5ModuleError(error)
|
||||
|
|
|
@ -295,8 +295,6 @@ def compare_dictionary(want, have):
|
|||
|
||||
Returns:
|
||||
bool:
|
||||
:param have:
|
||||
:return:
|
||||
"""
|
||||
if want == [] and have is None:
|
||||
return None
|
||||
|
@ -328,6 +326,26 @@ def exit_json(module, results, client=None):
|
|||
module.exit_json(**results)
|
||||
|
||||
|
||||
def is_uuid(uuid=None):
|
||||
"""Check to see if value is an F5 UUID
|
||||
|
||||
UUIDs are used in BIG-IQ and in select areas of BIG-IP (notably ASM). This method
|
||||
will check to see if the provided value matches a UUID as known by these products.
|
||||
|
||||
Args:
|
||||
uuid (string): The value to check for UUID-ness
|
||||
|
||||
Returns:
|
||||
bool:
|
||||
"""
|
||||
if uuid is None:
|
||||
return False
|
||||
pattern = r'[A-Za-z0-9]{8}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{4}-[A-Za-z0-9]{12}'
|
||||
if re.match(pattern, uuid):
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
class Noop(object):
|
||||
"""Represent no-operation required
|
||||
|
||||
|
@ -405,7 +423,7 @@ class F5BaseClient(object):
|
|||
elif self.params.get('auth_provider', None):
|
||||
result['auth_provider'] = self.params.get('auth_provider', None)
|
||||
else:
|
||||
result['auth_provider'] = 'tmos'
|
||||
result['auth_provider'] = None
|
||||
|
||||
if provider.get('user', None):
|
||||
result['user'] = provider.get('user', None)
|
||||
|
|
|
@ -35,8 +35,8 @@ Use this module to make calls to an F5 REST server. It is influenced by the same
|
|||
API that the Python ``requests`` tool uses, but the two are not the same, as the
|
||||
library here is **much** more simple and targeted specifically to F5's needs.
|
||||
|
||||
The ``requests`` design was chosen due to familiarity with the tool. Internals though
|
||||
use Ansible native libraries.
|
||||
The ``requests`` design was chosen due to familiarity with the tool. Internally,
|
||||
the classes contained herein use Ansible native libraries.
|
||||
|
||||
The means by which you should use it are similar to ``requests`` basic usage.
|
||||
|
||||
|
@ -159,7 +159,7 @@ class PreparedRequest(object):
|
|||
class Response(object):
|
||||
def __init__(self):
|
||||
self._content = None
|
||||
self.status_code = None
|
||||
self.status = None
|
||||
self.headers = dict()
|
||||
self.url = None
|
||||
self.reason = None
|
||||
|
@ -187,9 +187,14 @@ class iControlRestSession(object):
|
|||
self.headers = self.default_headers()
|
||||
self.verify = True
|
||||
self.params = {}
|
||||
self.auth = None
|
||||
self.timeout = 30
|
||||
|
||||
self.server = None
|
||||
self.user = None
|
||||
self.password = None
|
||||
self.server_port = None
|
||||
self.auth_provider = None
|
||||
|
||||
def _normalize_headers(self, headers):
|
||||
result = {}
|
||||
result.update(dict((k.lower(), v) for k, v in headers))
|
||||
|
@ -259,12 +264,13 @@ class iControlRestSession(object):
|
|||
method=request.method,
|
||||
data=request.body,
|
||||
timeout=kwargs.get('timeout', None) or self.timeout,
|
||||
validate_certs=kwargs.get('verify', None) or self.verify,
|
||||
headers=request.headers
|
||||
)
|
||||
|
||||
try:
|
||||
result = open_url(request.url, **params)
|
||||
response._content = result.read()
|
||||
response._content = result.read().decode('utf-8')
|
||||
response.status = result.getcode()
|
||||
response.url = result.geturl()
|
||||
response.msg = "OK (%s bytes)" % result.headers.get('Content-Length', 'unknown')
|
||||
|
@ -280,79 +286,19 @@ class iControlRestSession(object):
|
|||
response.status_code = e.code
|
||||
return response
|
||||
|
||||
def delete(self, url, **kwargs):
|
||||
"""Sends a HTTP DELETE command to an F5 REST Server.
|
||||
|
||||
Use this method to send a DELETE command to an F5 product.
|
||||
|
||||
Args:
|
||||
url (string): URL to call.
|
||||
data (bytes): An object specifying additional data to send to the server,
|
||||
or ``None`` if no such data is needed. Currently HTTP requests are the
|
||||
only ones that use data. The supported object types include bytes,
|
||||
file-like objects, and iterables.
|
||||
See https://docs.python.org/3/library/urllib.request.html#urllib.request.Request
|
||||
\\*\\*kwargs (dict): Optional arguments to send to the request.
|
||||
"""
|
||||
return self.request('DELETE', url, **kwargs)
|
||||
def delete(self, url, json=None, **kwargs):
|
||||
return self.request('DELETE', url, json=json, **kwargs)
|
||||
|
||||
def get(self, url, **kwargs):
|
||||
"""Sends a HTTP GET command to an F5 REST Server.
|
||||
|
||||
Use this method to send a GET command to an F5 product.
|
||||
|
||||
Args:
|
||||
url (string): URL to call.
|
||||
\\*\\*kwargs (dict): Optional arguments to send to the request.
|
||||
"""
|
||||
return self.request('GET', url, **kwargs)
|
||||
|
||||
def patch(self, url, data=None, **kwargs):
|
||||
"""Sends a HTTP PATCH command to an F5 REST Server.
|
||||
|
||||
Use this method to send a PATCH command to an F5 product.
|
||||
|
||||
Args:
|
||||
url (string): URL to call.
|
||||
data (bytes): An object specifying additional data to send to the server,
|
||||
or ``None`` if no such data is needed. Currently HTTP requests are the
|
||||
only ones that use data. The supported object types include bytes,
|
||||
file-like objects, and iterables.
|
||||
See https://docs.python.org/3/library/urllib.request.html#urllib.request.Request
|
||||
\\*\\*kwargs (dict): Optional arguments to send to the request.
|
||||
"""
|
||||
return self.request('PATCH', url, data=data, **kwargs)
|
||||
|
||||
def post(self, url, data=None, json=None, **kwargs):
|
||||
"""Sends a HTTP POST command to an F5 REST Server.
|
||||
|
||||
Use this method to send a POST command to an F5 product.
|
||||
|
||||
Args:
|
||||
url (string): URL to call.
|
||||
data (dict): An object specifying additional data to send to the server,
|
||||
or ``None`` if no such data is needed. Currently HTTP requests are the
|
||||
only ones that use data. The supported object types include bytes,
|
||||
file-like objects, and iterables.
|
||||
See https://docs.python.org/3/library/urllib.request.html#urllib.request.Request
|
||||
\\*\\*kwargs (dict): Optional arguments to the request.
|
||||
"""
|
||||
return self.request('POST', url, data=data, json=json, **kwargs)
|
||||
|
||||
def put(self, url, data=None, **kwargs):
|
||||
"""Sends a HTTP PUT command to an F5 REST Server.
|
||||
|
||||
Use this method to send a PUT command to an F5 product.
|
||||
|
||||
Args:
|
||||
url (string): URL to call.
|
||||
data (bytes): An object specifying additional data to send to the server,
|
||||
or ``None`` if no such data is needed. Currently HTTP requests are the
|
||||
only ones that use data. The supported object types include bytes,
|
||||
file-like objects, and iterables.
|
||||
See https://docs.python.org/3/library/urllib.request.html#urllib.request.Request
|
||||
\\*\\*kwargs (dict): Optional arguments to the request.
|
||||
"""
|
||||
return self.request('PUT', url, data=data, **kwargs)
|
||||
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue