From 2c0c46805dea95edf0f846f003c5316c12db1171 Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Tue, 18 Nov 2025 16:10:04 +0100 Subject: [PATCH 01/17] make proxy feature enablement easier --- src/roles/foreman_proxy/defaults/main.yaml | 3 +++ src/roles/foreman_proxy/tasks/configs.yaml | 8 -------- src/roles/foreman_proxy/tasks/feature.yaml | 20 ++++++++++++++++++++ src/roles/foreman_proxy/tasks/main.yaml | 15 ++++++++++++++- 4 files changed, 37 insertions(+), 9 deletions(-) create mode 100644 src/roles/foreman_proxy/tasks/feature.yaml diff --git a/src/roles/foreman_proxy/defaults/main.yaml b/src/roles/foreman_proxy/defaults/main.yaml index 4e4a4fe2..be9c996c 100644 --- a/src/roles/foreman_proxy/defaults/main.yaml +++ b/src/roles/foreman_proxy/defaults/main.yaml @@ -6,3 +6,6 @@ foreman_proxy_url: "https://{{ foreman_proxy_name }}:{{ foreman_proxy_https_port # Settings foreman_proxy_trusted_hosts: - "{{ foreman_proxy_name }}" + +foreman_proxy_features: + - logs diff --git a/src/roles/foreman_proxy/tasks/configs.yaml b/src/roles/foreman_proxy/tasks/configs.yaml index 568cfd78..0ccffe02 100644 --- a/src/roles/foreman_proxy/tasks/configs.yaml +++ b/src/roles/foreman_proxy/tasks/configs.yaml @@ -6,11 +6,3 @@ data: "{{ lookup('ansible.builtin.template', 'settings.yml.j2') }}" notify: - Restart Foreman Proxy - -- name: Create logs config secret - containers.podman.podman_secret: - state: present - name: foreman-proxy-logs-yml - data: "{{ lookup('ansible.builtin.template', 'settings.d/logs.yml.j2') }}" - notify: - - Restart Foreman Proxy diff --git a/src/roles/foreman_proxy/tasks/feature.yaml b/src/roles/foreman_proxy/tasks/feature.yaml new file mode 100644 index 00000000..8e06e37b --- /dev/null +++ b/src/roles/foreman_proxy/tasks/feature.yaml @@ -0,0 +1,20 @@ +--- +- name: Create config secret for {{ feature_name }} + containers.podman.podman_secret: + state: present + name: foreman-proxy-{{ feature_name }}-yml + data: "{{ lookup('ansible.builtin.template', 'settings.d/' + feature_name + '.yml.j2') }}" + notify: + - Restart Foreman Proxy + +- name: Mount config secret for {{ feature_name }} + ansible.builtin.copy: + dest: /etc/containers/systemd/foreman-proxy.container.d/{{ feature_name }}.conf + content: | + [Container] + Secret=foreman-proxy-{{ feature_name }}-yml,type=mount,target=/etc/foreman-proxy/settings.d/{{ feature_name }}.yml + mode: '0644' + owner: root + group: root + notify: + - Restart Foreman Proxy diff --git a/src/roles/foreman_proxy/tasks/main.yaml b/src/roles/foreman_proxy/tasks/main.yaml index 47eaff73..0ec20bf4 100644 --- a/src/roles/foreman_proxy/tasks/main.yaml +++ b/src/roles/foreman_proxy/tasks/main.yaml @@ -20,7 +20,6 @@ hostname: "{{ ansible_facts['fqdn'] }}" secrets: - 'foreman-proxy-settings-yml,type=mount,target=/etc/foreman-proxy/settings.yml' - - 'foreman-proxy-logs-yml,type=mount,target=/etc/foreman-proxy/settings.d/logs.yml' - 'foreman-proxy-ssl-ca,type=mount,target=/etc/foreman-proxy/ssl_ca.pem' - 'foreman-proxy-ssl-cert,type=mount,target=/etc/foreman-proxy/ssl_cert.pem' - 'foreman-proxy-ssl-key,type=mount,target=/etc/foreman-proxy/ssl_key.pem' @@ -35,6 +34,20 @@ PartOf=foreman.target notify: Restart Foreman Proxy +- name: Create foreman-proxy.container.d folder + ansible.builtin.file: + path: /etc/containers/systemd/foreman-proxy.container.d + state: directory + mode: '0755' + owner: 'root' + group: 'root' + +- name: Configure features + ansible.builtin.include_tasks: feature.yaml + loop: "{{ foreman_proxy_features }}" + loop_control: + loop_var: feature_name + - name: Run daemon reload to make Quadlet create the service files ansible.builtin.systemd: daemon_reload: true From 77d7d6b1624145115c43623d509e094c85b58d11 Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Wed, 19 Nov 2025 08:48:06 +0100 Subject: [PATCH 02/17] add rex feature --- src/roles/foreman_proxy/defaults/main.yaml | 1 + .../settings.d/remote_execution_ssh.yml.j2 | 46 +++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 src/roles/foreman_proxy/templates/settings.d/remote_execution_ssh.yml.j2 diff --git a/src/roles/foreman_proxy/defaults/main.yaml b/src/roles/foreman_proxy/defaults/main.yaml index be9c996c..db9a25a5 100644 --- a/src/roles/foreman_proxy/defaults/main.yaml +++ b/src/roles/foreman_proxy/defaults/main.yaml @@ -9,3 +9,4 @@ foreman_proxy_trusted_hosts: foreman_proxy_features: - logs + - remote_execution_ssh diff --git a/src/roles/foreman_proxy/templates/settings.d/remote_execution_ssh.yml.j2 b/src/roles/foreman_proxy/templates/settings.d/remote_execution_ssh.yml.j2 new file mode 100644 index 00000000..be09478d --- /dev/null +++ b/src/roles/foreman_proxy/templates/settings.d/remote_execution_ssh.yml.j2 @@ -0,0 +1,46 @@ +--- +:enabled: true +:ssh_identity_key_file: '~/.ssh/id_rsa_foreman_proxy' +:local_working_dir: '/var/tmp' +:remote_working_dir: '/var/tmp' +:socket_working_dir: '/var/tmp' +# :kerberos_auth: false + +# :cockpit_integration: true + +# Mode of operation, one of ssh, pull, pull-mqtt +:mode: ssh + +# Enables the use of SSH certificate for smart proxy authentication +# The file should contain an SSH CA public key that the SSH public key of smart proxy is signed by +# :ssh_user_ca_public_key_file: + +# Enables the use of SSH host certificates for host authentication +# The file should contain a list of trusted SSH CA authorities that the host certs can be signed by +# Example file content: @cert-authority * +# :ssh_ca_known_hosts_file: + +# Defines how often (in seconds) should the runner check +# for new data leave empty to use the runner's default +# :runner_refresh_interval: 1 + +# Defines the verbosity of logging coming from ssh command +# one of :debug, :info, :error, :fatal +# must be lower than general log level +# :ssh_log_level: error + +# Remove working directories on job completion +# :cleanup_working_dirs: true + +# MQTT configuration, need to be set if mode is set to pull-mqtt +# :mqtt_broker: localhost +# :mqtt_port: 1883 + +# Use of SSL can be forced either way by explicitly setting mqtt_tls setting. If +# unset, SSL gets used if smart-proxy's foreman_ssl_cert, foreman_ssl_key and +# foreman_ssl_ca settings are set available. +# :mqtt_tls: + +# The notification is sent over mqtt every $mqtt_resend_interval seconds, until +# the job is picked up by the host or cancelled +# :mqtt_resend_interval: 900 From b537ee69b37c8722872a39e74121426c4eb13556 Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Thu, 26 Feb 2026 13:00:19 +0100 Subject: [PATCH 03/17] require fam 5.9.0+ for refresh module --- src/requirements.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/requirements.yml b/src/requirements.yml index 1587cb83..97712608 100644 --- a/src/requirements.yml +++ b/src/requirements.yml @@ -6,3 +6,4 @@ collections: - name: containers.podman version: ">=1.16.4" - name: theforeman.foreman + version: ">=5.9.0" From c427041c735d3425083b7cd4e651e8fc087ccba9 Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Wed, 19 Nov 2025 11:19:44 +0100 Subject: [PATCH 04/17] refresh proxy features --- src/roles/foreman_proxy/handlers/main.yml | 8 ++++++++ src/roles/foreman_proxy/tasks/feature.yaml | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/roles/foreman_proxy/handlers/main.yml b/src/roles/foreman_proxy/handlers/main.yml index 6cea8a88..95161a88 100644 --- a/src/roles/foreman_proxy/handlers/main.yml +++ b/src/roles/foreman_proxy/handlers/main.yml @@ -3,3 +3,11 @@ ansible.builtin.systemd: name: foreman-proxy state: restarted + +- name: Refresh Foreman Proxy + theforeman.foreman.smart_proxy_refresh: + smart_proxy: "{{ foreman_proxy_name }}" + server_url: "{{ foreman_url }}" + username: "{{ foreman_initial_admin_username }}" + password: "{{ foreman_initial_admin_password }}" + validate_certs: false diff --git a/src/roles/foreman_proxy/tasks/feature.yaml b/src/roles/foreman_proxy/tasks/feature.yaml index 8e06e37b..6b8ecc1a 100644 --- a/src/roles/foreman_proxy/tasks/feature.yaml +++ b/src/roles/foreman_proxy/tasks/feature.yaml @@ -6,6 +6,7 @@ data: "{{ lookup('ansible.builtin.template', 'settings.d/' + feature_name + '.yml.j2') }}" notify: - Restart Foreman Proxy + - Refresh Foreman Proxy - name: Mount config secret for {{ feature_name }} ansible.builtin.copy: @@ -18,3 +19,4 @@ group: root notify: - Restart Foreman Proxy + - Refresh Foreman Proxy From 68f9d7d201e00b701e8123d21c6d9daf1d620408 Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Wed, 19 Nov 2025 12:07:02 +0100 Subject: [PATCH 05/17] make it possible to add per-feature tasks --- src/roles/foreman_proxy/tasks/feature.yaml | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/roles/foreman_proxy/tasks/feature.yaml b/src/roles/foreman_proxy/tasks/feature.yaml index 6b8ecc1a..3fa45812 100644 --- a/src/roles/foreman_proxy/tasks/feature.yaml +++ b/src/roles/foreman_proxy/tasks/feature.yaml @@ -20,3 +20,11 @@ notify: - Restart Foreman Proxy - Refresh Foreman Proxy + +- name: Include additional tasks for {{ feature_name }} + ansible.builtin.include_tasks: '{{ tasks_file }}' + when: + - tasks_file is not none + - tasks_file != "" + vars: + tasks_file: "{{ lookup('ansible.builtin.first_found', files=['feature/' + feature_name + '.yaml'], errors='ignore') }}" From 7d936ac7bc4e42c01549355e03749fdbd60ae588 Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Wed, 19 Nov 2025 12:20:51 +0100 Subject: [PATCH 06/17] add rex ssh feature setup --- .../tasks/feature/remote_execution_ssh.yaml | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/roles/foreman_proxy/tasks/feature/remote_execution_ssh.yaml diff --git a/src/roles/foreman_proxy/tasks/feature/remote_execution_ssh.yaml b/src/roles/foreman_proxy/tasks/feature/remote_execution_ssh.yaml new file mode 100644 index 00000000..66b74640 --- /dev/null +++ b/src/roles/foreman_proxy/tasks/feature/remote_execution_ssh.yaml @@ -0,0 +1,36 @@ +--- +- name: Create SSH Key + community.crypto.openssh_keypair: + path: /root/foreman-proxy-ssh + +- name: Create SSH Key podman secret + containers.podman.podman_secret: + state: present + name: foreman-proxy-remote_execution_ssh-ssh-key + path: /root/foreman-proxy-ssh + notify: + - Restart Foreman Proxy + - Refresh Foreman Proxy + +- name: Create SSH Pub podman secret + containers.podman.podman_secret: + state: present + name: foreman-proxy-remote_execution_ssh-ssh-pub + path: /root/foreman-proxy-ssh.pub + notify: + - Restart Foreman Proxy + - Refresh Foreman Proxy + +- name: Mount SSH secrets + ansible.builtin.copy: + dest: /etc/containers/systemd/foreman-proxy.container.d/remote_execution_ssh-keys.conf + content: | + [Container] + Secret=foreman-proxy-remote_execution_ssh-ssh-key,type=mount,target=/usr/share/foreman-proxy/.ssh/id_rsa_foreman_proxy + Secret=foreman-proxy-remote_execution_ssh-ssh-pub,type=mount,target=/usr/share/foreman-proxy/.ssh/id_rsa_foreman_proxy.pub + mode: '0644' + owner: root + group: root + notify: + - Restart Foreman Proxy + - Refresh Foreman Proxy From d4d9bb53bd06d5648a090823b6521b4ae4915a6e Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Wed, 19 Nov 2025 13:51:31 +0100 Subject: [PATCH 07/17] assert script feature and test rex --- tests/client_test.py | 11 ++++++++++- tests/foreman_proxy_test.py | 2 ++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/client_test.py b/tests/client_test.py index 49b4d0da..b753a683 100644 --- a/tests/client_test.py +++ b/tests/client_test.py @@ -1,6 +1,6 @@ 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']]}) + rcmd = foremanapi.create('registration_commands', {'organization_id': organization['id'], 'insecure': True, 'activation_keys': [activation_key['name']], 'force': True}) client.run_test(rcmd['registration_command']) client.run('subscription-manager repos --enable=*') client.run_test('dnf install -y bear') @@ -8,3 +8,12 @@ def test_foreman_content_view(client_environment, activation_key, organization, client.run('dnf remove -y bear') client.run('subscription-manager unregister') client.run('subscription-manager clean') + +def test_foreman_rex(client_environment, activation_key, organization, foremanapi, client, client_fqdn): + client.run('dnf install -y subscription-manager') + rcmd = foremanapi.create('registration_commands', {'organization_id': organization['id'], 'insecure': True, 'activation_keys': [activation_key['name']], 'force': True}) + client.run_test(rcmd['registration_command']) + job = foremanapi.create('job_invocations', {'feature': 'run_script', 'inputs': {'command': 'uptime'}, 'search_query': f'name = {client_fqdn}', 'targeting_type': 'static_query'}) + task = foremanapi.wait_for_task(job['task']) + assert task['result'] == 'success' + foremanapi.delete('hosts', {'id': client_fqdn}) diff --git a/tests/foreman_proxy_test.py b/tests/foreman_proxy_test.py index 840372ad..de7ffeac 100644 --- a/tests/foreman_proxy_test.py +++ b/tests/foreman_proxy_test.py @@ -7,6 +7,8 @@ def test_foreman_proxy_features(server, certificates, server_fqdn): assert cmd.succeeded features = json.loads(cmd.stdout) assert "logs" in features + assert "script" in features + assert "dynflow" in features def test_foreman_proxy_service(server): foreman_proxy = server.service("foreman-proxy") From 8ba26b07d87434abf74d1c1be1217e92e1053f25 Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Thu, 20 Nov 2025 09:03:07 +0100 Subject: [PATCH 08/17] [temp] flush handlers after registration this is suboptimal, as it means we do an additional restart, but it ensures the refresh works --- src/roles/foreman_proxy/tasks/main.yaml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/roles/foreman_proxy/tasks/main.yaml b/src/roles/foreman_proxy/tasks/main.yaml index 0ec20bf4..6b29f60e 100644 --- a/src/roles/foreman_proxy/tasks/main.yaml +++ b/src/roles/foreman_proxy/tasks/main.yaml @@ -52,9 +52,6 @@ ansible.builtin.systemd: daemon_reload: true -- name: Flush handlers to restart services - ansible.builtin.meta: flush_handlers - - name: Start the Foreman Proxy Service ansible.builtin.systemd: name: foreman-proxy @@ -68,3 +65,6 @@ username: "{{ foreman_initial_admin_username }}" password: "{{ foreman_initial_admin_password }}" validate_certs: false + +- name: Flush handlers to restart services + ansible.builtin.meta: flush_handlers From b997373f95395384c8700ec41cdb9607ce200cf4 Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Tue, 2 Dec 2025 13:04:02 +0100 Subject: [PATCH 09/17] add a default for foreman_plugins --- src/roles/foreman/defaults/main.yaml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/roles/foreman/defaults/main.yaml b/src/roles/foreman/defaults/main.yaml index 43e60584..9229c018 100644 --- a/src/roles/foreman/defaults/main.yaml +++ b/src/roles/foreman/defaults/main.yaml @@ -37,3 +37,5 @@ foreman_recurring_tasks: - instance: monthly rake: "cron:monthly" schedule: "monthly" + +foreman_plugins: [] From c366103b44dda2ed2d30788a402ffb72870380a1 Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Tue, 2 Dec 2025 12:08:24 +0100 Subject: [PATCH 10/17] add trivial feature to plugin mapping --- src/ansible.cfg | 1 + src/filter_plugins/foremanctl.py | 35 ++++++++++++++++++++++++++++++++ src/vars/base.yaml | 2 +- 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/filter_plugins/foremanctl.py diff --git a/src/ansible.cfg b/src/ansible.cfg index ae2058d1..e27074e0 100644 --- a/src/ansible.cfg +++ b/src/ansible.cfg @@ -1,4 +1,5 @@ [defaults] host_key_checking = False roles_path = ./roles +filter_plugins = ./filter_plugins callback_result_format = yaml diff --git a/src/filter_plugins/foremanctl.py b/src/filter_plugins/foremanctl.py new file mode 100644 index 00000000..9eb3d497 --- /dev/null +++ b/src/filter_plugins/foremanctl.py @@ -0,0 +1,35 @@ +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + +BASE_FEATURES = ['hammer', 'foreman-proxy', 'foreman'] + +FEATURE_MAP = { + 'katello': { + 'foreman': 'katello', + 'foreman_proxy': None + }, + 'remote_execution': { + 'foreman': 'foreman_remote_execution', + 'foreman_proxy': 'remote_execution_ssh' + } +} + + +def foreman_plugins(value): + plugins = [FEATURE_MAP.get(feature, {}).get('foreman') for feature in value if feature not in BASE_FEATURES] + return [plugin for plugin in plugins if plugin is not None] + + +def foreman_proxy_plugins(value): + plugins = [FEATURE_MAP.get(feature, {}).get('foreman_proxy') for feature in value if feature not in BASE_FEATURES] + return [plugin for plugin in plugins if plugin is not None] + + +class FilterModule(object): + ''' foremanctl filters''' + + def filters(self): + return { + 'features_to_foreman_plugins': foreman_plugins, + 'features_to_foreman_proxy_plugins': foreman_proxy_plugins, + } diff --git a/src/vars/base.yaml b/src/vars/base.yaml index 32c6f2c3..334f8ac1 100644 --- a/src/vars/base.yaml +++ b/src/vars/base.yaml @@ -20,7 +20,7 @@ foreman_client_key: "{{ client_key }}" foreman_client_certificate: "{{ client_certificate }}" foreman_oauth_consumer_key: abcdefghijklmnopqrstuvwxyz123456 foreman_oauth_consumer_secret: abcdefghijklmnopqrstuvwxyz123456 -foreman_plugins: "{{ enabled_features | reject('contains', 'content/') | difference(['hammer', 'foreman-proxy', 'foreman']) }}" +foreman_plugins: "{{ enabled_features | reject('contains', 'content/') | features_to_foreman_plugins }}" foreman_url: "https://{{ ansible_facts['fqdn'] }}" httpd_server_ca_certificate: "{{ server_ca_certificate }}" From f8d0261ce84a939993aacf00ad9f585c1a688959 Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Tue, 2 Dec 2025 13:43:32 +0100 Subject: [PATCH 11/17] map proxy features --- src/roles/foreman_proxy/defaults/main.yaml | 5 +++-- src/vars/base.yaml | 2 ++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/roles/foreman_proxy/defaults/main.yaml b/src/roles/foreman_proxy/defaults/main.yaml index db9a25a5..1b823e14 100644 --- a/src/roles/foreman_proxy/defaults/main.yaml +++ b/src/roles/foreman_proxy/defaults/main.yaml @@ -7,6 +7,7 @@ foreman_proxy_url: "https://{{ foreman_proxy_name }}:{{ foreman_proxy_https_port foreman_proxy_trusted_hosts: - "{{ foreman_proxy_name }}" -foreman_proxy_features: +foreman_proxy_base_feautures: - logs - - remote_execution_ssh +foreman_proxy_plugins: [] +foreman_proxy_features: "{{ foreman_proxy_base_feautures + foreman_proxy_plugins }}" diff --git a/src/vars/base.yaml b/src/vars/base.yaml index 334f8ac1..e4374f38 100644 --- a/src/vars/base.yaml +++ b/src/vars/base.yaml @@ -34,3 +34,5 @@ pulp_plugins: "{{ enabled_features | select('contains', 'content/') | map('repla hammer_ca_certificate: "{{ server_ca_certificate }}" hammer_plugins: "{{ foreman_plugins | map('replace', 'foreman-tasks', 'foreman_tasks') | list }}" + +foreman_proxy_plugins: "{{ enabled_features | reject('contains', 'content/') | features_to_foreman_proxy_plugins }}" From 1e069725bc3ff1bdb464a1e8dbf50e07e2e7049c Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Tue, 2 Dec 2025 14:10:40 +0100 Subject: [PATCH 12/17] explicitly enable rex --- .github/workflows/test.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5fac2f81..5d54c023 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -117,9 +117,9 @@ jobs: - name: Add optional feature - foreman-proxy run: | ./foremanctl deploy --add-feature foreman-proxy - - name: Add optional feature - foreman_azure_rm and foreman_google + - name: Add optional features - azure_rm, google and remote_execution run: | - ./foremanctl deploy --add-feature foreman_azure_rm --add-feature foreman_google + ./foremanctl deploy --add-feature foreman_azure_rm --add-feature foreman_google --add-feature remote_execution - name: Run tests run: | ./forge test --pytest-args="--certificate-source=${{ matrix.certificate_source }} --database-mode=${{ matrix.database }}" @@ -226,9 +226,9 @@ jobs: - name: Add optional feature - foreman-proxy run: | ./foremanctl deploy --add-feature foreman-proxy - - name: Add optional feature - foreman_azure_rm and foreman_google + - name: Add optional features - azure_rm, google and remote_execution run: | - ./foremanctl deploy --add-feature foreman_azure_rm --add-feature foreman_google + ./foremanctl deploy --add-feature foreman_azure_rm --add-feature foreman_google --add-feature remote_execution - name: Stop services run: vagrant ssh quadlet -- sudo systemctl stop foreman.target From 6a336936ec054fdaf8ca5bf0a537ee25f82cc012 Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Tue, 2 Dec 2025 15:15:36 +0100 Subject: [PATCH 13/17] allow disabling proxy features --- src/roles/foreman_proxy/defaults/main.yaml | 3 +++ src/roles/foreman_proxy/tasks/feature.yaml | 1 + src/roles/foreman_proxy/tasks/main.yaml | 10 ++++++++++ .../foreman_proxy/templates/settings.d/logs.yml.j2 | 2 +- .../templates/settings.d/remote_execution_ssh.yml.j2 | 2 +- 5 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/roles/foreman_proxy/defaults/main.yaml b/src/roles/foreman_proxy/defaults/main.yaml index 1b823e14..c02007a6 100644 --- a/src/roles/foreman_proxy/defaults/main.yaml +++ b/src/roles/foreman_proxy/defaults/main.yaml @@ -7,7 +7,10 @@ foreman_proxy_url: "https://{{ foreman_proxy_name }}:{{ foreman_proxy_https_port foreman_proxy_trusted_hosts: - "{{ foreman_proxy_name }}" +foreman_proxy_known_feautures: + - remote_execution_ssh foreman_proxy_base_feautures: - logs foreman_proxy_plugins: [] foreman_proxy_features: "{{ foreman_proxy_base_feautures + foreman_proxy_plugins }}" +foreman_proxy_disabled_features: "{{ foreman_proxy_known_feautures | difference(foreman_proxy_features) }}" diff --git a/src/roles/foreman_proxy/tasks/feature.yaml b/src/roles/foreman_proxy/tasks/feature.yaml index 3fa45812..b1d40c1c 100644 --- a/src/roles/foreman_proxy/tasks/feature.yaml +++ b/src/roles/foreman_proxy/tasks/feature.yaml @@ -24,6 +24,7 @@ - name: Include additional tasks for {{ feature_name }} ansible.builtin.include_tasks: '{{ tasks_file }}' when: + - feature_enabled != "false" - tasks_file is not none - tasks_file != "" vars: diff --git a/src/roles/foreman_proxy/tasks/main.yaml b/src/roles/foreman_proxy/tasks/main.yaml index 6b29f60e..2aa3292d 100644 --- a/src/roles/foreman_proxy/tasks/main.yaml +++ b/src/roles/foreman_proxy/tasks/main.yaml @@ -44,10 +44,20 @@ - name: Configure features ansible.builtin.include_tasks: feature.yaml + vars: + feature_enabled: "true" loop: "{{ foreman_proxy_features }}" loop_control: loop_var: feature_name +- name: Disable features + ansible.builtin.include_tasks: feature.yaml + vars: + feature_enabled: "false" + loop: "{{ foreman_proxy_disabled_features }}" + loop_control: + loop_var: feature_name + - name: Run daemon reload to make Quadlet create the service files ansible.builtin.systemd: daemon_reload: true diff --git a/src/roles/foreman_proxy/templates/settings.d/logs.yml.j2 b/src/roles/foreman_proxy/templates/settings.d/logs.yml.j2 index cdbc714d..dfcc456c 100644 --- a/src/roles/foreman_proxy/templates/settings.d/logs.yml.j2 +++ b/src/roles/foreman_proxy/templates/settings.d/logs.yml.j2 @@ -1,2 +1,2 @@ --- -:enabled: https +:enabled: {{ feature_enabled }} diff --git a/src/roles/foreman_proxy/templates/settings.d/remote_execution_ssh.yml.j2 b/src/roles/foreman_proxy/templates/settings.d/remote_execution_ssh.yml.j2 index be09478d..76ad3445 100644 --- a/src/roles/foreman_proxy/templates/settings.d/remote_execution_ssh.yml.j2 +++ b/src/roles/foreman_proxy/templates/settings.d/remote_execution_ssh.yml.j2 @@ -1,5 +1,5 @@ --- -:enabled: true +:enabled: {{ feature_enabled }} :ssh_identity_key_file: '~/.ssh/id_rsa_foreman_proxy' :local_working_dir: '/var/tmp' :remote_working_dir: '/var/tmp' From 0a0f333abc7db1678818a60b7184999f16cd28ff Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Mon, 12 Jan 2026 14:46:10 +0100 Subject: [PATCH 14/17] map azure and google features --- .github/workflows/test.yml | 4 ++-- src/filter_plugins/foremanctl.py | 8 ++++++++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5d54c023..1b7aa3d7 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -119,7 +119,7 @@ jobs: ./foremanctl deploy --add-feature foreman-proxy - name: Add optional features - azure_rm, google and remote_execution run: | - ./foremanctl deploy --add-feature foreman_azure_rm --add-feature foreman_google --add-feature remote_execution + ./foremanctl deploy --add-feature azure_rm --add-feature google --add-feature remote_execution - name: Run tests run: | ./forge test --pytest-args="--certificate-source=${{ matrix.certificate_source }} --database-mode=${{ matrix.database }}" @@ -228,7 +228,7 @@ jobs: ./foremanctl deploy --add-feature foreman-proxy - name: Add optional features - azure_rm, google and remote_execution run: | - ./foremanctl deploy --add-feature foreman_azure_rm --add-feature foreman_google --add-feature remote_execution + ./foremanctl deploy --add-feature azure_rm --add-feature google --add-feature remote_execution - name: Stop services run: vagrant ssh quadlet -- sudo systemctl stop foreman.target diff --git a/src/filter_plugins/foremanctl.py b/src/filter_plugins/foremanctl.py index 9eb3d497..742588a0 100644 --- a/src/filter_plugins/foremanctl.py +++ b/src/filter_plugins/foremanctl.py @@ -11,6 +11,14 @@ 'remote_execution': { 'foreman': 'foreman_remote_execution', 'foreman_proxy': 'remote_execution_ssh' + }, + 'google': { + 'foreman': 'foreman_google', + 'foreman_proxy': None + }, + 'azure_rm': { + 'foreman': 'foreman_azure_rm', + 'foreman_proxy': None } } From d53b3e182e9eb3c4072097e06455a980f2a9f0ea Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Thu, 12 Feb 2026 15:31:32 +0100 Subject: [PATCH 15/17] dependencies --- src/filter_plugins/foremanctl.py | 14 +++++++++++--- .../templates/settings.d/dynflow.yml.j2 | 10 ++++++++++ 2 files changed, 21 insertions(+), 3 deletions(-) create mode 100644 src/roles/foreman_proxy/templates/settings.d/dynflow.yml.j2 diff --git a/src/filter_plugins/foremanctl.py b/src/filter_plugins/foremanctl.py index 742588a0..7ac45eee 100644 --- a/src/filter_plugins/foremanctl.py +++ b/src/filter_plugins/foremanctl.py @@ -10,7 +10,11 @@ }, 'remote_execution': { 'foreman': 'foreman_remote_execution', - 'foreman_proxy': 'remote_execution_ssh' + 'foreman_proxy': 'remote_execution_ssh', + 'dependencies': ['dynflow'] + }, + 'dynflow': { + 'foreman_proxy': 'dynflow' }, 'google': { 'foreman': 'foreman_google', @@ -24,12 +28,16 @@ def foreman_plugins(value): - plugins = [FEATURE_MAP.get(feature, {}).get('foreman') for feature in value if feature not in BASE_FEATURES] + dependencies = [FEATURE_MAP.get(feature, {}).get('dependencies', []) for feature in value if feature not in BASE_FEATURES] + dependencies = list(set([dep for deplist in dependencies for dep in deplist])) + plugins = [FEATURE_MAP.get(feature, {}).get('foreman') for feature in (value + dependencies) if feature not in BASE_FEATURES] return [plugin for plugin in plugins if plugin is not None] def foreman_proxy_plugins(value): - plugins = [FEATURE_MAP.get(feature, {}).get('foreman_proxy') for feature in value if feature not in BASE_FEATURES] + dependencies = [FEATURE_MAP.get(feature, {}).get('dependencies', []) for feature in value if feature not in BASE_FEATURES] + dependencies = list(set([dep for deplist in dependencies for dep in deplist])) + plugins = [FEATURE_MAP.get(feature, {}).get('foreman_proxy') for feature in (value + dependencies) if feature not in BASE_FEATURES] return [plugin for plugin in plugins if plugin is not None] diff --git a/src/roles/foreman_proxy/templates/settings.d/dynflow.yml.j2 b/src/roles/foreman_proxy/templates/settings.d/dynflow.yml.j2 new file mode 100644 index 00000000..6bacaf20 --- /dev/null +++ b/src/roles/foreman_proxy/templates/settings.d/dynflow.yml.j2 @@ -0,0 +1,10 @@ +--- +:enabled: {{ feature_enabled }} +:database: + +# Require a valid cert to access Dynflow console +# :console_auth: true + +# Maximum age of execution plans to keep before having them cleaned +# by the execution plan cleaner (in seconds), defaults to 30 minutes +# :execution_plan_cleaner_age: 1800 From b4e4dd3127f7869c69dd306a8b07a53c22c69177 Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Tue, 17 Feb 2026 08:03:20 +0100 Subject: [PATCH 16/17] extract known plugins from metadata too --- src/filter_plugins/foremanctl.py | 19 +++++++++++++++++-- src/roles/foreman_proxy/defaults/main.yaml | 3 +-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/filter_plugins/foremanctl.py b/src/filter_plugins/foremanctl.py index 7ac45eee..2aa8475e 100644 --- a/src/filter_plugins/foremanctl.py +++ b/src/filter_plugins/foremanctl.py @@ -27,18 +27,31 @@ } +def compact_list(items): + return [item for item in items if item is not None] + + def foreman_plugins(value): dependencies = [FEATURE_MAP.get(feature, {}).get('dependencies', []) for feature in value if feature not in BASE_FEATURES] dependencies = list(set([dep for deplist in dependencies for dep in deplist])) plugins = [FEATURE_MAP.get(feature, {}).get('foreman') for feature in (value + dependencies) if feature not in BASE_FEATURES] - return [plugin for plugin in plugins if plugin is not None] + return compact_list(plugins) + +def known_foreman_plugins(_value): + plugins = [FEATURE_MAP.get(feature).get('foreman') for feature in FEATURE_MAP.keys()] + return compact_list(plugins) def foreman_proxy_plugins(value): dependencies = [FEATURE_MAP.get(feature, {}).get('dependencies', []) for feature in value if feature not in BASE_FEATURES] dependencies = list(set([dep for deplist in dependencies for dep in deplist])) plugins = [FEATURE_MAP.get(feature, {}).get('foreman_proxy') for feature in (value + dependencies) if feature not in BASE_FEATURES] - return [plugin for plugin in plugins if plugin is not None] + return compact_list(plugins) + + +def known_foreman_proxy_plugins(_value): + plugins = [FEATURE_MAP.get(feature).get('foreman_proxy') for feature in FEATURE_MAP.keys()] + return compact_list(plugins) class FilterModule(object): @@ -47,5 +60,7 @@ class FilterModule(object): def filters(self): return { 'features_to_foreman_plugins': foreman_plugins, + 'known_foreman_plugins': known_foreman_plugins, 'features_to_foreman_proxy_plugins': foreman_proxy_plugins, + 'known_foreman_proxy_plugins': known_foreman_proxy_plugins, } diff --git a/src/roles/foreman_proxy/defaults/main.yaml b/src/roles/foreman_proxy/defaults/main.yaml index c02007a6..000a5c36 100644 --- a/src/roles/foreman_proxy/defaults/main.yaml +++ b/src/roles/foreman_proxy/defaults/main.yaml @@ -7,8 +7,7 @@ foreman_proxy_url: "https://{{ foreman_proxy_name }}:{{ foreman_proxy_https_port foreman_proxy_trusted_hosts: - "{{ foreman_proxy_name }}" -foreman_proxy_known_feautures: - - remote_execution_ssh +foreman_proxy_known_feautures: "{{ [] | known_foreman_proxy_plugins }}" foreman_proxy_base_feautures: - logs foreman_proxy_plugins: [] From 2437e0b609ec6dd30bf18b68f185ea58b9838036 Mon Sep 17 00:00:00 2001 From: Evgeni Golov Date: Tue, 24 Feb 2026 09:04:48 +0100 Subject: [PATCH 17/17] use ansible 2.14 compatible first_found syntax --- src/roles/foreman_proxy/tasks/feature.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/roles/foreman_proxy/tasks/feature.yaml b/src/roles/foreman_proxy/tasks/feature.yaml index b1d40c1c..3d954a98 100644 --- a/src/roles/foreman_proxy/tasks/feature.yaml +++ b/src/roles/foreman_proxy/tasks/feature.yaml @@ -28,4 +28,4 @@ - tasks_file is not none - tasks_file != "" vars: - tasks_file: "{{ lookup('ansible.builtin.first_found', files=['feature/' + feature_name + '.yaml'], errors='ignore') }}" + tasks_file: "{{ lookup('ansible.builtin.first_found', ['feature/' + feature_name + '.yaml'], errors='ignore') }}"