Merge pull request #10382 from AlanCoding/downstream_waterslide

Handle inventory types where Automation Hub collection names differ

Some collections will be moving, which is #10323
Yet, other collections will change name, which this is intended to address.

Reviewed-by: Alan Rominger <arominge@redhat.com>
Reviewed-by: Sarabraj Singh <singh.sarabraj@gmail.com>
Reviewed-by: Elijah DeLee <kdelee@redhat.com>
This commit is contained in:
softwarefactory-project-zuul[bot]
2021-06-16 18:15:08 +00:00
committed by GitHub
7 changed files with 41 additions and 40 deletions

View File

@@ -39,6 +39,7 @@ from awx.main.models import UnifiedJob, UnifiedJobTemplate, User, Role, Credenti
from awx.main.access import access_registry from awx.main.access import access_registry
from awx.main.utils import camelcase_to_underscore, get_search_fields, getattrd, get_object_or_400, decrypt_field, get_awx_version from awx.main.utils import camelcase_to_underscore, get_search_fields, getattrd, get_object_or_400, decrypt_field, get_awx_version
from awx.main.utils.db import get_all_field_names from awx.main.utils.db import get_all_field_names
from awx.main.utils.licensing import server_product_name
from awx.main.views import ApiErrorView from awx.main.views import ApiErrorView
from awx.api.serializers import ResourceAccessListElementSerializer, CopySerializer, UserSerializer from awx.api.serializers import ResourceAccessListElementSerializer, CopySerializer, UserSerializer
from awx.api.versioning import URLPathVersioning from awx.api.versioning import URLPathVersioning
@@ -184,9 +185,6 @@ class APIView(views.APIView):
""" """
Log warning for 400 requests. Add header with elapsed time. Log warning for 400 requests. Add header with elapsed time.
""" """
from awx.main.utils import get_licenser
from awx.main.utils.licensing import OpenLicense
# #
# If the URL was rewritten, and we get a 404, we should entirely # If the URL was rewritten, and we get a 404, we should entirely
# replace the view in the request context with an ApiErrorView() # replace the view in the request context with an ApiErrorView()
@@ -226,7 +224,7 @@ class APIView(views.APIView):
response = super(APIView, self).finalize_response(request, response, *args, **kwargs) response = super(APIView, self).finalize_response(request, response, *args, **kwargs)
time_started = getattr(self, 'time_started', None) time_started = getattr(self, 'time_started', None)
response['X-API-Product-Version'] = get_awx_version() response['X-API-Product-Version'] = get_awx_version()
response['X-API-Product-Name'] = 'AWX' if isinstance(get_licenser(), OpenLicense) else 'Red Hat Ansible Tower' response['X-API-Product-Name'] = server_product_name()
response['X-API-Node'] = settings.CLUSTER_HOST_ID response['X-API-Node'] = settings.CLUSTER_HOST_ID
if time_started: if time_started:

View File

@@ -30,6 +30,7 @@ from awx.api.versioning import reverse, drf_reverse
from awx.main.constants import PRIVILEGE_ESCALATION_METHODS from awx.main.constants import PRIVILEGE_ESCALATION_METHODS
from awx.main.models import Project, Organization, Instance, InstanceGroup, JobTemplate from awx.main.models import Project, Organization, Instance, InstanceGroup, JobTemplate
from awx.main.utils import set_environ from awx.main.utils import set_environ
from awx.main.utils.licensing import get_licenser
logger = logging.getLogger('awx.api.views.root') logger = logging.getLogger('awx.api.views.root')
@@ -173,8 +174,6 @@ class ApiV2SubscriptionView(APIView):
self.permission_denied(request) # Raises PermissionDenied exception. self.permission_denied(request) # Raises PermissionDenied exception.
def post(self, request): def post(self, request):
from awx.main.utils.common import get_licenser
data = request.data.copy() data = request.data.copy()
if data.get('subscriptions_password') == '$encrypted$': if data.get('subscriptions_password') == '$encrypted$':
data['subscriptions_password'] = settings.SUBSCRIPTIONS_PASSWORD data['subscriptions_password'] = settings.SUBSCRIPTIONS_PASSWORD
@@ -222,7 +221,6 @@ class ApiV2AttachView(APIView):
user = getattr(settings, 'SUBSCRIPTIONS_USERNAME', None) user = getattr(settings, 'SUBSCRIPTIONS_USERNAME', None)
pw = getattr(settings, 'SUBSCRIPTIONS_PASSWORD', None) pw = getattr(settings, 'SUBSCRIPTIONS_PASSWORD', None)
if pool_id and user and pw: if pool_id and user and pw:
from awx.main.utils.common import get_licenser
data = request.data.copy() data = request.data.copy()
try: try:
@@ -264,8 +262,6 @@ class ApiV2ConfigView(APIView):
def get(self, request, format=None): def get(self, request, format=None):
'''Return various sitewide configuration settings''' '''Return various sitewide configuration settings'''
from awx.main.utils.common import get_licenser
license_data = get_licenser().validate() license_data = get_licenser().validate()
if not license_data.get('valid_key', False): if not license_data.get('valid_key', False):
@@ -320,8 +316,6 @@ class ApiV2ConfigView(APIView):
logger.info(smart_text(u"Invalid JSON submitted for license."), extra=dict(actor=request.user.username)) logger.info(smart_text(u"Invalid JSON submitted for license."), extra=dict(actor=request.user.username))
return Response({"error": _("Invalid JSON")}, status=status.HTTP_400_BAD_REQUEST) return Response({"error": _("Invalid JSON")}, status=status.HTTP_400_BAD_REQUEST)
from awx.main.utils.common import get_licenser
license_data = json.loads(data_actual) license_data = json.loads(data_actual)
if 'license_key' in license_data: if 'license_key' in license_data:
return Response({"error": _('Legacy license submitted. A subscription manifest is now required.')}, status=status.HTTP_400_BAD_REQUEST) return Response({"error": _('Legacy license submitted. A subscription manifest is now required.')}, status=status.HTTP_400_BAD_REQUEST)

