Adds revoke functionality to device license (#48772)
This commit is contained in:
parent
8b8aca21c1
commit
4f80c45c51
1 changed files with 73 additions and 9 deletions
|
@ -39,10 +39,13 @@ options:
|
|||
- When C(present), only guarantees that a license is there.
|
||||
- When C(latest), ensures that the license is always valid.
|
||||
- When C(absent), removes the license on the system.
|
||||
- When C(revoked), removes the license on the system and revokes its future usage
|
||||
on the F5 license servers.
|
||||
default: present
|
||||
choices:
|
||||
- absent
|
||||
- present
|
||||
- revoked
|
||||
accept_eula:
|
||||
description:
|
||||
- Declares whether you accept the BIG-IP EULA or not. By default, this
|
||||
|
@ -385,6 +388,8 @@ class ModuleManager(object):
|
|||
changed = self.present()
|
||||
elif state == "absent":
|
||||
changed = self.absent()
|
||||
elif state == "revoked":
|
||||
changed = self.revoke()
|
||||
|
||||
reportable = ReportableChanges(params=self.changes.to_return())
|
||||
changes = reportable.to_return()
|
||||
|
@ -402,7 +407,7 @@ class ModuleManager(object):
|
|||
)
|
||||
|
||||
def present(self):
|
||||
if self.exists():
|
||||
if self.exists() and not self.is_revoked():
|
||||
return False
|
||||
else:
|
||||
return self.create()
|
||||
|
@ -415,11 +420,67 @@ class ModuleManager(object):
|
|||
raise F5ModuleError("Failed to delete the resource.")
|
||||
return True
|
||||
|
||||
def revoke(self):
|
||||
if self.is_revoked():
|
||||
return False
|
||||
else:
|
||||
# When revoking a license, it should be acceptable to auto-accept the
|
||||
# license since you accepted it the first time when you activated the
|
||||
# license you are now revoking.
|
||||
self.want.update({'accept_eula': True})
|
||||
|
||||
# Revoking seems to just be another way of saying "get me a new license".
|
||||
# There appear to be revoke-specific wording in the license and I assume
|
||||
# some special revoke-like signing is happening, but the process is essentially
|
||||
# just another form of "create".
|
||||
return self.create()
|
||||
|
||||
def revoke_from_device(self):
|
||||
if self.module.check_mode:
|
||||
return True
|
||||
|
||||
dossier = self.read_dossier_from_device()
|
||||
if dossier:
|
||||
self.want.update({'dossier': dossier})
|
||||
else:
|
||||
raise F5ModuleError("Dossier not generated.")
|
||||
|
||||
if self.is_revoked():
|
||||
return False
|
||||
|
||||
def is_revoked(self):
|
||||
command = '-c "egrep Revoked /config/bigip.license"'
|
||||
params = dict(
|
||||
command='run',
|
||||
utilCmdArgs=command
|
||||
)
|
||||
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:
|
||||
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 and 'Revoked' in response['commandResult']:
|
||||
return True
|
||||
return False
|
||||
|
||||
def read_dossier_from_device(self):
|
||||
params = dict(
|
||||
command='run',
|
||||
utilCmdArgs='-b "{0}"'.format(self.want.license_key)
|
||||
)
|
||||
if self.want.state == 'revoked':
|
||||
params['utilCmdArgs'] = '-r ' + params['utilCmdArgs']
|
||||
|
||||
uri = "https://{0}:{1}/mgmt/tm/util/get-dossier".format(
|
||||
self.client.provider['server'],
|
||||
self.client.provider['server_port']
|
||||
|
@ -436,7 +497,10 @@ class ModuleManager(object):
|
|||
else:
|
||||
raise F5ModuleError(resp.content)
|
||||
try:
|
||||
return response['commandResult']
|
||||
if self.want.state == 'revoked':
|
||||
return response['commandResult'][8:]
|
||||
else:
|
||||
return response['commandResult']
|
||||
except Exception:
|
||||
return None
|
||||
|
||||
|
@ -455,13 +519,13 @@ class ModuleManager(object):
|
|||
self.want.license_url,
|
||||
data=self.want.license_envelope,
|
||||
)
|
||||
except Exception as ex:
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
try:
|
||||
resp = LicenseXmlParser(content=resp._content)
|
||||
resp = LicenseXmlParser(content=resp.content)
|
||||
result = resp.json()
|
||||
except F5ModuleError as ex:
|
||||
except F5ModuleError:
|
||||
# This error occurs when there is a problem with the license server and it
|
||||
# starts returning invalid XML (like if they upgraded something and the server
|
||||
# is redirecting improperly.
|
||||
|
@ -469,7 +533,7 @@ class ModuleManager(object):
|
|||
# There's no way to recover from this error except by notifying F5 that there
|
||||
# is an issue with the license server.
|
||||
raise
|
||||
except Exception as ex:
|
||||
except Exception:
|
||||
continue
|
||||
|
||||
if result['state'] == 'EULA_REQUIRED':
|
||||
|
@ -554,7 +618,7 @@ class ModuleManager(object):
|
|||
nops += 1
|
||||
else:
|
||||
nops = 0
|
||||
except Exception as ex:
|
||||
except Exception:
|
||||
pass
|
||||
time.sleep(5)
|
||||
|
||||
|
@ -583,7 +647,7 @@ class ModuleManager(object):
|
|||
|
||||
if 'commandResult' in response:
|
||||
return True
|
||||
except Exception as ex:
|
||||
except Exception:
|
||||
pass
|
||||
return False
|
||||
|
||||
|
@ -790,7 +854,7 @@ class ArgumentSpec(object):
|
|||
default='activate.f5.com'
|
||||
),
|
||||
state=dict(
|
||||
choices=['absent', 'present'],
|
||||
choices=['absent', 'present', 'revoked'],
|
||||
default='present'
|
||||
),
|
||||
accept_eula=dict(
|
||||
|
|
Loading…
Reference in a new issue