diff --git a/conf/capsule.yaml.template b/conf/capsule.yaml.template index 4f50d26bfaf..1b6517d6e59 100644 --- a/conf/capsule.yaml.template +++ b/conf/capsule.yaml.template @@ -7,7 +7,7 @@ CAPSULE: # The snap version currently testing (if applicable) # SNAP: # The source of Capsule packages. Can be one of: - # internal, ga, beta + # internal, ga SOURCE: "internal" # The base os rhel version where the capsule installed # RHEL_VERSION: diff --git a/conf/robottelo.yaml.template b/conf/robottelo.yaml.template index 513ee0db15e..5b3c2688a1d 100644 --- a/conf/robottelo.yaml.template +++ b/conf/robottelo.yaml.template @@ -18,6 +18,9 @@ ROBOTTELO: SATELLITE_VERSION: "6.17" # The Base OS RHEL Version(x.y) where the satellite would be installed RHEL_VERSION: "8.10" + # The source of RHEL packages. Can be one of: + # internal, ga (CDN) + RHEL_SOURCE: "ga" # Dynaconf and Dynaconf hooks related options SETTINGS: GET_FRESH: true diff --git a/conf/server.yaml.template b/conf/server.yaml.template index e196dd9413d..7abb7857b36 100644 --- a/conf/server.yaml.template +++ b/conf/server.yaml.template @@ -4,15 +4,15 @@ SERVER: # - replace.with.satellite.hostname # - replace.with.satellite.hostname VERSION: - # The full release version (6.9.2) - RELEASE: 6.9.2 + # The full release version (6.15.0) + RELEASE: 6.15.0 # The snap version currently testing (if applicable) SNAP: 1.0 # The source of Satellite packages. Can be one of: - # internal, ga, beta + # internal, ga SOURCE: "internal" # The RHEL Base OS Version(x.y) where the Satellite is installed - RHEL_VERSION: '7' + RHEL_VERSION: '8' # If the the satellite server is IPv6 server IS_IPV6: False # HTTP Proxy url for IPv6 satellite to connect for outer world access diff --git a/pytest_fixtures/core/sat_cap_factory.py b/pytest_fixtures/core/sat_cap_factory.py index 4c38c77546f..c78b3163281 100644 --- a/pytest_fixtures/core/sat_cap_factory.py +++ b/pytest_fixtures/core/sat_cap_factory.py @@ -331,8 +331,9 @@ def module_sat_ready_rhels(request): @pytest.fixture def cap_ready_rhel(): + """Deploy bare RHEL system ready for Capsule installation.""" rhel_version = Version(settings.capsule.version.rhel_version) - deploy_args = { + deploy_args = settings.capsule.deploy_arguments | { 'deploy_rhel_version': rhel_version.base_version, 'deploy_network_type': 'ipv6' if settings.server.is_ipv6 else 'ipv4', 'deploy_flavor': settings.flavors.default, @@ -359,13 +360,28 @@ def installer_satellite(request): else: sat = lru_sat_ready_rhel(getattr(request, 'param', None)) sat.setup_firewall() - # # Register for RHEL8 repos, get Ohsnap repofile, and enable and download satellite + + # register to cdn (also enables rhel repos from cdn) sat.register_to_cdn(enable_proxy=True) - sat.download_repofile( - product='satellite', - release=settings.server.version.release, - snap=settings.server.version.snap, - ) + + # setup source repositories + if settings.server.version.source == "ga": + # enable satellite repos + for repo in sat.SATELLITE_CDN_REPOS.values(): + sat.enable_repo(repo, force=True) + else: + # get ohsnap repofile + sat.download_repofile( + product='satellite', + release=settings.server.version.release, + snap=settings.server.version.snap, + ) + if settings.robottelo.rhel_source == "internal": + # disable rhel repos from cdn + sat.disable_repo("rhel-*") + # add internal rhel repos + sat.create_custom_repos(**settings.repos.get(f'rhel{sat.os_version.major}_os')) + sat.install_satellite_or_capsule_package() installed_version = sat.execute('rpm --query satellite').stdout assert sat_version in installed_version diff --git a/robottelo/config/validators.py b/robottelo/config/validators.py index bf3d313b514..07b2781dc33 100644 --- a/robottelo/config/validators.py +++ b/robottelo/config/validators.py @@ -13,7 +13,7 @@ Validator('server.hostname', is_type_of=str), Validator('server.hostnames', must_exist=True, is_type_of=list), Validator('server.version.release', must_exist=True), - Validator('server.version.source', must_exist=True), + Validator('server.version.source', default='internal', is_in=['internal', 'ga']), Validator('server.version.rhel_version', must_exist=True, cast=str), Validator( 'server.xdist_behavior', must_exist=True, is_in=['run-on-one', 'balance', 'on-demand'] @@ -79,7 +79,7 @@ ], capsule=[ Validator('capsule.version.release', must_exist=True), - Validator('capsule.version.source', must_exist=True), + Validator('capsule.version.source', default='internal', is_in=['internal', 'ga']), 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), @@ -316,6 +316,7 @@ ], robottelo=[ Validator('robottelo.settings.ignore_validation_errors', is_type_of=bool, default=False), + Validator('robottelo.rhel_source', default='ga', is_in=['ga', 'internal']), ], shared_function=[ Validator('shared_function.storage', is_in=('file', 'redis'), default='file'), diff --git a/robottelo/host_helpers/contenthost_mixins.py b/robottelo/host_helpers/contenthost_mixins.py index 2fcfd909d3e..aed79993434 100644 --- a/robottelo/host_helpers/contenthost_mixins.py +++ b/robottelo/host_helpers/contenthost_mixins.py @@ -56,6 +56,22 @@ def REPOS(self): except KeyError as err: raise ValueError(f'Unsupported system version: {self._v_major}') from err + @cached_property + def SATELLITE_CDN_REPOS(self): + sat_version = ".".join(settings.server.version.release.split('.')[0:2]) + return { + 'satellite': f"satellite-{sat_version}-for-rhel-{self._v_major}-x86_64-rpms", + 'sat-maintenance': f"satellite-maintenance-{sat_version}-for-rhel-{self._v_major}-x86_64-rpms", + } + + @cached_property + def CAPSULE_CDN_REPOS(self): + sat_version = ".".join(settings.server.version.release.split('.')[0:2]) + return { + 'capsule': f"satellite-capsule-{sat_version}-for-rhel-{self._v_major}-x86_64-rpms", + 'sat-maintenance': f"satellite-maintenance-{sat_version}-for-rhel-{self._v_major}-x86_64-rpms", + } + @cached_property def OSCAP(self): return { diff --git a/robottelo/hosts.py b/robottelo/hosts.py index 68c789d050c..04ac0bd8f5f 100644 --- a/robottelo/hosts.py +++ b/robottelo/hosts.py @@ -20,7 +20,6 @@ from broker.hosts import Host from dynaconf.vendor.box.exceptions import BoxKeyError from fauxfactory import gen_alpha, gen_string -from manifester import Manifester from nailgun import entities from packaging.version import Version import requests @@ -41,12 +40,8 @@ CUSTOM_PUPPET_MODULE_REPOS, CUSTOM_PUPPET_MODULE_REPOS_PATH, CUSTOM_PUPPET_MODULE_REPOS_VERSION, - DEFAULT_ARCHITECTURE, HAMMER_CONFIG, KEY_CLOAK_CLI, - PRDS, - REPOS, - REPOSET, RHSSO_NEW_GROUP, RHSSO_NEW_USER, RHSSO_RESET_PASSWORD, @@ -70,8 +65,9 @@ @lru_cache def lru_sat_ready_rhel(rhel_ver): + """Deploy bare RHEL system ready for Satellite installation.""" rhel_version = rhel_ver or settings.server.version.rhel_version - deploy_args = { + deploy_args = settings.server.deploy_arguments | { 'deploy_rhel_version': rhel_version, 'deploy_network_type': 'ipv6' if settings.server.is_ipv6 else 'ipv4', 'deploy_flavor': settings.flavors.default, @@ -109,53 +105,6 @@ def get_sat_rhel_version(): return Version(rhel_version) -def setup_capsule(satellite, capsule, org, registration_args=None, installation_args=None): - """Given satellite and capsule instances, run the commands needed to set up the capsule - - Note: This does not perform content setup actions on the Satellite - - :param satellite: An instance of this module's Satellite class - :param capsule: An instance of this module's Capsule class - :param org: An instance of the org to use on the Satellite - :param registration_args: A dictionary mapping argument: value pairs for registration - :param installation_args: A dictionary mapping argument: value pairs for installation - :return: An ssh2-python result object for the installation command. - - """ - # Unregister capsule incase it's registered to CDN - capsule.unregister() - - # Add a manifest to the Satellite - with Manifester(manifest_category=settings.manifest.entitlement) as manifest: - satellite.upload_manifest(org.id, manifest.content) - - # Enable RHEL 8 BaseOS and AppStream repos and sync - for rh_repo_key in ['rhel8_bos', 'rhel8_aps']: - satellite.api_factory.enable_rhrepo_and_fetchid( - basearch=DEFAULT_ARCHITECTURE, - org_id=org.id, - product=PRDS['rhel8'], - repo=REPOS[rh_repo_key]['name'], - reposet=REPOSET[rh_repo_key], - releasever=REPOS[rh_repo_key]['releasever'], - ) - product = satellite.api.Product(name=PRDS['rhel8'], organization=org.id).search()[0] - product.sync(timeout=1800, synchronous=True) - - if not registration_args: - registration_args = {} - file, _, cmd_args = satellite.capsule_certs_generate(capsule) - if installation_args: - cmd_args.update(installation_args) - satellite.execute( - f'sshpass -p "{capsule.password}" scp -o "StrictHostKeyChecking no" ' - f'{file} root@{capsule.hostname}:{file}' - ) - capsule.install_katello_ca(satellite) - capsule.register_contenthost(org=org.label, **registration_args) - return capsule.install(cmd_args) - - class ContentHostError(Exception): pass @@ -525,6 +474,9 @@ def enable_repo(self, repo, force=False): return self.execute(f'subscription-manager repos --enable {repo}') return None + def disable_repo(self, repo): + return self.execute(f'subscription-manager repos --disable {repo}') + def subscription_manager_list_repos(self): return self.execute('subscription-manager repos --list') diff --git a/tests/foreman/installer/test_installer.py b/tests/foreman/installer/test_installer.py index 506dddef312..520ce37afae 100644 --- a/tests/foreman/installer/test_installer.py +++ b/tests/foreman/installer/test_installer.py @@ -12,16 +12,17 @@ """ +from manifester import Manifester import pytest import requests import yaml from robottelo import ssh from robottelo.config import settings -from robottelo.constants import FOREMAN_SETTINGS_YML, PRDS, REPOS, REPOSET -from robottelo.hosts import setup_capsule +from robottelo.constants import DEFAULT_ARCHITECTURE, FOREMAN_SETTINGS_YML, PRDS, REPOS, REPOSET from robottelo.utils.installer import InstallerCommand from robottelo.utils.issue_handlers import is_open +from robottelo.utils.ohsnap import dogfood_repository SATELLITE_SERVICES = [ 'dynflow-sidekiq@orchestrator', @@ -195,10 +196,10 @@ def test_capsule_installation(sat_non_default_install, cap_ready_rhel, setting_u :id: 64fa85b6-96e6-4fea-bea4-a30539d59e65 :steps: - 1. Get a fapolicyd enabled Satellite - 2. Configure capsule repos - 3. Install and enable fapolicyd - 4. Enable capsule module + 1. Use Satellite with fapolicyd enabled (non-default) + 2. Configure RHEL and Capsule repos on Satellite + 3. Register Capsule machine to consume Satellite content + 4. Install and enable fapolicyd 5. Install and setup capsule :expectedresults: @@ -212,25 +213,145 @@ def test_capsule_installation(sat_non_default_install, cap_ready_rhel, setting_u :customerscenario: true """ - # Get Capsule repofile, and enable and download satellite-capsule + # Create testing organization org = sat_non_default_install.api.Organization().create() - cap_ready_rhel.register_to_cdn() - cap_ready_rhel.download_repofile( - product='capsule', - release=settings.server.version.release, - snap=settings.server.version.snap, + + # Unregister capsule in case it's registered to CDN + cap_ready_rhel.unregister() + + # Add a manifest to the Satellite + with Manifester(manifest_category=settings.manifest.entitlement) as manifest: + sat_non_default_install.upload_manifest(org.id, manifest.content) + # Create capsule certs and activation key + file, _, cmd_args = sat_non_default_install.capsule_certs_generate(cap_ready_rhel) + sat_non_default_install.session.remote_copy(file, cap_ready_rhel) + ak = sat_non_default_install.api.ActivationKey( + organization=org, environment=org.library + ).create() + + # List of sync tasks - all repos will be synced asynchronously + sync_tasks = [] + + # Enable and sync RHEL BaseOS and AppStream repos + if settings.robottelo.rhel_source == "internal": + # Configure internal sources as custom repositories + product_rhel = sat_non_default_install.api.Product(organization=org.id).create() + for repourl in settings.repos.get(f'rhel{cap_ready_rhel.os_version.major}_os').values(): + repo = sat_non_default_install.api.Repository( + organization=org.id, product=product_rhel, content_type='yum', url=repourl + ).create() + # custom repos need to be explicitly enabled + ak.content_override( + data={ + 'content_overrides': [ + { + 'content_label': '_'.join([org.label, product_rhel.label, repo.label]), + 'value': '1', + } + ] + } + ) + else: + # use AppStream and BaseOS from CDN + for rh_repo_key in [ + f'rhel{cap_ready_rhel.os_version.major}_bos', + f'rhel{cap_ready_rhel.os_version.major}_aps', + ]: + sat_non_default_install.api_factory.enable_rhrepo_and_fetchid( + basearch=DEFAULT_ARCHITECTURE, + org_id=org.id, + product=PRDS[f'rhel{cap_ready_rhel.os_version.major}'], + repo=REPOS[rh_repo_key]['name'], + reposet=REPOSET[rh_repo_key], + releasever=REPOS[rh_repo_key]['releasever'], + ) + product_rhel = sat_non_default_install.api.Product( + name=PRDS[f'rhel{cap_ready_rhel.os_version.major}'], organization=org.id + ).search()[0] + sync_tasks.append( + sat_non_default_install.api.Product(id=product_rhel.id).sync(synchronous=False) ) - # Enable fapolicyd + + # Enable and sync Capsule repos + if settings.capsule.version.source == "ga": + # enable Capsule repos from CDN + for repo in cap_ready_rhel.CAPSULE_CDN_REPOS.values(): + reposet = sat_non_default_install.api.RepositorySet(organization=org.id).search( + query={'search': repo} + )[0] + reposet.enable() + # repos need to be explicitly enabled in AK + ak.content_override( + data={ + 'content_overrides': [ + { + 'content_label': reposet.label, + 'value': '1', + } + ] + } + ) + sync_tasks.append( + sat_non_default_install.api.Product(id=reposet.product.id).sync(synchronous=False) + ) + else: + # configure internal source as custom repos + product_capsule = sat_non_default_install.api.Product(organization=org.id).create() + for repo_variant in ['capsule', 'maintenance']: + dogfood_repo = dogfood_repository( + ohsnap=settings.ohsnap, + repo=repo_variant, + product="capsule", + release=settings.capsule.version.release, + os_release=cap_ready_rhel.os_version.major, + snap=settings.capsule.version.snap, + ) + repo = sat_non_default_install.api.Repository( + organization=org.id, + product=product_capsule, + content_type='yum', + url=dogfood_repo.baseurl, + ).create() + # custom repos need to be explicitly enabled + ak.content_override( + data={ + 'content_overrides': [ + { + 'content_label': '_'.join( + [org.label, product_capsule.label, repo.label] + ), + 'value': '1', + } + ] + } + ) + sync_tasks.append( + sat_non_default_install.api.Product(id=product_capsule.id).sync(synchronous=False) + ) + + # Wait for asynchronous sync tasks + for task in sync_tasks: + sat_non_default_install.wait_for_tasks( + search_query=(f'id = {task["id"]}'), + poll_timeout=1800, + ) + + cap_ready_rhel.register(org, None, ak.name, sat_non_default_install) + + # Install (enable) fapolicyd assert ( cap_ready_rhel.execute( 'dnf -y install fapolicyd && systemctl enable --now fapolicyd' ).status == 0 ) + # Install Capsule package cap_ready_rhel.install_satellite_or_capsule_package() assert cap_ready_rhel.execute('rpm -q foreman-proxy-fapolicyd').status == 0 + # Setup Capsule - setup_capsule(sat_non_default_install, cap_ready_rhel, org) + cap_ready_rhel.install(cmd_args) + assert sat_non_default_install.api.Capsule().search( query={'search': f'name={cap_ready_rhel.hostname}'} )[0]