From 4489ff821659a1fe837a485f3833d0e18266fd35 Mon Sep 17 00:00:00 2001 From: Jeremy Lenz Date: Mon, 19 Aug 2024 11:28:45 -0400 Subject: [PATCH] Add tests for multi-CV hosts (#15871) --- pytest_fixtures/component/contentview.py | 21 +++ robottelo/host_helpers/satellite_mixins.py | 4 + robottelo/hosts.py | 15 +- tests/foreman/cli/test_host.py | 171 +++++++++++++++++++++ 4 files changed, 210 insertions(+), 1 deletion(-) diff --git a/pytest_fixtures/component/contentview.py b/pytest_fixtures/component/contentview.py index ea7568352de..5f979878e79 100644 --- a/pytest_fixtures/component/contentview.py +++ b/pytest_fixtures/component/contentview.py @@ -76,3 +76,24 @@ def session_multicv_sat(session_satellite_host): session_satellite_host.enable_multicv_setting() session_satellite_host.update_setting('allow_multiple_content_views', 'True') return session_satellite_host + + +@pytest.fixture(scope='session') +def session_multicv_org(session_multicv_sat): + return session_multicv_sat.api.Organization().create() + + +@pytest.fixture(scope='session') +def session_multicv_default_ak(session_multicv_sat, session_multicv_org): + return session_multicv_sat.api.ActivationKey( + organization=session_multicv_org, + content_view=session_multicv_org.default_content_view.id, + environment=session_multicv_org.library.id, + ).create() + + +@pytest.fixture(scope='session') +def session_multicv_lce(session_multicv_sat, session_multicv_org): + return session_multicv_sat.api.LifecycleEnvironment( + organization=session_multicv_org, + ).create() diff --git a/robottelo/host_helpers/satellite_mixins.py b/robottelo/host_helpers/satellite_mixins.py index e44fc9573c4..ae33ff6f167 100644 --- a/robottelo/host_helpers/satellite_mixins.py +++ b/robottelo/host_helpers/satellite_mixins.py @@ -41,6 +41,10 @@ def enable_puppet_satellite(self): def enable_multicv_setting(self): """Makes multi-CV setting available in the downstream Satellite""" + if len( + self.api.Setting().search(query={'search': 'name={"allow_multiple_content_views"}'}) + ): + return # Setting is already exposed cfg_file = 'upstream_only_settings.rb' cfg_path = self.execute(f'find /usr/share/gems/gems/ -name {cfg_file}').stdout.strip() assert cfg_file in cfg_path, 'Config file not found' diff --git a/robottelo/hosts.py b/robottelo/hosts.py index cfd4a67b76d..7efc94be288 100644 --- a/robottelo/hosts.py +++ b/robottelo/hosts.py @@ -451,7 +451,6 @@ def download_install_rpm(self, repo_url, package_name): def enable_repo(self, repo, force=False): """Enables specified Red Hat repository on the broker virtual machine. Does nothing if downstream capsule or satellite tools repo was passed. - Custom repos are enabled by default when registering a host. :param repo: Red Hat repository name. :param force: enforce enabling command, even when custom repos are @@ -484,6 +483,20 @@ def subscription_manager_status(self): def subscription_manager_list(self): return self.execute('subscription-manager list') + def subscription_manager_environments_set( + self, + env_names, + username=settings.server.admin_username, + password=settings.server.admin_password, + ): + """ + Reassign the host to the specified content view environments + """ + assert isinstance(env_names, str) + return self.execute( + f'subscription-manager environments --set="{env_names}" --username={username} --password={password}' + ) + def subscription_manager_get_pool(self, sub_list=None): """ Return pool ids for the corresponding subscriptions in the list diff --git a/tests/foreman/cli/test_host.py b/tests/foreman/cli/test_host.py index 3f179a75bca..050fdb969c4 100644 --- a/tests/foreman/cli/test_host.py +++ b/tests/foreman/cli/test_host.py @@ -2016,6 +2016,7 @@ def test_syspurpose_end_to_end( ) +# -------------------------- MULTI-CV SCENARIOS ------------------------- @pytest.mark.rhel_ver_match('[^7]') def test_negative_multi_cv_registration( module_org, @@ -2043,6 +2044,10 @@ def test_negative_multi_cv_registration( :CaseImportance: Critical + :CaseComponent: Hosts-Content + + :team: Phoenix-subscriptions + :parametrized: yes """ @@ -2068,6 +2073,172 @@ def test_negative_multi_cv_registration( ), f'Expecting error "Registering to multiple environments is not enabled"; instead got: {res.stderr}' +@pytest.mark.rhel_ver_match('[^7]') +def test_positive_multi_cv_registration( + session_multicv_sat, + session_multicv_org, + session_multicv_default_ak, + session_multicv_lce, + rhel_contenthost, +): + """Register a host to multiple content view environments. + + :id: d0f78923-cace-4dc4-9936-81fe7e189a6b + + :steps: + 1. Register a host with global reg, just to get the sub-man config and certs right + 2. Unregister the host + 3. Attempt to register the host with subscription-manager, passing multiple environments + 4. Confirm that registration succeeds + 5. Confirm that the host is registered to both environments + + :expectedresults: Registration succeeds and the host is registered to both environments. + + :CaseImportance: Critical + + :CaseComponent: Hosts-Content + + :team: Phoenix-subscriptions + + :parametrized: yes + """ + + library_lce = ( + session_multicv_sat.api.LifecycleEnvironment() + .search(query={'search': f'name=Library and organization_id={session_multicv_org.id}'})[0] + .read() + ) + + # Create a content view + cv1 = session_multicv_sat.api.ContentView(organization=session_multicv_org).create() + cv1.publish() + cv1 = cv1.read() + + # Create a second content view + cv2 = session_multicv_sat.api.ContentView(organization=session_multicv_org).create() + cv2.publish() + cv2 = cv2.read() + cv2_version = cv2.version[0] + cv2_version.promote(data={'environment_ids': session_multicv_lce.id}) + + # Register with global reg, just to get the sub-man config and certs right + result = rhel_contenthost.register( + session_multicv_org, None, session_multicv_default_ak.name, session_multicv_sat + ) + assert result.status == 0 + assert rhel_contenthost.subscribed + + # Unregister the host + unregister_result = rhel_contenthost.unregister() + assert unregister_result.status == 0 + + # Register the host with subscription-manager, passing multiple environments + env_names = f"{library_lce.name}/{cv1.name},{session_multicv_lce.name}/{cv2.name}" + res = rhel_contenthost.register_contenthost( + session_multicv_org.label, lce=None, environments=env_names + ) + + # Confirm that registration succeeds + assert res.status == 0 + assert rhel_contenthost.subscribed + + # Confirm that the host is registered to both environments + host = session_multicv_sat.cli.Host.info({'name': rhel_contenthost.hostname}) + assert ( + len(host['content-information']['content-view-environments']) == 2 + ), "Expected host to be registered to both environments" + + +@pytest.mark.rhel_ver_match('[^7]') +def test_positive_multi_cv_host_repo_availability( + session_multicv_sat, + rhel_contenthost, + session_multicv_org, + session_multicv_default_ak, +): + """Multi-environment hosts should have access to repositories from all of their content view environments. + + :id: 6a15d591-be84-4b5b-8deb-8ea6eb32fee6 + + :setup: + 1. Create two lifecycle environments + 2. Create two synced custom repositories + 3. Create two content views, each with a repo in them, and promote them to their own lifecycle environment + + :steps: + 1. Register a host with global registration to a single content view environment + 2. Assign the host to multiple content view environments + 3. Confirm repos listed in subscription-manager repos match the repos in the content view environments + + :expectedresults: Host sees repositories from both content view environments, not just one. + + :CaseImportance: Critical + + :CaseComponent: Hosts-Content + + :team: Phoenix-subscriptions + + :parametrized: yes + """ + + # Create two lifecycle environments + lce1 = session_multicv_sat.api.LifecycleEnvironment(organization=session_multicv_org).create() + lce2 = session_multicv_sat.api.LifecycleEnvironment(organization=session_multicv_org).create() + + # Create two synced custom repositories + repo_instances = [] + for repo in ['RepoA', 'RepoB']: + repo_id = session_multicv_sat.api_factory.create_sync_custom_repo( + org_id=session_multicv_org.id, + product_name=gen_string('alpha'), + repo_name=repo, + repo_url=settings.repos.fake_repo_zoo3, + ) + repo_instances.append(session_multicv_sat.api.Repository(id=repo_id).read()) + + repo_b = repo_instances.pop() + repo_a = repo_instances.pop() + + # Create two content views, each with a repo in them, and promote them to their own lifecycle environment + + cv1 = session_multicv_sat.api.ContentView( + organization=session_multicv_org, repository=[repo_a] + ).create() + cv1.publish() + cv1 = cv1.read() + + module_published_cvv = cv1.read().version[0] + module_published_cvv.promote(data={'environment_ids': lce1.id}) + + cv2 = session_multicv_sat.api.ContentView( + organization=session_multicv_org, repository=[repo_b] + ).create() + cv2.publish() + cv2_content_view_version = cv2.read().version[0] + cv2_content_view_version.promote(data={'environment_ids': lce2.id}) + + # Register with global registration + result = rhel_contenthost.register( + session_multicv_org, None, session_multicv_default_ak.name, session_multicv_sat + ) + assert result.status == 0 + assert rhel_contenthost.subscribed + + # Assign the host to multiple content view environments with subscription-manager + env_names = f"{lce2.name}/{cv2.name},{lce1.name}/{cv1.name}" + rhel_contenthost.subscription_manager_environments_set(env_names) + + host = session_multicv_sat.cli.Host.info({'name': rhel_contenthost.hostname}) + repos = rhel_contenthost.subscription_manager_list_repos() + # Confirm that the host is registered to both environments + assert ( + len(host['content-information']['content-view-environments']) == 2 + ), "Expected host to be registered to both environments" + # Confirm that the host sees repositories from both content view environments + assert repo_a.label in repos.stdout + assert repo_b.label in repos.stdout + + # -------------------------- HOST ERRATA SUBCOMMAND SCENARIOS ------------------------- @pytest.mark.tier1 def test_positive_errata_list_of_sat_server(target_sat):