mirror of
https://github.com/ansible/awx.git
synced 2026-03-06 11:11:07 -03:30
Allow combining multiple subscriptions if they are in a manifest.
The rules: - subs must be of same SKU type (all MCTxxxx, all SERxxxx, etc) - when combining, we take the earliest end date
This commit is contained in:
@@ -11,7 +11,7 @@ The Licenser class can do the following:
|
|||||||
|
|
||||||
import base64
|
import base64
|
||||||
import configparser
|
import configparser
|
||||||
from datetime import datetime
|
from datetime import datetime, timezone
|
||||||
import collections
|
import collections
|
||||||
import copy
|
import copy
|
||||||
import io
|
import io
|
||||||
@@ -73,9 +73,12 @@ def validate_entitlement_manifest(data):
|
|||||||
|
|
||||||
buff.write(export)
|
buff.write(export)
|
||||||
z = zipfile.ZipFile(buff)
|
z = zipfile.ZipFile(buff)
|
||||||
|
subs = []
|
||||||
for f in z.filelist:
|
for f in z.filelist:
|
||||||
if f.filename.startswith('export/entitlements') and f.filename.endswith('.json'):
|
if f.filename.startswith('export/entitlements') and f.filename.endswith('.json'):
|
||||||
return json.loads(z.open(f).read())
|
subs.append(json.loads(z.open(f).read()))
|
||||||
|
if subs:
|
||||||
|
return subs
|
||||||
raise ValueError(_("Invalid manifest: manifest contains no subscriptions."))
|
raise ValueError(_("Invalid manifest: manifest contains no subscriptions."))
|
||||||
|
|
||||||
|
|
||||||
@@ -131,21 +134,64 @@ class Licenser(object):
|
|||||||
|
|
||||||
|
|
||||||
def license_from_manifest(self, manifest):
|
def license_from_manifest(self, manifest):
|
||||||
|
def is_appropriate_manifest_sub(sub):
|
||||||
|
if sub['pool']['activeSubscription'] is False:
|
||||||
|
return False
|
||||||
|
now = datetime.now(timezone.utc)
|
||||||
|
if parse_date(sub['startDate']) > now:
|
||||||
|
return False
|
||||||
|
if parse_date(sub['endDate']) < now:
|
||||||
|
return False
|
||||||
|
products = sub['pool']['providedProducts']
|
||||||
|
if any(product.get('productId') == '480' for product in products):
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
def _can_aggregate(sub, license):
|
||||||
|
# We aggregate multiple subs into a larger meta-sub, if they match
|
||||||
|
#
|
||||||
|
# No current sub in aggregate
|
||||||
|
if not license:
|
||||||
|
return True
|
||||||
|
# Same SKU type (SER vs MCT vs others)?
|
||||||
|
if license['sku'][0:3] != sub['pool']['productId'][0:3]:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
# Parse output for subscription metadata to build config
|
# Parse output for subscription metadata to build config
|
||||||
license = dict()
|
license = dict()
|
||||||
license['sku'] = manifest['pool']['productId']
|
for sub in manifest:
|
||||||
try:
|
if not is_appropriate_manifest_sub(sub):
|
||||||
license['instance_count'] = manifest['pool']['exported']
|
logger.warning("Subscription %s (%s) in manifest is not active or for another product" %
|
||||||
except KeyError:
|
(sub['pool']['productName'], sub['pool']['productId']))
|
||||||
license['instance_count'] = manifest['pool']['quantity']
|
continue
|
||||||
license['subscription_name'] = manifest['pool']['productName']
|
if not _can_aggregate(sub, license):
|
||||||
license['pool_id'] = manifest['pool']['id']
|
logger.warning("Subscription %s (%s) in manifest does not match other manifest subscriptions" %
|
||||||
license['license_date'] = parse_date(manifest['endDate']).strftime('%s')
|
(sub['pool']['productName'], sub['pool']['productId']))
|
||||||
license['product_name'] = manifest['pool']['productName']
|
continue
|
||||||
license['valid_key'] = True
|
|
||||||
license['license_type'] = 'enterprise'
|
|
||||||
license['satellite'] = False
|
|
||||||
|
|
||||||
|
license.setdefault('sku', sub['pool']['productId'])
|
||||||
|
license.setdefault('subscription_name', sub['pool']['productName'])
|
||||||
|
license.setdefault('pool_id', sub['pool']['id'])
|
||||||
|
license.setdefault('product_name', sub['pool']['productName'])
|
||||||
|
license.setdefault('valid_key', True)
|
||||||
|
license.setdefault('license_type', 'enterprise')
|
||||||
|
license.setdefault('satellite', False)
|
||||||
|
# Use the nearest end date
|
||||||
|
endDate = parse_date(sub['endDate'])
|
||||||
|
currentEndDateStr = license.get('license_date', '4102462800') # 2100-01-01
|
||||||
|
currentEndDate = datetime.fromtimestamp(int(currentEndDateStr), timezone.utc)
|
||||||
|
if endDate < currentEndDate:
|
||||||
|
license['license_date'] = endDate.strftime('%s')
|
||||||
|
try:
|
||||||
|
instances = sub['pool']['exported']
|
||||||
|
except KeyError:
|
||||||
|
instances = sub['pool']['quantity']
|
||||||
|
license['instance_count'] = license.get('instance_count', 0) + instances
|
||||||
|
license['subscription_name'] = re.sub(r'[\d]* Managed Nodes', '%d Managed Nodes' % license['instance_count'], license['subscription_name'])
|
||||||
|
|
||||||
|
if not license:
|
||||||
|
logger.error("No valid subscriptions found in manifest")
|
||||||
self._attrs.update(license)
|
self._attrs.update(license)
|
||||||
settings.LICENSE = self._attrs
|
settings.LICENSE = self._attrs
|
||||||
return self._attrs
|
return self._attrs
|
||||||
@@ -272,7 +318,7 @@ class Licenser(object):
|
|||||||
return False
|
return False
|
||||||
# Products that contain Ansible Tower
|
# Products that contain Ansible Tower
|
||||||
products = sub.get('providedProducts', [])
|
products = sub.get('providedProducts', [])
|
||||||
if any(map(lambda product: product.get('productId', None) == "480", products)):
|
if any(product.get('productId') == '480' for product in products):
|
||||||
return True
|
return True
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user