diff --git a/conf/capsule.yaml.template b/conf/capsule.yaml.template index e6747faa5eb..9ef9e48a2c2 100644 --- a/conf/capsule.yaml.template +++ b/conf/capsule.yaml.template @@ -10,6 +10,8 @@ CAPSULE: # The base os rhel version where the capsule installed # RHEL_VERSION: # The Ansible Tower workflow used to deploy a capsule - DEPLOY_WORKFLOW: deploy-capsule + DEPLOY_WORKFLOWS: + PRODUCT: deploy-capsule # workflow to deploy OS with product running on top of it + OS: deploy-rhel # workflow to deploy OS that is ready to run the product # Dictionary of arguments which should be passed along to the deploy workflow DEPLOY_ARGUMENTS: diff --git a/conf/dynaconf_hooks.py b/conf/dynaconf_hooks.py index 116207aa165..6d09d6e5bec 100644 --- a/conf/dynaconf_hooks.py +++ b/conf/dynaconf_hooks.py @@ -1,5 +1,9 @@ +from inspect import getmembers, isfunction import json from pathlib import Path +import sys + +from box import Box from robottelo.logging import logger from robottelo.utils.ohsnap import dogfood_repository @@ -22,6 +26,7 @@ def post(settings): ) data = get_repos_config(settings) write_cache(settings_cache_path, data) + config_migrations(settings, data) data['dynaconf_merge'] = True return data @@ -33,7 +38,32 @@ def write_cache(path, data): def read_cache(path): logger.info(f'Using settings cache file: {path}') - return json.loads(path.read_text()) + return Box(json.loads(path.read_text())) + + +def config_migrations(settings, data): + """Run config migrations + + Fetch the config migrations from the conf/migrations.py file and run them. + + :param settings: dynaconf settings object + :type settings: LazySettings + :param data: settings data to be merged with the rest of the settings + :type data: dict + """ + logger.info('Running config migration hooks') + sys.path.append(str(Path(__file__).parent)) + from conf import migrations + + migration_functions = [ + mf for mf in getmembers(migrations, isfunction) if mf[0].startswith('migration_') + ] + # migration_functions is a sorted list of tuples (name, function) + for name, func in migration_functions: + logger.debug(f'Running {name}') + func(settings, data) + logger.debug(f'Finished running {name}') + logger.info('Finished running config migration hooks') def get_repos_config(settings): @@ -46,7 +76,7 @@ def get_repos_config(settings): 'The Ohsnap URL is invalid! Post-configuration hooks will not run. ' 'Default configuration will be used.' ) - return {'REPOS': data} + return Box({'REPOS': data}) def get_ohsnap_repos(settings): diff --git a/conf/migrations.py b/conf/migrations.py new file mode 100644 index 00000000000..b263fa352d6 --- /dev/null +++ b/conf/migrations.py @@ -0,0 +1,37 @@ +"""Robottelo configuration migrations + +This module contains functions that are run after the configuration is loaded. Each function +should be named `migration__` and accept two parameters: `settings` and +`data`. `settings` is a `dynaconf` `Box` object containing the configuration. `data` is a +`dict` that can be used to store settings that will be merged with the rest of the settings. +The functions should not return anything. +""" + +from packaging.version import Version + +from robottelo.logging import logger + + +def migration_231129_deploy_workflow(settings, data): + """Migrates {server,capsule}.deploy_workflow to {server,capsule}.deploy_workflows""" + for product_type in ['server', 'capsule']: + # If the product_type has a deploy_workflow and it is a string, and + # it does not have a deploy_workflows set + if ( + settings[product_type].get('deploy_workflow') + and isinstance(settings[product_type].deploy_workflow, str) + and not settings[product_type].get('deploy_workflows') + ): + sat_rhel_version = settings[product_type].version.rhel_version + data[product_type] = {} + # Set the deploy_workflows to a dict with product and os keys + # Get the OS workflow from the content_host config + data[product_type].deploy_workflows = { + 'product': settings[product_type].deploy_workflow, + 'os': settings.content_host[ + f'rhel{Version(str(sat_rhel_version)).major}' + ].vm.workflow, + } + logger.info( + f'Migrated {product_type}.DEPLOY_WORKFLOW to {product_type}.DEPLOY_WORKFLOWS' + ) diff --git a/conf/server.yaml.template b/conf/server.yaml.template index 7f876bccaba..c5b844e6509 100644 --- a/conf/server.yaml.template +++ b/conf/server.yaml.template @@ -27,7 +27,9 @@ SERVER: # this setting determines if they will be automatically checked in AUTO_CHECKIN: False # The Ansible Tower workflow used to deploy a satellite - DEPLOY_WORKFLOW: "deploy-sat-jenkins" + DEPLOY_WORKFLOWS: + PRODUCT: deploy-satellite # workflow to deploy OS with product running on top of it + OS: deploy-rhel # workflow to deploy OS that is ready to run the product # Dictionary of arguments which should be passed along to the deploy workflow # DEPLOY_ARGUMENTS: # HTTP scheme when building the server URL diff --git a/pytest_fixtures/core/sat_cap_factory.py b/pytest_fixtures/core/sat_cap_factory.py index 8f83704702e..436d8b6d443 100644 --- a/pytest_fixtures/core/sat_cap_factory.py +++ b/pytest_fixtures/core/sat_cap_factory.py @@ -63,7 +63,7 @@ def factory(retry_limit=3, delay=300, workflow=None, **broker_args): vmb = Broker( host_class=Satellite, - workflow=workflow or settings.server.deploy_workflow, + workflow=workflow or settings.server.deploy_workflows.product, **broker_args, ) timeout = (1200 + delay) * retry_limit @@ -95,7 +95,7 @@ def factory(retry_limit=3, delay=300, workflow=None, **broker_args): broker_args.update(settings.capsule.deploy_arguments) vmb = Broker( host_class=Capsule, - workflow=workflow or settings.capsule.deploy_workflow, + workflow=workflow or settings.capsule.deploy_workflows.product, **broker_args, ) timeout = (1200 + delay) * retry_limit @@ -202,7 +202,7 @@ def module_lb_capsule(retry_limit=3, delay=300, **broker_args): timeout = (1200 + delay) * retry_limit hosts = Broker( host_class=Capsule, - workflow=settings.capsule.deploy_workflow, + workflow=settings.capsule.deploy_workflows.product, _count=2, **broker_args, ) @@ -245,12 +245,13 @@ def parametrized_enrolled_sat( def get_deploy_args(request): + """Get deploy arguments for Satellite base OS deployment. Should not be used for Capsule.""" rhel_version = get_sat_rhel_version() deploy_args = { 'deploy_rhel_version': rhel_version.base_version, 'deploy_flavor': settings.flavors.default, 'promtail_config_template_file': 'config_sat.j2', - 'workflow': settings.content_host.get(f'rhel{rhel_version.major}').vm.workflow, + 'workflow': settings.server.deploy_workflows.os, } if hasattr(request, 'param'): if isinstance(request.param, dict): @@ -277,11 +278,11 @@ def module_sat_ready_rhels(request): @pytest.fixture def cap_ready_rhel(): rhel_version = Version(settings.capsule.version.release) - settings.content_host.get(f'rhel{rhel_version.major}').vm.workflow deploy_args = { 'deploy_rhel_version': rhel_version.base_version, 'deploy_flavor': settings.flavors.default, - 'workflow': settings.content_host.get(f'rhel{rhel_version.major}').vm.workflow, + 'promtail_config_template_file': 'config_sat.j2', + 'workflow': settings.capsule.deploy_workflows.os, } with Broker(**deploy_args, host_class=Capsule) as host: yield host diff --git a/robottelo/config/validators.py b/robottelo/config/validators.py index 383abfb7aed..f598821839d 100644 --- a/robottelo/config/validators.py +++ b/robottelo/config/validators.py @@ -23,7 +23,9 @@ ), Validator('server.admin_password', default='changeme'), Validator('server.admin_username', default='admin'), - Validator('server.deploy_workflow', must_exist=True), + Validator('server.deploy_workflows', must_exist=True, is_type_of=dict), + Validator('server.deploy_workflows.product', must_exist=True), + Validator('server.deploy_workflows.os', must_exist=True), Validator('server.deploy_arguments', must_exist=True, is_type_of=dict, default={}), Validator('server.scheme', default='https'), Validator('server.port', default=443), @@ -67,7 +69,9 @@ capsule=[ Validator('capsule.version.release', must_exist=True), Validator('capsule.version.source', must_exist=True), - Validator('capsule.deploy_workflow', must_exist=True), + Validator('capsule.deploy_workflows', must_exist=True, is_type_of=dict), + Validator('capsule.deploy_workflows.product', must_exist=True), + Validator('capsule.deploy_workflows.os', must_exist=True), Validator('capsule.deploy_arguments', must_exist=True, is_type_of=dict, default={}), ], certs=[ diff --git a/robottelo/hosts.py b/robottelo/hosts.py index 4c35dbd41d5..9b1ef870b1a 100644 --- a/robottelo/hosts.py +++ b/robottelo/hosts.py @@ -74,7 +74,7 @@ def lru_sat_ready_rhel(rhel_ver): 'deploy_rhel_version': rhel_version, 'deploy_flavor': settings.flavors.default, 'promtail_config_template_file': 'config_sat.j2', - 'workflow': settings.content_host.get(f'rhel{Version(rhel_version).major}').vm.workflow, + 'workflow': settings.server.deploy_workflows.os, } sat_ready_rhel = Broker(**deploy_args, host_class=Satellite).checkout() return sat_ready_rhel