mirror of
https://github.com/ansible/awx.git
synced 2026-03-19 18:07:33 -02:30
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:
@@ -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:
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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):
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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'
|
||||||
|
|||||||
@@ -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')
|
||||||
|
|||||||
Reference in New Issue
Block a user