View File

@@ -51,6 +51,7 @@ from awx.main.models.credential.injectors import _openstack_data
from awx.main.utils import _inventory_updates from awx.main.utils import _inventory_updates
from awx.main.utils.safe_yaml import sanitize_jinja from awx.main.utils.safe_yaml import sanitize_jinja
from awx.main.utils.execution_environments import to_container_path from awx.main.utils.execution_environments import to_container_path
from awx.main.utils.licensing import server_product_name
__all__ = ['Inventory', 'Host', 'Group', 'InventorySource', 'InventoryUpdate', 'SmartInventoryMembership'] __all__ = ['Inventory', 'Host', 'Group', 'InventorySource', 'InventoryUpdate', 'SmartInventoryMembership']
@@ -1336,6 +1337,7 @@ class PluginFileInjector(object):
namespace = None namespace = None
collection = None collection = None
collection_migration = '2.9' # Starting with this version, we use collections collection_migration = '2.9' # Starting with this version, we use collections
use_fqcn = False # plugin: name versus plugin: namespace.collection.name
# TODO: delete this method and update unit tests # TODO: delete this method and update unit tests
@classmethod @classmethod
@@ -1362,7 +1364,12 @@ class PluginFileInjector(object):
Note that a plugin value of '' should still be overridden. Note that a plugin value of '' should still be overridden.
''' '''
if self.plugin_name is not None: if self.plugin_name is not None:
source_vars['plugin'] = self.plugin_name if hasattr(self, 'downstream_namespace') and server_product_name() != 'AWX':
source_vars['plugin'] = f'{self.downstream_namespace}.{self.downstream_collection}.{self.plugin_name}'
elif self.use_fqcn:
source_vars['plugin'] = f'{self.namespace}.{self.collection}.{self.plugin_name}'
else:
source_vars['plugin'] = self.plugin_name
return source_vars return source_vars
def build_env(self, inventory_update, env, private_data_dir, private_data_files): def build_env(self, inventory_update, env, private_data_dir, private_data_files):
@@ -1510,12 +1517,17 @@ class rhv(PluginFileInjector):
initial_version = '2.9' initial_version = '2.9'
namespace = 'ovirt' namespace = 'ovirt'
collection = 'ovirt' collection = 'ovirt'
downstream_namespace = 'redhat'
downstream_collection = 'rhv'
class satellite6(PluginFileInjector): class satellite6(PluginFileInjector):
plugin_name = 'foreman' plugin_name = 'foreman'
namespace = 'theforeman' namespace = 'theforeman'
collection = 'foreman' collection = 'foreman'
downstream_namespace = 'redhat'
downstream_collection = 'satellite'
use_fqcn = True
def get_plugin_env(self, inventory_update, private_data_dir, private_data_files): def get_plugin_env(self, inventory_update, private_data_dir, private_data_files):
# this assumes that this is merged # this assumes that this is merged
@@ -1528,18 +1540,14 @@ class satellite6(PluginFileInjector):
ret['FOREMAN_PASSWORD'] = credential.get_input('password', default='') ret['FOREMAN_PASSWORD'] = credential.get_input('password', default='')
return ret return ret
def inventory_as_dict(self, inventory_update, private_data_dir):
ret = super(satellite6, self).inventory_as_dict(inventory_update, private_data_dir)
# this inventory plugin requires the fully qualified inventory plugin name
ret['plugin'] = f'{self.namespace}.{self.collection}.{self.plugin_name}'
return ret
class tower(PluginFileInjector): class tower(PluginFileInjector):
plugin_name = 'tower' plugin_name = 'tower'
base_injector = 'template' base_injector = 'template'
namespace = 'awx' namespace = 'awx'
collection = 'awx' collection = 'awx'
downstream_namespace = 'ansible'
downstream_collection = 'controller'
class insights(PluginFileInjector): class insights(PluginFileInjector):

