Testing a foreman-installer patch with Packit and forklift


Today I was working on a potential fix for the issue that Puppetserver doesn’t start when deployed with fapolicyd in enforcing mode.

I knew that the potential fix is to set PrivateTmp=true in the systemd unit, so the patch was quickly written, but how would one verify it end to end?

In Foreman, our releases (and nightlies!) are tested using forklift, a combination of Vagrant for managing VMs and Ansible for deploying Foreman in them and running bats.

We can run the installation pipeline for Foreman nightly on CentOS Stream 8 like this:

% ansible-playbook pipelines/install_pipeline.yml -e pipeline_os=centos8-stream -e pipeline_version=nightly -e pipeline_type=foreman
…
TASK [bats : Run bats] *************************************************************************************************************
changed: [pipe-foreman-server-nightly-centos8-stream] => (item=fb-verify-packages.bats)
changed: [pipe-foreman-server-nightly-centos8-stream] => (item=fb-test-foreman.bats)
changed: [pipe-foreman-server-nightly-centos8-stream] => (item=fb-test-puppet.bats)
changed: [pipe-foreman-server-nightly-centos8-stream] => (item=fb-test-backup.bats)
changed: [pipe-foreman-server-nightly-centos8-stream] => (item=fb-verify-selinux.bats)
…
PLAY RECAP *************************************************************************************************************************
localhost                  : ok=5    changed=2    unreachable=0    failed=0    skipped=5    rescued=0    ignored=0
pipe-foreman-server-nightly-centos8-stream : ok=62   changed=19   unreachable=0    failed=0    skipped=37   rescued=0    ignored=1
pipe-foreman-smoker-nightly-centos8-stream : ok=17   changed=12   unreachable=0    failed=0    skipped=3    rescued=0    ignored=0

As we see, the tests pass and everyone is happy.

We can destroy the setup again, and continue with our tasks:

% ansible-playbook pipelines/install_pipeline.yml -e pipeline_os=centos8-stream -e pipeline_version=nightly -e pipeline_type=foreman -e forklift_state=destroy

The tests passed because we do not deploy fapolicyd by default as the integration is not yet fully ready.

To test the integration, there is a feature flag: foreman_fapolicyd and if we enable it, the overall installation fails as expected:

% ansible-playbook pipelines/install_pipeline.yml -e pipeline_os=centos8-stream -e pipeline_version=nightly -e pipeline_type=foreman -e foreman_fapolicyd=true
…
TASK [foreman_installer : Run installer] *******************************************************************************************
fatal: [pipe-foreman-server-nightly-centos8-stream]: FAILED! => changed=true
…
    Error 1: Puppet Service resource 'puppetserver' failed. Logs:
      /Service[puppetserver]
        Starting to evaluate the resource (993 of 1266)
        Skipping restart; service is not running
        Triggered 'refresh' from 2 events
        The container Class[Puppet::Server::Service] will propagate my refresh event
        Evaluated in 9.75 seconds
      /Stage[main]/Puppet::Server::Service/Service[puppetserver]/ensure
        change from 'stopped' to 'running' failed: Systemd start for puppetserver failed!
    journalctl log for puppetserver:
    -- Logs begin at Fri 2023-11-03 08:53:57 UTC, end at Fri 2023-11-03 09:01:28 UTC. --
    Nov 03 09:01:19 pipe-foreman-server-nightly-centos8-stream.tanso.example.com systemd[1]: Starting puppetserver Service...
    Nov 03 09:01:22 pipe-foreman-server-nightly-centos8-stream.tanso.example.com puppetserver[48125]: WARNING: abs already refers to: #'clojure.core/abs in namespace: medley.core, being replaced by: #'medley.core/abs
    Nov 03 09:01:28 pipe-foreman-server-nightly-centos8-stream.tanso.example.com puppetserver[48125]: Execution error (ClassNotFoundException) at java.net.URLClassLoader/findClass (URLClassLoader.java:387).
    Nov 03 09:01:28 pipe-foreman-server-nightly-centos8-stream.tanso.example.com puppetserver[48125]: org.jruby.ext.psych.PsychLibrary
    Nov 03 09:01:28 pipe-foreman-server-nightly-centos8-stream.tanso.example.com puppetserver[48125]: Full report at:
    Nov 03 09:01:28 pipe-foreman-server-nightly-centos8-stream.tanso.example.com puppetserver[48125]: /tmp/clojure-5697285534509071746.edn
    Nov 03 09:01:28 pipe-foreman-server-nightly-centos8-stream.tanso.example.com puppetserver[48098]: Background process 48125 exited before start had completed
    Nov 03 09:01:28 pipe-foreman-server-nightly-centos8-stream.tanso.example.com systemd[1]: puppetserver.service: Control process exited, code=exited status=1
    Nov 03 09:01:28 pipe-foreman-server-nightly-centos8-stream.tanso.example.com systemd[1]: puppetserver.service: Failed with result 'exit-code'.
    Nov 03 09:01:28 pipe-foreman-server-nightly-centos8-stream.tanso.example.com systemd[1]: Failed to start puppetserver Service.

    1 error was detected during installation.
    Please address the errors and re-run the installer to ensure the system is properly configured.
    Failing to do so is likely to result in broken functionality.

    The full log is at /var/log/foreman-installer/foreman.log
  stdout_lines: <omitted>

PLAY RECAP *************************************************************************************************************************
localhost                  : ok=5    changed=2    unreachable=0    failed=0    skipped=5    rescued=0    ignored=0
pipe-foreman-server-nightly-centos8-stream : ok=47   changed=12   unreachable=0    failed=1    skipped=28   rescued=0    ignored=1

Now that we know that we can reproduce the reported issue, let’s try to deploy the fix and see if it actually fixes things.

The patch is against our Puppet module that is responsible for deploying the Puppetserver, but our installation procedure doesn’t call Puppet directly, it uses foreman-installer which under the hood uses Puppet. So to test the fix we need to build foreman-installer with the patched module and deploy the result during the installation pipeline, before Ansible calls the installer.

This sounds tedious and error prone, but luckily we have Packit integration in our foreman-installer repository and in forklift. That means that we need to create a PR against the installer repository, temporarily pointing at the patched Puppet module and once Packit has built the package can instruct forklift to use that Packit repository during deployment, validating the fix:

% ansible-playbook pipelines/install_pipeline.yml -e pipeline_os=centos8-stream -e pipeline_version=nightly -e pipeline_type=foreman -e foreman_fapolicyd=true -e '{"packit_prs":["theforeman/foreman-installer/897"]}'
…
TASK [packit : setup packit copr] **************************************************************************************************
changed: [pipe-foreman-server-nightly-centos8-stream] => (item=theforeman/foreman-installer/897)
…
TASK [bats : Run bats] *************************************************************************************************************
changed: [pipe-foreman-server-nightly-centos8-stream] => (item=fb-verify-packages.bats)
changed: [pipe-foreman-server-nightly-centos8-stream] => (item=fb-test-foreman.bats)
changed: [pipe-foreman-server-nightly-centos8-stream] => (item=fb-test-puppet.bats)
changed: [pipe-foreman-server-nightly-centos8-stream] => (item=fb-test-backup.bats)
changed: [pipe-foreman-server-nightly-centos8-stream] => (item=fb-verify-selinux.bats)

And this is the story of how I could validate the fix while drinking a coffee instead of thinking how to inject the manually built package at the right time into the automated installation test.


Comments from the community:


Foreman 3.12.0 has been released! Follow the quick start to install it.

Foreman 3.11.2 has been released! Follow the quick start to install it.