GitOps our Foreman. This is where most of our Foreman configuration lives.
clientConfigure attached systems (this role run everywhere, most the others are specific to the server)contentPut Content into ForemanforemanAdminister and Configure ForemanhostsProvisioning Setup and TemplatesinfrastructureInfrastruturenetwork(This role wrapsrhel.rhel_system_roles.networkso we can use ansible facts for network configuration and is run on all hosts.)
- RaBe Foreman Playbooks : Content View Promote
- RaBe Foreman Playbook : Content View Publish
- RaBe Foreman Playbook : Content View Version Cleanup
The repository includes a hostgroup dumper that reads hostgroup data from Foreman
and writes YAML files into roles/foreman/vars/hostgroups/.
-
Create and activate a Python virtual environment:
python3 -m venv .venv source .venv/bin/activate pip install --upgrade pip pip install ansible ansible-lint ruamel.yaml ansible-galaxy collection install theforeman.foreman -
In the Foreman UI, create a Personal Access Token for your user:
User menu->My Account->Personal Access Tokens->Create tokenSave the token in a secure location, you won't be able to recover it once you close the Foreman UI.
-
Run the dumper with your Foreman username and API token:
export FOREMAN_SERVER_URL="https://foreman.service.int.rabe.ch" export FOREMAN_USERNAME="your-user" export FOREMAN_API_TOKEN="your-personal-access-token" source .venv/bin/activate ansible-playbook \ -e foreman_server_url="$FOREMAN_SERVER_URL" \ -e foreman_username="$FOREMAN_USERNAME" \ -e foreman_password="$FOREMAN_API_TOKEN" \ -e foreman_validate_certs=false \ hack/playbooks/dump_foreman_hostgroups.yml
-
Review changes
The resulting output might need some cleanup in edge cases.
Verify the output using git:
git diff roles/foreman/vars/hostgroups/
Hostgroup files in roles/foreman/vars/hostgroups/ are regular Ansible vars first and
Foreman data second. Jinja2 in those files is therefore rendered by this collection
unless it is escaped on purpose.
If a value must reach Foreman as a literal template for later evaluation on the host, escape the outer expression:
parameters:
- name: cockpit_certificates
parameter_type: yaml
value:
- dns:
- "{{ '{{' }} ansible_host {{ '}}' }}"
principal: "HTTP/{{ '{{' }} ansible_host {{ '}}' }}@INT.RABE.CH"Use plain Jinja2 when resolving the value while applying the hostgroup is acceptable or desired:
parameters:
- name: example
parameter_type: string
value: "{{ radiorabe_base_mail_noreply }}"If the nested value must also stay as a template inside Foreman, escape the whole expression instead:
parameters:
- name: example_runtime_yaml_config
parameter_type: yaml
value:
secret: "{{ '{{' }} example_secret {{ '}}' }}"
- name: example_runtime_b64_config
parameter_type: yaml
value:
secret: "{{ '{{ example_secret | ansible.builtin.b64encode }}' }}"Templates in comments or generated text can use whichever form is more useful for the
resulting data. For example, rendering # {{ ansible_managed }} while applying the
hostgroup is acceptable when Foreman does not need to keep it as a live template.
The hostgroup dumper cannot reliably infer which templates should stay literal in Foreman, so always review dumped files and re-escape values as needed before committing them.
- add the product and repo in
roles/content/tasks/products.yml - if creating a new product, add it in
roles/content/tasks/sync_plans.yml - add the new repo to the corresponding "Base" repo or create a new view in
roles/content/tasks/content_views.yml - if you created a new view add it to
playbooks/content_view_publish.ymlandplaybooks/content_view_promote.yml - disable the new repo in all relevant activation keys or create a new key in
roles/content/tasks/activation_keys.yml- your content views need to be published to Prod for this step! this isn't currently automated
Products are removed once they are not in active use by any content view. Hence deprovisioning a component needs to be done in stages:
- remove the product from
roles/content/tasks/content_views.ymland from the publish and promote playbooks inplaybooks/ - at this stage, there are probably still active users of the old content view so we wait until a new version of the content view is released and they are life cycled
- once there are no more active users, we can stop syncing the product since we don't need updated errata anymore, we remove it from
roles/content/tasks/sync_plans.yml - at this point, there are still old versions of content views that may contain the product. it will take a while until
playbooks/content_view_version_cleanup.ymlremoves them - after checking that there are no more dependencies on the product, they get changed to
state: absentinroles/content/tasks/products.ymlremoving them from our foreman, at this point the list of repositories is also removed from the file - Once they are gone from Foreman they can be removed from this repo with the next major release (or any 0.x release)
This collection is free software: you can redistribute it and/or modify it under the terms of the GNU Affero General Public License as published by the Free Software Foundation, version 3 of the License.