This is the journey I had recently. I had intended to write a blog, but I rarely finish those so I decided to write it as a Discourse post instead. You may recognize the writing style reflects that.
My problem is that I have an old Puppet 7 server running on CentOS Stream 8. Both are end of life, but it was OK to leave it for a bit because it’s firewalled. Now that the CA certificate also expired I really need to take action.
My plan is to build a new OpenVox 8 server running on CentOS Stream 10 so I need Foreman Proxy there. Today it’s not built on EL 10 so we need to bootstrap the build environment.
Spoiler: today I can’t fully recreate the buildroot. At the end there are various issues I found.
Allowing Foreman to bootstrap itself
I’m assuming you’re on a supported Fedora version, have a Fedora Account and used fkinit to log into Kerberos. With all of that in place we can move to the Foreman specific parts.
Clone the packaging repository if you haven’t already:
$ git clone https://github.com/theforeman/foreman-packaging -b rpm/develop
Note: at the time of writing this relies on the bootstrap conditional in foreman and related support in obal.
Foreman packaging is largely automated using obal. There are multiple ways of installing it, but I maintain a copr repository which I think is the easiest way. First install obal:
# dnf copr enable ekohl/obal
# dnf install obal
That was all the important set up, so let’s get to the real work.
To build in your own namespace you can use either always pass -e copr_project_user=MyUser every command or locally modify package_manifest.yaml. In the commands below I’ve assumed a local modification so you can copy-paste commands.
The first important part is that we are bootstrapping, which is always awkward because you need a build artifact to build itself.
The Foreman buildroot needs foreman-build to set the right version macros, but that is a subpackage of the foreman package.
With that out of the way we can create the COPR project in bootstrap state:
$ obal copr-project foreman-copr -e bootstrap=true
Now build foreman:
$ obal release foreman
Once that built successfully you reconfigure the project for the final configuration.
$ obal copr-project foreman-copr
Now we can start building all packages. There are 2 ways to go about this:
- Run
obal release --skip-failed-build packagesuntil it all passes - Call various release groups
I’m opting for the latter since it’s faster in runtime. To understand what’s going on it’s important to understand that the package manifest is actually an Ansible inventory file. Each package is a “host” and those “hosts” are in various groups.
For example, packages contains foreman_packages, plugin_packages, foreman_client_packages, katello_packages and foreman_release_packages as children. Those all correlate to the various repositories we have. In turn, foreman_packages has foreman_core_packages, foreman_proxy_packages, foreman_nodejs_packages and foreman_installer_packages as children. And so forth.
We’ll also use --nowait to build all packages within a group in parallel.
$ obal release --nowait ruby_core_packages_tier1
Now it takes quite a while to even submit all of these, let alone build. Once submitted, start watching all builds concurrently:
$ copr list-builds --output-format text-row $USER/foreman-nightly-staging | awk '!/succeeded/ { print $1 }' | xargs copr watch-build
Once it’s complete and it does come up with failures, you should analyze them. The ones I found are described at the end. Otherwise, proceed with building tier 2 is similar to tier 1:
$ obal release --nowait ruby_core_packages_tier2
Similar to the above, you should monitor the builds and once completed, you can kick off another set of builds that can run in parallel:
$ obal release --nowait rails_core_packages hammer_core_packages other_core_packages foreman_nodejs_packages
Once everything is built, you can release the top level to build the final packages:
$ obal release --nowait foreman foreman_installer_packages foreman_proxy_packages
Now you should have built the core repository from scratch. Building the plugins and later Katello repositories are left as an exercise for the reader.
Issues found
Building EL 10
In my initial attempt I started brave and wanted to build on EL 10 so I used RHEL 10 buildroots. I haven’t submitted a PR for this and it’s for another post, but I’ll list some of the issues I found below.
A buildroot needs a foreman-build package, but that’s built from foreman. I’ve modified foreman.spec to introduce an RPM conditional called bootstrap.
This allows calling rpmbuild --with bootstrap to only build the foreman-build and foreman-plugin packages. The packaging PR is still open. It also really benefits from an obal PR that’s also still open.
Once that was in place, I shifted to building dependencies and found issues:
rubygem-nokogiri,rubygem-nokogiriandforeman-bootloadersfail to build on Fedora 42 so I can’t even submit the build. Fix breakages when submitting RPM builds from Fedora by ekohl · Pull Request #12769 · theforeman/foreman-packaging · GitHub has addressed that- nokogiri 1.15.7 fails to build on EL 10. Perhaps the update to 1.17.2 will resolve that
- ipaddress is incompatible with Ruby 3.2. If only they had released Integer Unification for Ruby 2.4.0+ by koic · Pull Request #86 · ipaddress-gem/ipaddress · GitHub somewhere in the past 8 years. Fix ipaddress for Ruby 3.2+ compatibility by ekohl · Pull Request #12771 · theforeman/foreman-packaging · GitHub backports that patch. I wonder how we’ll deal with this in source-only builds
- Some nodejs packages fail to rebuild. I didn’t fully investigate
Building on EL 9 ARM
At this point I shifted my whole effort to just being able to bootstrap a Foreman environment. I still wanted some challenge so I decided to look at building on ARM instead. We used to have Debian builds on ARM, but never had RPMs because we lacked the builders. These days we build on copr which has them. So why not.
I found that several nodejs packages failed to build due to NPM 6+ and the cache was still using the old layout:
- nodejs-babel-plugin-transform-class-properties
- nodejs-babel-preset-env
- nodejs-babel-preset-react
- nodejs-buffer
- nodejs-compression-webpack-plugin
- nodejs-react-bootstrap
- nodejs-react-intl
- nodejs-sass
- nodejs-sass-loader
- nodejs-style-loader
- nodejs-use-deep-compare-effect
- nodejs-webpack-cli
I then had the thought of removing unused nodejs packages because maybe that resolved some of the issues. A first round found a few unused packages but none that failed to build previously. While doing so I also found that the remove script needed a patch for the line width.
Fixing them is relatively easy: regenerate them with npm2rpm in the right environment, but I haven’t done that.
Then I also found that various go packages were skipped because it doesn’t use the OS provided go architectures (PR is open for dynflow-utils and pcp-mmvstatsd. The latter doesn’t build on EL9 x86_64 either and never has. There is also similar work in the client tools repo, but I didn’t touch that because it also builds on SLES which is another can of worms.
Chronological list
The above is a nice write up, but in reality my process was:
- Realize I need to replace my Puppet server
- Realize I need to build Foreman Proxy on EL 10
- Realize I need to set up my own COPR project
- Come to find I need
foreman-build, which is a bootstrap problem - Enhance
foreman.specwith the bootstrap conditional - Enhance obal to provide conditionals during build
- Realize I need Replace pkg_resources with importlib for Python 3.12+ support by ogajduse · Pull Request #411 · theforeman/obal · GitHub to test it
- Fix that building with so open Fix unversioned obsoletes warning from rpmlint by ekohl · Pull Request #417 · theforeman/obal · GitHub & Fix Ansible bool usage by ekohl · Pull Request #418 · theforeman/obal · GitHub
- While that’s building, rebase my own PR to let it build
- Figure out how to use conditionals in COPR builds
- Turns out I don’t need RPM conditionals in obal because COPR is configured at the chroot level. Instead I need an option to configure the chroot
- Iterate on building by manually modifying the chroot via the UI
- Come up with Add copr chroot options for RPM conditionals by ekohl · Pull Request #419 · theforeman/obal · GitHub to reconfigure the chroot
- Come up with Allow bootstrapping foreman-build by ekohl · Pull Request #12768 · theforeman/foreman-packaging · GitHub
- Test bootstrapping from scratch
- Update Allow bootstrapping foreman-build by ekohl · Pull Request #12768 · theforeman/foreman-packaging · GitHub with end to end steps
- Build all packages
- Find out I can’t build some on Fedora so submit Fix breakages when submitting RPM builds from Fedora by ekohl · Pull Request #12769 · theforeman/foreman-packaging · GitHub
- Backport an 8 year old patch to ipaddress because it was never released: Fix ipaddress for Ruby 3.2+ compatibility by ekohl · Pull Request #12771 · theforeman/foreman-packaging · GitHub
- Switch the whole effort to actually attempt to build Foreman on EL9 with ARM because it’s a clearer goal
- Still not fully complete it but decide to write this post anyway