mirror of
https://github.com/ansible/awx.git
synced 2026-01-19 13:41:28 -03:30
Switch out existing obfuscated license with external module
This creates a new fallback license module called StubLicense that will be used in the event that the tower_license module is not installed. All existing license mechanisms are routed through the get_licenser() util method
This commit is contained in:
parent
7fda3c0658
commit
8486944eaa
3
Makefile
3
Makefile
@ -971,6 +971,9 @@ docker-compose-test: docker-auth
|
||||
docker-compose-build: tower-devel-build tower-isolated-build
|
||||
|
||||
tower-devel-build:
|
||||
rm -rf tools/docker-compose/tower-license
|
||||
git clone git@github.com:ansible/tower-license.git tools/docker-compose/tower-license
|
||||
cd tools/docker-compose/tower-license && $(PYTHON) setup.py sdist
|
||||
docker build -t ansible/tower_devel -f tools/docker-compose/Dockerfile .
|
||||
docker tag ansible/tower_devel gcr.io/ansible-tower-engineering/tower_devel:$(COMPOSE_TAG)
|
||||
#docker push gcr.io/ansible-tower-engineering/tower_devel:$(COMPOSE_TAG)
|
||||
|
||||
@ -324,9 +324,9 @@ class ApiV1ConfigView(APIView):
|
||||
extra=dict(actor=request.user.username))
|
||||
return Response({"error": _("Invalid JSON")}, status=status.HTTP_400_BAD_REQUEST)
|
||||
try:
|
||||
from awx.main.task_engine import TaskEnhancer
|
||||
from awx.main.utils.common import get_licenser
|
||||
license_data = json.loads(data_actual)
|
||||
license_data_validated = TaskEnhancer(**license_data).validate_enhancements()
|
||||
license_data_validated = get_licenser(**license_data).validate()
|
||||
except Exception:
|
||||
logger.warning(smart_text(u"Invalid license submitted."),
|
||||
extra=dict(actor=request.user.username))
|
||||
|
||||
@ -8,7 +8,7 @@ from django.utils.translation import ugettext_lazy as _
|
||||
from rest_framework.exceptions import APIException
|
||||
|
||||
# Tower
|
||||
from awx.main.task_engine import TaskEnhancer
|
||||
from awx.main.utils.common import get_licenser
|
||||
|
||||
__all__ = ['LicenseForbids', 'get_license', 'get_licensed_features',
|
||||
'feature_enabled', 'feature_exists']
|
||||
@ -20,7 +20,7 @@ class LicenseForbids(APIException):
|
||||
|
||||
|
||||
def _get_validated_license_data():
|
||||
return TaskEnhancer().validate_enhancements()
|
||||
return get_licenser().validate()
|
||||
|
||||
|
||||
def get_license(show_key=False):
|
||||
@ -42,7 +42,10 @@ def get_licensed_features():
|
||||
|
||||
def feature_enabled(name):
|
||||
"""Return True if the requested feature is enabled, False otherwise."""
|
||||
return _get_validated_license_data().get('features', {}).get(name, False)
|
||||
validated_license_data = _get_validated_license_data()
|
||||
if validated_license_data['license_type'] == 'open':
|
||||
return True
|
||||
return validated_license_data.get('features', {}).get(name, False)
|
||||
|
||||
|
||||
def feature_exists(name):
|
||||
|
||||
@ -21,8 +21,6 @@ from awx.main.utils import * # noqa
|
||||
from awx.main.models import * # noqa
|
||||
from awx.main.models.unified_jobs import ACTIVE_STATES
|
||||
from awx.main.models.mixins import ResourceMixin
|
||||
from awx.main.task_engine import TaskEnhancer
|
||||
from awx.conf.license import LicenseForbids
|
||||
|
||||
__all__ = ['get_user_queryset', 'check_user_access', 'check_user_access_with_errors',
|
||||
'user_accessible_objects', 'consumer_access',
|
||||
@ -255,7 +253,10 @@ class BaseAccess(object):
|
||||
return True # User has access to both, permission check passed
|
||||
|
||||
def check_license(self, add_host_name=None, feature=None, check_expiration=True):
|
||||
validation_info = TaskEnhancer().validate_enhancements()
|
||||
validation_info = get_licenser().validate()
|
||||
if validation_info['license_type'] == 'open':
|
||||
return
|
||||
|
||||
if ('test' in sys.argv or 'py.test' in sys.argv[0] or 'jenkins' in sys.argv) and not os.environ.get('SKIP_LICENSE_FIXUP_FOR_TEST', ''):
|
||||
validation_info['free_instances'] = 99999999
|
||||
validation_info['time_remaining'] = 99999999
|
||||
|
||||
@ -22,12 +22,12 @@ from django.utils.encoding import smart_text
|
||||
|
||||
# AWX
|
||||
from awx.main.models import * # noqa
|
||||
from awx.main.task_engine import TaskEnhancer
|
||||
from awx.main.utils import (
|
||||
ignore_inventory_computed_fields,
|
||||
check_proot_installed,
|
||||
wrap_args_with_proot,
|
||||
build_proot_temp_dir
|
||||
build_proot_temp_dir,
|
||||
get_licenser
|
||||
)
|
||||
from awx.main.utils.mem_inventory import MemInventory, dict_to_mem_data
|
||||
from awx.main.signals import disable_activity_stream
|
||||
@ -845,10 +845,12 @@ class Command(NoArgsCommand):
|
||||
self._create_update_group_hosts()
|
||||
|
||||
def check_license(self):
|
||||
license_info = TaskEnhancer().validate_enhancements()
|
||||
license_info = get_licenser().validate()
|
||||
if license_info.get('license_key', 'UNLICENSED') == 'UNLICENSED':
|
||||
logger.error(LICENSE_NON_EXISTANT_MESSAGE)
|
||||
raise CommandError('No license found!')
|
||||
elif license_info['license_type'] == 'open':
|
||||
return
|
||||
available_instances = license_info.get('available_instances', 0)
|
||||
free_instances = license_info.get('free_instances', 0)
|
||||
time_remaining = license_info.get('time_remaining', 0)
|
||||
|
||||
@ -47,10 +47,9 @@ from awx.main.constants import CLOUD_PROVIDERS
|
||||
from awx.main.models import * # noqa
|
||||
from awx.main.models.unified_jobs import ACTIVE_STATES
|
||||
from awx.main.queue import CallbackQueueDispatcher
|
||||
from awx.main.task_engine import TaskEnhancer
|
||||
from awx.main.isolated import run, isolated_manager
|
||||
from awx.main.utils import (get_ansible_version, get_ssh_version, decrypt_field, update_scm_url,
|
||||
check_proot_installed, build_proot_temp_dir,
|
||||
check_proot_installed, build_proot_temp_dir, get_licenser,
|
||||
wrap_args_with_proot, get_system_task_capacity, OutputEventFilter,
|
||||
parse_yaml_or_json, ignore_inventory_computed_fields, ignore_inventory_group_removal)
|
||||
from awx.main.utils.reload import restart_local_services, stop_local_services
|
||||
@ -140,8 +139,8 @@ def run_administrative_checks(self):
|
||||
logger.warn("Running administrative checks.")
|
||||
if not settings.TOWER_ADMIN_ALERTS:
|
||||
return
|
||||
validation_info = TaskEnhancer().validate_enhancements()
|
||||
if validation_info.get('instance_count', 0) < 1:
|
||||
validation_info = get_licenser().validate()
|
||||
if validation_info['license_type'] != 'open' and validation_info.get('instance_count', 0) < 1:
|
||||
return
|
||||
used_percentage = float(validation_info.get('current_instances', 0)) / float(validation_info.get('instance_count', 100))
|
||||
tower_admin_emails = User.objects.filter(is_superuser=True).values_list('email', flat=True)
|
||||
|
||||
@ -29,11 +29,12 @@ from django.utils.encoding import force_text
|
||||
|
||||
# AWX
|
||||
from awx.main.models import * # noqa
|
||||
from awx.main.task_engine import TaskEnhancer
|
||||
from awx.main.utils import get_ansible_version
|
||||
from awx.sso.backends import LDAPSettings
|
||||
from awx.main.tests.URI import URI # noqa
|
||||
|
||||
from tower_license import TowerLicense
|
||||
|
||||
TEST_PLAYBOOK = '''- hosts: mygroup
|
||||
gather_facts: false
|
||||
tasks:
|
||||
@ -179,7 +180,7 @@ class BaseTestMixin(MockCommonlySlowTestMixin):
|
||||
return __name__ + '-generated-' + string + rnd_str
|
||||
|
||||
def create_test_license_file(self, instance_count=10000, license_date=int(time.time() + 3600), features={}):
|
||||
settings.LICENSE = TaskEnhancer(
|
||||
settings.LICENSE = TowerLicense(
|
||||
company_name='AWX',
|
||||
contact_name='AWX Admin',
|
||||
contact_email='awx@example.com',
|
||||
@ -187,17 +188,17 @@ class BaseTestMixin(MockCommonlySlowTestMixin):
|
||||
instance_count=instance_count,
|
||||
license_type='enterprise',
|
||||
features=features,
|
||||
).enhance()
|
||||
).generate()
|
||||
|
||||
def create_basic_license_file(self, instance_count=100, license_date=int(time.time() + 3600)):
|
||||
settings.LICENSE = TaskEnhancer(
|
||||
settings.LICENSE = TowerLicense(
|
||||
company_name='AWX',
|
||||
contact_name='AWX Admin',
|
||||
contact_email='awx@example.com',
|
||||
license_date=license_date,
|
||||
instance_count=instance_count,
|
||||
license_type='basic',
|
||||
).enhance()
|
||||
).generate()
|
||||
|
||||
def create_expired_license_file(self, instance_count=1000, grace_period=False):
|
||||
license_date = time.time() - 1
|
||||
|
||||
@ -101,12 +101,12 @@ def job_template_with_survey_passwords_unit(job_template_with_survey_passwords_f
|
||||
|
||||
@pytest.fixture
|
||||
def enterprise_license():
|
||||
from awx.main.task_engine import TaskEnhancer
|
||||
return TaskEnhancer(
|
||||
from tower_license import TowerLicense
|
||||
return TowerLicense(
|
||||
company_name='AWX',
|
||||
contact_name='AWX Admin',
|
||||
contact_email='awx@example.com',
|
||||
license_date=int(time.time() + 3600),
|
||||
instance_count=10000,
|
||||
license_type='enterprise',
|
||||
).enhance()
|
||||
).generate()
|
||||
|
||||
@ -6,19 +6,20 @@ import pytest
|
||||
from datetime import datetime
|
||||
|
||||
from awx.main.models import Host
|
||||
from awx.main.task_engine import TaskEnhancer
|
||||
from awx.main.utils import get_licenser, StubLicense
|
||||
from tower_license import TowerLicense
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_license_writer(inventory, admin):
|
||||
task_enhancer = TaskEnhancer(
|
||||
license_actual = TowerLicense(
|
||||
company_name='acmecorp',
|
||||
contact_name='Michael DeHaan',
|
||||
contact_email='michael@ansibleworks.com',
|
||||
license_date=25000, # seconds since epoch
|
||||
instance_count=500)
|
||||
|
||||
data = task_enhancer.enhance()
|
||||
data = license_actual.generate()
|
||||
|
||||
Host.objects.bulk_create(
|
||||
[
|
||||
@ -38,7 +39,7 @@ def test_license_writer(inventory, admin):
|
||||
assert data['license_date'] == 25000
|
||||
assert data['license_key'] == "11bae31f31c6a6cdcb483a278cdbe98bd8ac5761acd7163a50090b0f098b3a13"
|
||||
|
||||
vdata = task_enhancer.validate_enhancements()
|
||||
vdata = license_actual.validate()
|
||||
|
||||
assert vdata['available_instances'] == 500
|
||||
assert vdata['current_instances'] == 12
|
||||
@ -52,43 +53,51 @@ def test_license_writer(inventory, admin):
|
||||
assert vdata['subscription_name']
|
||||
|
||||
|
||||
def test_stub_license():
|
||||
license_actual = StubLicense()
|
||||
assert license_actual['license_key'] == 'OPEN'
|
||||
assert license_actual['valid_key']
|
||||
assert license_actual['compliant']
|
||||
assert license_actual['license_type'] == 'open'
|
||||
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_expired_licenses():
|
||||
task_enhancer = TaskEnhancer(
|
||||
license_actual = TowerLicense(
|
||||
company_name='Tower',
|
||||
contact_name='Tower Admin',
|
||||
contact_email='tower@ansible.com',
|
||||
license_date=int(time.time() - 3600),
|
||||
instance_count=100,
|
||||
trial=True)
|
||||
task_enhancer.enhance()
|
||||
vdata = task_enhancer.validate_enhancements()
|
||||
license_actual.generate()
|
||||
vdata = license_actual.validate()
|
||||
|
||||
assert vdata['compliant'] is False
|
||||
assert vdata['grace_period_remaining'] < 0
|
||||
|
||||
task_enhancer = TaskEnhancer(
|
||||
license_actual = TowerLicense(
|
||||
company_name='Tower',
|
||||
contact_name='Tower Admin',
|
||||
contact_email='tower@ansible.com',
|
||||
license_date=int(time.time() - 2592001),
|
||||
instance_count=100,
|
||||
trial=False)
|
||||
task_enhancer.enhance()
|
||||
vdata = task_enhancer.validate_enhancements()
|
||||
license_actual.generate()
|
||||
vdata = license_actual.validate()
|
||||
|
||||
assert vdata['compliant'] is False
|
||||
assert vdata['grace_period_remaining'] < 0
|
||||
|
||||
task_enhancer = TaskEnhancer(
|
||||
license_actual = TowerLicense(
|
||||
company_name='Tower',
|
||||
contact_name='Tower Admin',
|
||||
contact_email='tower@ansible.com',
|
||||
license_date=int(time.time() - 3600),
|
||||
instance_count=100,
|
||||
trial=False)
|
||||
task_enhancer.enhance()
|
||||
vdata = task_enhancer.validate_enhancements()
|
||||
license_actual.generate()
|
||||
vdata = license_actual.validate()
|
||||
|
||||
assert vdata['compliant'] is False
|
||||
assert vdata['grace_period_remaining'] > 0
|
||||
@ -96,9 +105,9 @@ def test_expired_licenses():
|
||||
|
||||
@pytest.mark.django_db
|
||||
def test_cloudforms_license(mocker):
|
||||
with mocker.patch('awx.main.task_engine.TaskEnhancer._check_cloudforms_subscription', return_value=True):
|
||||
task_enhancer = TaskEnhancer()
|
||||
vdata = task_enhancer.validate_enhancements()
|
||||
with mocker.patch('tower_license.TowerLicense._check_cloudforms_subscription', return_value=True):
|
||||
license_actual = TowerLicense()
|
||||
vdata = license_actual.validate()
|
||||
assert vdata['compliant'] is True
|
||||
assert vdata['subscription_name'] == "Red Hat CloudForms License"
|
||||
assert vdata['available_instances'] == 9999999
|
||||
|
||||
@ -268,7 +268,7 @@ class TestCheckLicense:
|
||||
def exists(self):
|
||||
return host_exists
|
||||
|
||||
mocker.patch('awx.main.tasks.TaskEnhancer.validate_enhancements', return_value={'free_instances': free_instances, 'available_instances': available_instances, 'date_warning': True})
|
||||
mocker.patch('tower_license.TowerLicense.validate', return_value={'free_instances': free_instances, 'available_instances': available_instances, 'date_warning': True})
|
||||
|
||||
mock_filter = MockFilter()
|
||||
mocker.patch('awx.main.models.Host.objects.filter', return_value=mock_filter)
|
||||
|
||||
@ -29,9 +29,10 @@ from awx.main.models import (
|
||||
)
|
||||
|
||||
from awx.main import tasks
|
||||
from awx.main.task_engine import TaskEnhancer
|
||||
from awx.main.utils import encrypt_field
|
||||
|
||||
from tower_license import TowerLicense
|
||||
|
||||
|
||||
@contextmanager
|
||||
def apply_patches(_patches):
|
||||
@ -83,9 +84,9 @@ def test_run_admin_checks_usage(mocker, current_instances, call_count):
|
||||
patches = list()
|
||||
patches.append(mocker.patch('awx.main.tasks.User'))
|
||||
|
||||
mock_te = mocker.Mock(spec=TaskEnhancer)
|
||||
mock_te.validate_enhancements.return_value = {'instance_count': 100, 'current_instances': current_instances, 'date_warning': True}
|
||||
patches.append(mocker.patch('awx.main.tasks.TaskEnhancer', return_value=mock_te))
|
||||
mock_te = mocker.Mock(spec=TowerLicense)
|
||||
mock_te.validate.return_value = {'instance_count': 100, 'current_instances': current_instances, 'date_warning': True}
|
||||
patches.append(mocker.patch('tower_license.TowerLicense', return_value=mock_te))
|
||||
|
||||
mock_sm = mocker.Mock()
|
||||
patches.append(mocker.patch('awx.main.tasks.send_mail', wraps=mock_sm))
|
||||
|
||||
@ -33,7 +33,7 @@ from django.apps import apps
|
||||
logger = logging.getLogger('awx.main.utils')
|
||||
|
||||
__all__ = ['get_object_or_400', 'get_object_or_403', 'camelcase_to_underscore', 'memoize',
|
||||
'get_ansible_version', 'get_ssh_version', 'get_awx_version', 'update_scm_url',
|
||||
'get_ansible_version', 'get_ssh_version', 'get_licenser', 'get_awx_version', 'update_scm_url',
|
||||
'get_type_for_model', 'get_model_for_type', 'copy_model_by_class',
|
||||
'copy_m2m_relationships' ,'cache_list_capabilities', 'to_python_boolean',
|
||||
'ignore_inventory_computed_fields', 'ignore_inventory_group_removal',
|
||||
@ -161,6 +161,23 @@ def get_awx_version():
|
||||
return __version__
|
||||
|
||||
|
||||
class StubLicense(object):
|
||||
|
||||
def validate(self):
|
||||
return dict(license_key='OPEN',
|
||||
valid_key=True,
|
||||
compliant=True,
|
||||
license_type='open')
|
||||
|
||||
|
||||
def get_licenser(*args, **kwargs):
|
||||
try:
|
||||
from tower_license import TowerLicense
|
||||
return TowerLicense(*args, **kwargs)
|
||||
except ImportError:
|
||||
return StubLicense(*args, **kwargs)
|
||||
|
||||
|
||||
def update_scm_url(scm_type, url, username=True, password=True,
|
||||
check_special_cases=True, scp_format=False):
|
||||
'''
|
||||
|
||||
@ -2,6 +2,7 @@ FROM centos:7
|
||||
|
||||
ADD Makefile /tmp/Makefile
|
||||
RUN mkdir /tmp/requirements
|
||||
COPY tools/docker-compose/tower-license/dist/tower-license-0.1.tar.gz /tmp/tower-license.tar.gz
|
||||
ADD requirements/requirements.txt \
|
||||
requirements/requirements_git.txt \
|
||||
requirements/requirements_ansible.txt \
|
||||
@ -33,6 +34,7 @@ RUN openssl req -nodes -newkey rsa:2048 -keyout /etc/nginx/nginx.key -out /etc/n
|
||||
RUN openssl x509 -req -days 365 -in /etc/nginx/nginx.csr -signkey /etc/nginx/nginx.key -out /etc/nginx/nginx.crt
|
||||
WORKDIR /tmp
|
||||
RUN SWIG_FEATURES="-cpperraswarn -includeall -D__`uname -m`__ -I/usr/include/openssl" VENV_BASE="/venv" make requirements_dev
|
||||
RUN /venv/tower/bin/pip install /tmp/tower-license.tar.gz
|
||||
RUN localedef -c -i en_US -f UTF-8 en_US.UTF-8
|
||||
ENV LANG en_US.UTF-8
|
||||
ENV LANGUAGE en_US:en
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user