-
Notifications
You must be signed in to change notification settings - Fork 22
Proxy features: REX #309
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Proxy features: REX #309
Changes from all commits
68b0ebd
56c19d9
8006d73
e4535f3
f20ed5d
707492b
6f62082
c986fe5
0099c42
e4f5931
86c3b1a
53eab43
1983a86
7cc9629
36cf297
cd6a35c
6726508
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,4 +1,5 @@ | ||
| [defaults] | ||
| host_key_checking = False | ||
| roles_path = ./roles | ||
| filter_plugins = ./filter_plugins | ||
| callback_result_format = yaml |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,66 @@ | ||
| 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', | ||
| 'dependencies': ['dynflow'] | ||
| }, | ||
| 'dynflow': { | ||
| 'foreman_proxy': 'dynflow' | ||
| }, | ||
| 'google': { | ||
| 'foreman': 'foreman_google', | ||
| 'foreman_proxy': None | ||
| }, | ||
| 'azure_rm': { | ||
| 'foreman': 'foreman_azure_rm', | ||
| 'foreman_proxy': None | ||
| } | ||
| } | ||
|
|
||
|
|
||
| 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 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 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): | ||
| ''' foremanctl filters''' | ||
|
|
||
| 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, | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,3 +6,4 @@ collections: | |
| - name: containers.podman | ||
| version: ">=1.16.4" | ||
| - name: theforeman.foreman | ||
| version: ">=5.9.0" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -3,3 +3,11 @@ | |
| ansible.builtin.systemd: | ||
| name: foreman-proxy | ||
| state: restarted | ||
|
|
||
| - name: Refresh Foreman Proxy | ||
|
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This gets executed too early on fresh installs. Damn.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Now i wonder why is refreshing feature needed at the first place?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Foreman stores the list of features a Proxy has in its database, when the configuration of a proxy changes, you need to "refresh" that data. |
||
| 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 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| --- | ||
| - 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 | ||
| - Refresh 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 | ||
| - Refresh Foreman Proxy | ||
|
|
||
| - 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: | ||
| tasks_file: "{{ lookup('ansible.builtin.first_found', ['feature/' + feature_name + '.yaml'], errors='ignore') }}" |
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
| @@ -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 | ||||||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
|
||||||
| 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 | ||||||
|
Comment on lines
+9
to
+19
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These two tasks can be consolidated into a loop to create the SSH key/pub secrets, which will also ensure the handler runs only once, OR just run the handler when SSH secrets are mounted to the container
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Handlers run only once, no matter how often they are notified. |
||||||
| 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 | ||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -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,13 +34,34 @@ | |
| 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 | ||
| vars: | ||
| feature_enabled: "true" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are we limiting this
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It can, but given that we only configure a https port right now, it's kinda pointless to differentiate. |
||
| 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 | ||
|
|
||
| - name: Flush handlers to restart services | ||
| ansible.builtin.meta: flush_handlers | ||
|
|
||
| - name: Start the Foreman Proxy Service | ||
| ansible.builtin.systemd: | ||
| name: foreman-proxy | ||
|
|
@@ -55,3 +75,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 | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,2 +1,2 @@ | ||
| --- | ||
| :enabled: https | ||
| :enabled: {{ feature_enabled }} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,46 @@ | ||
| --- | ||
| :enabled: {{ feature_enabled }} | ||
| :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 public key> | ||
| # :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 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,10 +1,19 @@ | ||
| 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') | ||
| assert client.package('bear').is_installed | ||
| 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}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@ekohl can you remind me why we're force-enabling
logs?This is there since #279 but no explanation why we enable it.