-
Notifications
You must be signed in to change notification settings - Fork 30
Add foreman_ansible #444
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?
Add foreman_ansible #444
Changes from all commits
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 |
|---|---|---|
|
|
@@ -29,6 +29,15 @@ remote-execution: | |
| hammer: foreman_remote_execution | ||
| dependencies: | ||
| - dynflow | ||
| foreman-ansible: | ||
| description: Ansible plugin for Foreman | ||
| foreman: | ||
| plugin_name: foreman_ansible | ||
| foreman_proxy: | ||
| plugin_name: ansible | ||
| hammer: foreman_ansible | ||
| dependencies: | ||
| - dynflow | ||
|
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. I see remote_execution as dependecy of smart proxy ansible plugin too. https://github.com/theforeman/smart_proxy_ansible/blob/master/smart_proxy_ansible.gemspec#L32C31-L32C63, so by the metadata defination, should we add here?
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.
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. Sure, i was thinking about the scenario where remote-execution is not enabled(or explictely disabled via |
||
| dynflow: | ||
| internal: true | ||
| foreman_proxy: | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,22 @@ | ||
| --- | ||
| - name: Create ansible.env secret | ||
| containers.podman.podman_secret: | ||
| state: present | ||
| name: foreman-proxy-ansible-env | ||
| data: "{{ lookup('ansible.builtin.template', 'ansible.env.j2') }}" | ||
| notify: | ||
| - Restart Foreman Proxy | ||
| - Refresh Foreman Proxy | ||
|
|
||
| - name: Mount ansible.env secret | ||
| ansible.builtin.copy: | ||
| dest: /etc/containers/systemd/foreman-proxy.container.d/ansible-env.conf | ||
| content: | | ||
| [Container] | ||
| Secret=foreman-proxy-ansible-env,type=mount,target=/etc/foreman-proxy/ansible.env | ||
| mode: '0644' | ||
| owner: root | ||
| group: root | ||
| notify: | ||
| - Restart Foreman Proxy | ||
| - Refresh Foreman Proxy |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| export ANSIBLE_CALLBACK_WHITELIST="theforeman.foreman.foreman" | ||
| export ANSIBLE_CALLBACKS_ENABLED="theforeman.foreman.foreman" | ||
| export ANSIBLE_LOCAL_TEMP="/tmp" | ||
| export ANSIBLE_HOST_KEY_CHECKING="False" | ||
| export ANSIBLE_ROLES_PATH="/etc/ansible/roles:/usr/share/ansible/roles" | ||
| export ANSIBLE_COLLECTIONS_PATHS="/etc/ansible/collections:/usr/share/ansible/collections" | ||
|
|
||
| export FOREMAN_URL="{{ foreman_url }}" | ||
| export FOREMAN_SSL_CERT="/etc/foreman-proxy/foreman_ssl_cert.pem" | ||
| export FOREMAN_SSL_KEY="/etc/foreman-proxy/foreman_ssl_key.pem" | ||
| export FOREMAN_SSL_VERIFY="/etc/foreman-proxy/foreman_ssl_ca.pem" | ||
|
|
||
| export ANSIBLE_SSH_ARGS="-C -o ControlMaster=auto -o ControlPersist=60s -o ServerAliveInterval=15 -o ServerAliveCountMax=3" |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,5 @@ | ||
| --- | ||
| :enabled: {{ feature_enabled }} | ||
| :ansible_dir: /usr/share/foreman-proxy | ||
| :working_dir: /tmp | ||
| :ansible_environment_file: /etc/foreman-proxy/ansible.env |
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -0,0 +1,83 @@ | ||||||||||||||||||
| import json | ||||||||||||||||||
| import pytest | ||||||||||||||||||
|
|
||||||||||||||||||
| FOREMAN_PROXY_PORT = 8443 | ||||||||||||||||||
| ROLE_NAME = "theforeman.foremanctltest" | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| def test_foreman_ansible_plugin_installed(foremanapi): | ||||||||||||||||||
| plugins = [plugin['name'] for plugin in foremanapi.list('plugins')] | ||||||||||||||||||
| assert 'foreman_ansible' in plugins | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| def test_foreman_proxy_ansible_feature(server, certificates, server_fqdn): | ||||||||||||||||||
| cmd = server.run(f"curl --cacert {certificates['ca_certificate']} --silent https://{server_fqdn}:{FOREMAN_PROXY_PORT}/features") | ||||||||||||||||||
| assert cmd.succeeded | ||||||||||||||||||
| features = json.loads(cmd.stdout) | ||||||||||||||||||
| assert "ansible" in features | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| def test_import_ansible_role(ansible_role, server): | ||||||||||||||||||
| role_list = server.run(f"hammer --output csv --no-headers ansible roles list --search='name={ansible_role}'") | ||||||||||||||||||
| assert role_list.succeeded | ||||||||||||||||||
| assert ansible_role in role_list.stdout | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| @pytest.fixture(scope="module") | ||||||||||||||||||
| def ansible_proxy_id(foremanapi): | ||||||||||||||||||
| proxies = foremanapi.list('smart_proxies') | ||||||||||||||||||
| for proxy in proxies: | ||||||||||||||||||
| if any(f['name'] == 'Ansible' for f in proxy.get('features', [])): | ||||||||||||||||||
| return proxy['id'] | ||||||||||||||||||
| pytest.skip("No smart proxy with Ansible feature found") | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| @pytest.fixture(scope="module") | ||||||||||||||||||
| def ansible_role(server, foremanapi, ansible_proxy_id): | ||||||||||||||||||
|
Member
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 needs to run in a way that the result ends up inside the proxy container, otherwise ansible will never see the roles |
||||||||||||||||||
| setup = server.run(f"mkdir -p /etc/ansible/roles/{ROLE_NAME}/tasks") | ||||||||||||||||||
| assert setup.succeeded | ||||||||||||||||||
|
|
||||||||||||||||||
| write = server.run(f"echo '- command: uptime' > /etc/ansible/roles/{ROLE_NAME}/tasks/main.yml") | ||||||||||||||||||
| assert write.succeeded | ||||||||||||||||||
|
|
||||||||||||||||||
| fetch = server.run(f"hammer ansible roles fetch --proxy-id {ansible_proxy_id}") | ||||||||||||||||||
| assert fetch.succeeded | ||||||||||||||||||
|
|
||||||||||||||||||
| sync = server.run(f"hammer ansible roles sync --proxy-id {ansible_proxy_id} --role-names {ROLE_NAME}") | ||||||||||||||||||
| assert sync.succeeded | ||||||||||||||||||
|
|
||||||||||||||||||
| for task in foremanapi.list('foreman_tasks', search='label ~ SyncRolesAndVariables and state != stopped'): | ||||||||||||||||||
| foremanapi.wait_for_task(task) | ||||||||||||||||||
|
|
||||||||||||||||||
| yield ROLE_NAME | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| def test_run_ansible_role(ansible_role, foremanapi, server, server_fqdn): | ||||||||||||||||||
| assign = server.run(f"hammer host ansible-roles assign --name {server_fqdn} --ansible-roles {ansible_role}") | ||||||||||||||||||
| assert assign.succeeded | ||||||||||||||||||
| assert 'Ansible roles were assigned to the host' in assign.stdout | ||||||||||||||||||
|
|
||||||||||||||||||
| play = server.run(f"hammer host ansible-roles play --name {server_fqdn}") | ||||||||||||||||||
| assert play.succeeded | ||||||||||||||||||
| assert 'Ansible roles are being played.' in play.stdout | ||||||||||||||||||
|
|
||||||||||||||||||
| tasks = foremanapi.list('foreman_tasks', search='label = Actions::RemoteExecution::RunHostsJob') | ||||||||||||||||||
| for task in tasks: | ||||||||||||||||||
| foremanapi.wait_for_task(task) | ||||||||||||||||||
|
|
||||||||||||||||||
| report = server.run(f"hammer --output csv --no-headers config-report list --search 'host={server_fqdn} origin=Ansible'") | ||||||||||||||||||
| assert report.succeeded | ||||||||||||||||||
| assert server_fqdn in report.stdout | ||||||||||||||||||
| assert 'Ansible' in report.stdout | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
| def test_run_command_via_ansible(foremanapi, server_fqdn): | ||||||||||||||||||
| templates = foremanapi.list('job_templates', search='name = "Run Command - Ansible Default"') | ||||||||||||||||||
| job = foremanapi.create('job_invocations', { | ||||||||||||||||||
| 'job_template_id': templates[0]['id'], | ||||||||||||||||||
| 'inputs': {'command': 'uptime'}, | ||||||||||||||||||
| 'search_query': f'name = {server_fqdn}', | ||||||||||||||||||
| 'targeting_type': 'static_query', | ||||||||||||||||||
| }) | ||||||||||||||||||
| task = foremanapi.wait_for_task(job['task']) | ||||||||||||||||||
| assert task['result'] == 'success' | ||||||||||||||||||
|
Comment on lines
+55
to
+83
Member
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 need to go to see foremanctl/tests/client_test.py Lines 12 to 19 in 488b150
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. This is what I had: |
||||||||||||||||||
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.
Can we combine this 2 steps and enable foreman-ansible feature along with others?
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.
Yes - I can do that for efficiency.