View File

@@ -11,3 +11,4 @@ from awx.main.utils.encryption import ( # noqa
decrypt_value, decrypt_value,
encrypt_dict, encrypt_dict,
) )
from awx.main.utils.licensing import get_licenser # noqa

View File

@@ -51,7 +51,6 @@ __all__ = [
'underscore_to_camelcase', 'underscore_to_camelcase',
'memoize', 'memoize',
'memoize_delete', 'memoize_delete',
'get_licenser',
'get_awx_http_client_headers', 'get_awx_http_client_headers',
'get_awx_version', 'get_awx_version',
'update_scm_url', 'update_scm_url',
@@ -255,18 +254,6 @@ def get_awx_http_client_headers():
return headers return headers
def get_licenser(*args, **kwargs):
from awx.main.utils.licensing import Licenser, OpenLicense
try:
if os.path.exists('/var/lib/awx/.tower_version'):
return Licenser(*args, **kwargs)
else:
return OpenLicense()
except Exception as e:
raise ValueError(_('Error importing License: %s') % e)
def update_scm_url(scm_type, url, username=True, password=True, check_special_cases=True, scp_format=False): def update_scm_url(scm_type, url, username=True, password=True, check_special_cases=True, scp_format=False):
""" """
Update the given SCM URL to add/replace/remove the username/password. When Update the given SCM URL to add/replace/remove the username/password. When

View File

@@ -15,6 +15,7 @@ from datetime import datetime, timezone
import collections import collections
import copy import copy
import io import io
import os
import json import json
import logging import logging
import re import re
@@ -34,8 +35,6 @@ from cryptography import x509
from django.conf import settings from django.conf import settings
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
# AWX
from awx.main.models import Host, HostMetric, Instance
MAX_INSTANCES = 9999999 MAX_INSTANCES = 9999999
@@ -379,10 +378,9 @@ class Licenser(object):
return attrs return attrs
attrs['valid_key'] = True attrs['valid_key'] = True
if Host: from awx.main.models import Host, HostMetric, Instance
current_instances = Host.objects.active_count()
else: current_instances = Host.objects.active_count()
current_instances = 0
license_date = int(attrs.get('license_date', 0) or 0) license_date = int(attrs.get('license_date', 0) or 0)
automated_instances = HostMetric.objects.count() automated_instances = HostMetric.objects.count()
first_host = HostMetric.objects.only('first_automation').order_by('first_automation').first() first_host = HostMetric.objects.only('first_automation').order_by('first_automation').first()
@@ -408,3 +406,19 @@ class Licenser(object):
attrs['date_warning'] = bool(time_remaining < self.SUBSCRIPTION_TIMEOUT) attrs['date_warning'] = bool(time_remaining < self.SUBSCRIPTION_TIMEOUT)
attrs['date_expired'] = bool(time_remaining <= 0) attrs['date_expired'] = bool(time_remaining <= 0)
return attrs return attrs
def get_licenser(*args, **kwargs):
from awx.main.utils.licensing import Licenser, OpenLicense
try:
if os.path.exists('/var/lib/awx/.tower_version'):
return Licenser(*args, **kwargs)
else:
return OpenLicense()
except Exception as e:
raise ValueError(_('Error importing License: %s') % e)
def server_product_name():
return 'AWX' if isinstance(get_licenser(), OpenLicense) else 'Red Hat Ansible Automation Platform'

View File

@@ -2,8 +2,7 @@ from django.conf.urls import url
from django.utils.translation import ugettext_lazy as _ from django.utils.translation import ugettext_lazy as _
from django.views.generic.base import TemplateView from django.views.generic.base import TemplateView
from awx.main.utils.common import get_licenser from awx.main.utils.licensing import server_product_name
from awx.main.utils.licensing import OpenLicense
class IndexView(TemplateView): class IndexView(TemplateView):
@@ -17,7 +16,7 @@ class MigrationsNotran(TemplateView):
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs) context = super().get_context_data(**kwargs)
product_name = 'AWX' if isinstance(get_licenser(), OpenLicense) else 'Red Hat Ansible Automation Platform' product_name = server_product_name()
context['title'] = _('%s Upgrading' % product_name) context['title'] = _('%s Upgrading' % product_name)
context['image_alt'] = _('Logo') context['image_alt'] = _('Logo')
context['aria_spinner'] = _('Loading') context['aria_spinner'] = _('Loading')