diff --git a/conf/capsule.yaml.template b/conf/capsule.yaml.template index b101f432a93..aed01592162 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 d6ed57a1605..987749793cb 100644 --- a/conf/robottelo.yaml.template +++ b/conf/robottelo.yaml.template @@ -22,6 +22,9 @@ ROBOTTELO: - '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 c54fa8026bc..6ab8333f1b4 100644 --- a/pytest_fixtures/core/sat_cap_factory.py +++ b/pytest_fixtures/core/sat_cap_factory.py @@ -324,14 +324,15 @@ def sat_ready_rhel(request): @pytest.fixture(scope='module') def module_sat_ready_rhels(request): deploy_args = get_deploy_args(request) - with Broker(**deploy_args, host_class=Satellite, _count=2) as hosts: + with Broker(**deploy_args, host_class=Satellite, _count=3) as hosts: yield hosts @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, @@ -356,13 +357,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() # Install Satellite sat.execute( diff --git a/robottelo/config/validators.py b/robottelo/config/validators.py index bf70b2487af..89c7aa7e24a 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), @@ -322,6 +322,7 @@ default=[], cast=lambda x: list(map(str, x)), ), + 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 707b13ef4cd..4433334ace7 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 582aa000f0a..d3cd4f54bbe 100644 --- a/robottelo/hosts.py +++ b/robottelo/hosts.py @@ -70,8 +70,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, @@ -525,6 +526,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 e83e512129f..bc092613f3d 100644 --- a/tests/foreman/installer/test_installer.py +++ b/tests/foreman/installer/test_installer.py @@ -17,10 +17,10 @@ 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 PREVIOUS_INSTALLER_OPTIONS = { '-', @@ -1359,7 +1359,7 @@ def install_satellite(satellite, installer_args, enable_fapolicyd=False): satellite.execute('dnf -y install fapolicyd && systemctl enable --now fapolicyd').status == 0 ) - satellite.execute('dnf -y module enable satellite:el8 && dnf -y install satellite') + satellite.install_satellite_or_capsule_package() if enable_fapolicyd: assert satellite.execute('rpm -q foreman-fapolicyd').status == 0 assert satellite.execute('rpm -q foreman-proxy-fapolicyd').status == 0 @@ -1374,6 +1374,114 @@ def install_satellite(satellite, installer_args, enable_fapolicyd=False): ) +def setup_capsule_repos(satellite, capsule_host, org, ak): + """ + Enables repositories that are necessary to install capsule + 1. Enable RHEL repositories based on configuration + 2. Enable capsule repositories based on configuration + 3. Synchonize repositories + """ + # 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 = satellite.api.Product(organization=org.id).create() + for repourl in settings.repos.get(f'rhel{capsule_host.os_version.major}_os').values(): + repo = satellite.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{capsule_host.os_version.major}_bos', + f'rhel{capsule_host.os_version.major}_aps', + ]: + satellite.api_factory.enable_rhrepo_and_fetchid( + basearch=DEFAULT_ARCHITECTURE, + org_id=org.id, + product=PRDS[f'rhel{capsule_host.os_version.major}'], + repo=REPOS[rh_repo_key]['name'], + reposet=REPOSET[rh_repo_key], + releasever=REPOS[rh_repo_key]['releasever'], + ) + product_rhel = satellite.api.Product( + name=PRDS[f'rhel{capsule_host.os_version.major}'], organization=org.id + ).search()[0] + sync_tasks.append(satellite.api.Product(id=product_rhel.id).sync(synchronous=False)) + + # Enable and sync Capsule repos + if settings.capsule.version.source == "ga": + # enable Capsule repos from CDN + for repo in capsule_host.CAPSULE_CDN_REPOS.values(): + reposet = satellite.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(satellite.api.Product(id=reposet.product.id).sync(synchronous=False)) + else: + # configure internal source as custom repos + product_capsule = satellite.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=capsule_host.os_version.major, + snap=settings.capsule.version.snap, + ) + repo = satellite.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(satellite.api.Product(id=product_capsule.id).sync(synchronous=False)) + + # Wait for asynchronous sync tasks + satellite.wait_for_tasks( + search_query=(f'id ^ "{",".join(task["id"] for task in sync_tasks)}"'), + poll_timeout=1800, + ) + + @pytest.fixture(scope='module') def sat_default_install(module_sat_ready_rhels): """Install Satellite with default options""" @@ -1387,6 +1495,19 @@ def sat_default_install(module_sat_ready_rhels): return sat +@pytest.fixture(scope='module') +def sat_fapolicyd_install(module_sat_ready_rhels): + """Install Satellite with default options and fapolicyd enabled""" + installer_args = [ + 'scenario satellite', + f'foreman-initial-admin-password {settings.server.admin_password}', + ] + install_satellite(module_sat_ready_rhels[1], installer_args, enable_fapolicyd=True) + sat = module_sat_ready_rhels[1] + sat.enable_ipv6_http_proxy() + return sat + + @pytest.fixture(scope='module') def sat_non_default_install(module_sat_ready_rhels): """Provides fapolicyd enabled Satellite with various options""" @@ -1398,8 +1519,8 @@ def sat_non_default_install(module_sat_ready_rhels): 'enable-foreman-plugin-discovery', 'foreman-proxy-plugin-discovery-install-images true', ] - install_satellite(module_sat_ready_rhels[1], installer_args, enable_fapolicyd=True) - sat = module_sat_ready_rhels[1] + install_satellite(module_sat_ready_rhels[2], installer_args, enable_fapolicyd=True) + sat = module_sat_ready_rhels[2] sat.enable_ipv6_http_proxy() sat.execute('dnf -y --disableplugin=foreman-protector install foreman-discovery-image') return sat @@ -1411,16 +1532,18 @@ def sat_non_default_install(module_sat_ready_rhels): @pytest.mark.parametrize( 'setting_update', [f'http_proxy={settings.http_proxy.un_auth_proxy_url}'], indirect=True ) -def test_capsule_installation(sat_non_default_install, cap_ready_rhel, setting_update): +def test_capsule_installation( + sat_fapolicyd_install, cap_ready_rhel, module_sca_manifest, setting_update +): """Run a basic Capsule installation with fapolicyd :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 + 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: @@ -1434,28 +1557,39 @@ def test_capsule_installation(sat_non_default_install, cap_ready_rhel, setting_u :customerscenario: true """ - # Get Capsule repofile, and enable and download satellite-capsule - 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, - ) - # Enable fapolicyd + # Create testing organization + org = sat_fapolicyd_install.api.Organization().create() + + # Unregister capsule in case it's registered to CDN + cap_ready_rhel.unregister() + + # Add a manifest to the Satellite + sat_fapolicyd_install.upload_manifest(org.id, module_sca_manifest.content) + # Create capsule certs and activation key + file, _, cmd_args = sat_fapolicyd_install.capsule_certs_generate(cap_ready_rhel) + sat_fapolicyd_install.session.remote_copy(file, cap_ready_rhel) + ak = sat_fapolicyd_install.api.ActivationKey(organization=org, environment=org.library).create() + + setup_capsule_repos(sat_fapolicyd_install, cap_ready_rhel, org, ak) + + cap_ready_rhel.register(org, None, ak.name, sat_fapolicyd_install) + + # Install (enable) fapolicyd assert ( cap_ready_rhel.execute( 'dnf -y install fapolicyd && systemctl enable --now fapolicyd' ).status == 0 ) - cap_ready_rhel.execute( - 'dnf -y module enable satellite-capsule:el8 && dnf -y install satellite-capsule' - ) + + # 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) - assert sat_non_default_install.api.Capsule().search( + cap_ready_rhel.install(cmd_args) + + assert sat_fapolicyd_install.api.Capsule().search( query={'search': f'name={cap_ready_rhel.hostname}'} )[0]