diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 3d62026..060c0f6 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -49,8 +49,10 @@ jobs: run: pip install -r requirements.txt - name: Install collection dependencies run: ansible-galaxy install -r requirements.yml - - name: Start VM - run: vagrant up quadlet + - name: Start VMs + run: | + vagrant up quadlet + vagrant up client - name: Run deployment run: | ansible-playbook playbooks/setup.yaml diff --git a/Vagrantfile b/Vagrantfile index 06a9bcc..82d22cf 100644 --- a/Vagrantfile +++ b/Vagrantfile @@ -14,4 +14,13 @@ Vagrant.configure("2") do |config| provider.vm.box_url = CENTOS_9_BOX_URL end end + + config.vm.define "client" do |override| + override.vm.hostname = "client.example.com" + + override.vm.provider "libvirt" do |libvirt, provider| + libvirt.memory = 1024 + provider.vm.box_url = CENTOS_9_BOX_URL + end + end end diff --git a/playbooks/deploy.yaml b/playbooks/deploy.yaml index 1450e2e..495de02 100644 --- a/playbooks/deploy.yaml +++ b/playbooks/deploy.yaml @@ -1,6 +1,7 @@ --- - name: Setup quadlet demo machine - hosts: all + hosts: + - quadlet become: true vars: certificates_hostnames: diff --git a/playbooks/setup.yaml b/playbooks/setup.yaml index 371bc05..926cf5d 100644 --- a/playbooks/setup.yaml +++ b/playbooks/setup.yaml @@ -1,7 +1,14 @@ --- -- name: Setup quadlet demo machine +- name: Setup basic stuff hosts: all become: true + roles: + - theforeman.forklift.etc_hosts + +- name: Setup quadlet demo machine + hosts: + - quadlet + become: true pre_tasks: - name: Upgrade all packages ansible.builtin.package: # noqa: package-latest diff --git a/requirements.txt b/requirements.txt index 36f7907..b4de63e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,3 @@ pytest-testinfra paramiko +apypie>=0.5.0 diff --git a/requirements.yml b/requirements.yml index c92fd87..809ce19 100644 --- a/requirements.yml +++ b/requirements.yml @@ -6,6 +6,8 @@ collections: - name: containers.podman version: ">=1.14.0" - name: theforeman.foreman + - name: https://github.com/theforeman/forklift + type: git roles: - name: geerlingguy.postgresql diff --git a/roles/foreman/defaults/main.yaml b/roles/foreman/defaults/main.yaml index 748a063..32a31f6 100644 --- a/roles/foreman/defaults/main.yaml +++ b/roles/foreman/defaults/main.yaml @@ -1,3 +1,3 @@ --- foreman_container_image: "quay.io/evgeni/foreman-rpm" -foreman_container_tag: "3.12" +foreman_container_tag: "nightly" diff --git a/tests/client_test.py b/tests/client_test.py new file mode 100644 index 0000000..49b4d0d --- /dev/null +++ b/tests/client_test.py @@ -0,0 +1,10 @@ +def test_foreman_content_view(client_environment, activation_key, organization, foremanapi, client): + client.run('dnf install -y subscription-manager') + rcmd = foremanapi.create('registration_commands', {'organization_id': organization['id'], 'insecure': True, 'activation_keys': [activation_key['name']]}) + client.run_test(rcmd['registration_command']) + client.run('subscription-manager repos --enable=*') + client.run_test('dnf install -y bear') + assert client.package('bear').is_installed + client.run('dnf remove -y bear') + client.run('subscription-manager unregister') + client.run('subscription-manager clean') diff --git a/tests/conftest.py b/tests/conftest.py index 4509fce..0837b13 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,3 +1,7 @@ +import uuid + +import apypie +import paramiko import pytest import testinfra @@ -5,3 +9,93 @@ @pytest.fixture(scope="module") def server(): yield testinfra.get_host('paramiko://quadlet', sudo=True, ssh_config='./.vagrant/ssh-config') + + +@pytest.fixture(scope="module") +def client(): + yield testinfra.get_host('paramiko://client', sudo=True, ssh_config='./.vagrant/ssh-config') + + +@pytest.fixture(scope="module") +def ssh_config(): + config = paramiko.SSHConfig.from_path('./.vagrant/ssh-config') + return config.lookup('quadlet') + + +@pytest.fixture(scope="module") +def foremanapi(ssh_config): + return apypie.ForemanApi( + uri=f'https://{ssh_config['hostname']}', + username='admin', + password='changeme', + verify_ssl=False, + ) + +@pytest.fixture +def organization(foremanapi): + org = foremanapi.create('organizations', {'name': str(uuid.uuid4())}) + yield org + foremanapi.delete('organizations', org) + +@pytest.fixture +def product(organization, foremanapi): + prod = foremanapi.create('products', {'name': str(uuid.uuid4()), 'organization_id': organization['id']}) + yield prod + foremanapi.delete('products', prod) + +@pytest.fixture +def yum_repository(product, organization, foremanapi): + repo = foremanapi.create('repositories', {'name': str(uuid.uuid4()), 'product_id': product['id'], 'content_type': 'yum', 'url': 'https://fixtures.pulpproject.org/rpm-no-comps/'}) + yield repo + foremanapi.delete('repositories', repo) + +@pytest.fixture +def file_repository(product, organization, foremanapi): + repo = foremanapi.create('repositories', {'name': str(uuid.uuid4()), 'product_id': product['id'], 'content_type': 'file', 'url': 'https://fixtures.pulpproject.org/file/'}) + yield repo + foremanapi.delete('repositories', repo) + +@pytest.fixture +def container_repository(product, organization, foremanapi): + repo = foremanapi.create('repositories', {'name': str(uuid.uuid4()), 'product_id': product['id'], 'content_type': 'docker', 'url': 'https://quay.io/', 'docker_upstream_name': 'foreman/busybox-test'}) + yield repo + foremanapi.delete('repositories', repo) + +@pytest.fixture +def lifecycle_environment(organization, foremanapi): + library = foremanapi.list('lifecycle_environments', 'name=Library', {'organization_id': organization['id']})[0] + lce = foremanapi.create('lifecycle_environments', {'name': str(uuid.uuid4()), 'organization_id': organization['id'], 'prior_id': library['id']}) + yield lce + foremanapi.delete('lifecycle_environments', lce) + +@pytest.fixture +def content_view(organization, foremanapi): + cv = foremanapi.create('content_views', {'name': str(uuid.uuid4()), 'organization_id': organization['id']}) + yield cv + foremanapi.delete('content_views', cv) + +@pytest.fixture +def activation_key(organization, foremanapi): + ak = foremanapi.create('activation_keys', {'name': str(uuid.uuid4()), 'organization_id': organization['id']}) + yield ak + foremanapi.delete('activation_keys', ak) + +@pytest.fixture +def client_environment(activation_key, content_view, lifecycle_environment, yum_repository, organization, foremanapi): + foremanapi.resource_action('repositories', 'sync', {'id': yum_repository['id']}) + foremanapi.update('content_views', {'id': content_view['id'], 'repository_ids': [yum_repository['id']]}) + foremanapi.resource_action('content_views', 'publish', {'id': content_view['id']}) + + library = foremanapi.list('lifecycle_environments', 'name=Library', {'organization_id': organization['id']})[0] + foremanapi.update('activation_keys', {'id': activation_key['id'], 'organization_id': organization['id'], 'environment_id': library['id'], 'content_view_id': content_view['id']}) + + yield activation_key + + foremanapi.update('activation_keys', {'id': activation_key['id'], 'organization_id': organization['id'], 'environment_id': None, 'content_view_id': None}) + + versions = foremanapi.list('content_view_versions', params={'content_view_id': content_view['id']}) + for version in versions: + current_environment_ids = {environment['id'] for environment in version['environments']} + for environment_id in current_environment_ids: + foremanapi.resource_action('content_views', 'remove_from_environment', params={'id': content_view['id'], 'environment_id': environment_id}) + foremanapi.delete('content_view_versions', version) diff --git a/tests/foreman_api_test.py b/tests/foreman_api_test.py new file mode 100644 index 0000000..f9b8ef0 --- /dev/null +++ b/tests/foreman_api_test.py @@ -0,0 +1,50 @@ +import urllib.parse + +import requests + + +def _repo_url(repo, ssh_config): + return urllib.parse.urlunparse(urllib.parse.urlparse(repo['full_path'])._replace(netloc=ssh_config['hostname'])) + + +def test_foreman_organization(organization): + assert organization + +def test_foreman_product(product): + assert product + +def test_foreman_yum_repository(yum_repository, foremanapi, ssh_config): + assert yum_repository + foremanapi.resource_action('repositories', 'sync', {'id': yum_repository['id']}) + repo_url = _repo_url(yum_repository, ssh_config) + assert requests.get(f'{repo_url}/repodata/repomd.xml', verify=False) + assert requests.get(f'{repo_url}/Packages/b/bear-4.1-1.noarch.rpm', verify=False) + + +def test_foreman_file_repository(file_repository, foremanapi, ssh_config): + assert file_repository + foremanapi.resource_action('repositories', 'sync', {'id': file_repository['id']}) + repo_url = _repo_url(file_repository, ssh_config) + assert requests.get(f'{repo_url}/1.iso', verify=False) + + +def test_foreman_container_repository(container_repository, foremanapi, ssh_config): + assert container_repository + foremanapi.resource_action('repositories', 'sync', {'id': container_repository['id']}) + + +def test_foreman_lifecycle_environment(lifecycle_environment): + assert lifecycle_environment + + +def test_foreman_content_view(content_view, yum_repository, foremanapi): + assert content_view + foremanapi.update('content_views', {'id': content_view['id'], 'repository_ids': [yum_repository['id']]}) + foremanapi.resource_action('content_views', 'publish', {'id': content_view['id']}) + # do something with the published view + versions = foremanapi.list('content_view_versions', params={'content_view_id': content_view['id']}) + for version in versions: + current_environment_ids = {environment['id'] for environment in version['environments']} + for environment_id in current_environment_ids: + foremanapi.resource_action('content_views', 'remove_from_environment', params={'id': content_view['id'], 'environment_id': environment_id}) + foremanapi.delete('content_view_versions', version)