diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 12b221970..0972d7430 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -138,6 +138,7 @@ jobs: --add-feature azure-rm \ --add-feature google \ --add-feature remote-execution \ + --add-feature bmc \ ${{ matrix.iop == 'enabled' && '--add-feature iop' || '' }} - name: Run tests run: | diff --git a/docs/user/parameters.md b/docs/user/parameters.md index 85d9c6619..37cbef906 100644 --- a/docs/user/parameters.md +++ b/docs/user/parameters.md @@ -103,6 +103,19 @@ There are multiple use cases from the users perspective that dictate what parame ## Smart Proxy +### Mapped + +| Parameter | Description | foreman-installer Parameters | +| --------- | ----------- | ---------------------------- | +| `--bmc-default-provider` | Default BMC provider | `--foreman-proxy-bmc-default-provider` | +| `--bmc-redfish-verify-ssl` | Verify SSL certificates for Redfish BMC connections | `--foreman-proxy-bmc-redfish-verify-ssl` | +| `--bmc-ssh-user` | BMC SSH user | `--foreman-proxy-bmc-ssh-user` | +| `--bmc-ssh-key` | BMC SSH key | `--foreman-proxy-bmc-ssh-key` | +| `--bmc-ssh-poweron` | BMC SSH power on command | `--foreman-proxy-bmc-ssh-poweron` | +| `--bmc-ssh-poweroff` | BMC SSH power off command | `--foreman-proxy-bmc-ssh-poweroff` | +| `--bmc-ssh-powerstatus` | BMC SSH power status command | `--foreman-proxy-bmc-ssh-powerstatus` | +| `--bmc-ssh-powercycle` | BMC SSH power cycle command | `--foreman-proxy-bmc-ssh-powercycle` | + ### Undetermined | Installer Parameter | Description | Module | Puppet Parameter | @@ -152,8 +165,6 @@ There are multiple use cases from the users perspective that dictate what parame | `--foreman-proxy-plugin-remote-execution-script-mode` | | foreman_proxy::plugin::remote_execution_script | mode | | `--foreman-proxy-plugin-openscap-ansible-module` | | foreman_proxy::plugin::openscap | ansible_module | | `--foreman-proxy-plugin-openscap-puppet-module` | | foreman_proxy::plugin::openscap | puppet_module | -| `--foreman-proxy-bmc` | | | | -| `--foreman-proxy-bmc-default-provider` | | | | | `--foreman-proxy-content-enable-ostree` | | | | | `--foreman-proxy-content-pulpcore-additional-import-paths` | | | | | `--foreman-proxy-http` | | | | diff --git a/src/features.yaml b/src/features.yaml index 5a77a1585..24dc7a084 100644 --- a/src/features.yaml +++ b/src/features.yaml @@ -44,3 +44,7 @@ iop: description: iop services dependencies: - rh-cloud +bmc: + description: Power management for bare metal hosts (IPMI, Redfish, SSH) + foreman_proxy: + plugin_name: bmc diff --git a/src/playbooks/deploy/metadata.obsah.yaml b/src/playbooks/deploy/metadata.obsah.yaml index e572ff46d..5a85772d5 100644 --- a/src/playbooks/deploy/metadata.obsah.yaml +++ b/src/playbooks/deploy/metadata.obsah.yaml @@ -46,6 +46,37 @@ variables: type: AbsolutePath parameter: --certificate-server-ca-certificate persist: false + foreman_proxy_bmc_default_provider: + parameter: --bmc-default-provider + help: Default BMC provider. + choices: + - freeipmi + - ipmitool + - redfish + - ssh + - shell + foreman_proxy_bmc_redfish_verify_ssl: + parameter: --bmc-redfish-verify-ssl + help: Verify SSL certificates for Redfish BMC connections. + type: Boolean + foreman_proxy_bmc_ssh_user: + parameter: --bmc-ssh-user + help: BMC SSH user. + foreman_proxy_bmc_ssh_key: + parameter: --bmc-ssh-key + help: BMC SSH key. + foreman_proxy_bmc_ssh_poweron: + parameter: --bmc-ssh-poweron + help: BMC SSH power on command. + foreman_proxy_bmc_ssh_poweroff: + parameter: --bmc-ssh-poweroff + help: BMC SSH power off command. + foreman_proxy_bmc_ssh_powerstatus: + parameter: --bmc-ssh-powerstatus + help: BMC SSH power status command. + foreman_proxy_bmc_ssh_powercycle: + parameter: --bmc-ssh-powercycle + help: BMC SSH power cycle command. constraints: required_together: diff --git a/src/roles/foreman_proxy/defaults/main.yaml b/src/roles/foreman_proxy/defaults/main.yaml index 1d48354d3..b5a698548 100644 --- a/src/roles/foreman_proxy/defaults/main.yaml +++ b/src/roles/foreman_proxy/defaults/main.yaml @@ -19,3 +19,15 @@ foreman_proxy_available_features: "{{ [] | available_foreman_proxy_plugins }}" foreman_proxy_disabled_features: "{{ foreman_proxy_available_features | difference(foreman_proxy_features) }}" foreman_proxy_foreman_server_url: "https://{{ ansible_facts['fqdn'] }}" + +# BMC settings +foreman_proxy_bmc_default_provider: ipmitool +foreman_proxy_bmc_redfish_verify_ssl: true + +# BMC SSH provider settings +foreman_proxy_bmc_ssh_user: root +foreman_proxy_bmc_ssh_key: /usr/share/foreman-proxy/.ssh/id_rsa_bmc +foreman_proxy_bmc_ssh_poweron: 'false' +foreman_proxy_bmc_ssh_poweroff: 'shutdown +1' +foreman_proxy_bmc_ssh_powerstatus: 'true' +foreman_proxy_bmc_ssh_powercycle: 'shutdown -r +1' diff --git a/src/roles/foreman_proxy/tasks/feature/bmc.yaml b/src/roles/foreman_proxy/tasks/feature/bmc.yaml new file mode 100644 index 000000000..4a9bf9908 --- /dev/null +++ b/src/roles/foreman_proxy/tasks/feature/bmc.yaml @@ -0,0 +1,41 @@ +--- +- name: Create BMC SSH key + community.crypto.openssh_keypair: + path: "/root/foreman-proxy-bmc-ssh" + comment: "Foreman Proxy BMC SSH key" + when: foreman_proxy_bmc_default_provider == 'ssh' + +- name: Create BMC SSH private key podman secret + containers.podman.podman_secret: + state: present + name: foreman_proxy-bmc-ssh-key + path: "/root/foreman-proxy-bmc-ssh" + when: foreman_proxy_bmc_default_provider == 'ssh' + notify: + - Restart Foreman Proxy + - Refresh Foreman Proxy + +- name: Create BMC SSH public key podman secret + containers.podman.podman_secret: + state: present + name: foreman_proxy-bmc-ssh-key-pub + path: "/root/foreman-proxy-bmc-ssh.pub" + when: foreman_proxy_bmc_default_provider == 'ssh' + notify: + - Restart Foreman Proxy + - Refresh Foreman Proxy + +- name: Mount BMC SSH keys into proxy container + ansible.builtin.copy: + dest: /etc/containers/systemd/foreman-proxy.container.d/bmc-ssh-keys.conf + content: | + [Container] + Secret=foreman_proxy-bmc-ssh-key,type=mount,target={{ foreman_proxy_bmc_ssh_key }} + Secret=foreman_proxy-bmc-ssh-key-pub,type=mount,target={{ foreman_proxy_bmc_ssh_key }}.pub + mode: '0644' + owner: root + group: root + when: foreman_proxy_bmc_default_provider == 'ssh' + notify: + - Restart Foreman Proxy + - Refresh Foreman Proxy diff --git a/src/roles/foreman_proxy/templates/settings.d/bmc.yml.j2 b/src/roles/foreman_proxy/templates/settings.d/bmc.yml.j2 new file mode 100644 index 000000000..00e8d30c1 --- /dev/null +++ b/src/roles/foreman_proxy/templates/settings.d/bmc.yml.j2 @@ -0,0 +1,13 @@ +--- +:enabled: {{ feature_enabled }} +:bmc_default_provider: {{ foreman_proxy_bmc_default_provider }} +:redfish_verify_ssl: {{ foreman_proxy_bmc_redfish_verify_ssl }} + +{% if foreman_proxy_bmc_default_provider == 'ssh' %} +:bmc_ssh_user: {{ foreman_proxy_bmc_ssh_user }} +:bmc_ssh_key: {{ foreman_proxy_bmc_ssh_key }} +:bmc_ssh_poweron: {{ foreman_proxy_bmc_ssh_poweron }} +:bmc_ssh_poweroff: {{ foreman_proxy_bmc_ssh_poweroff }} +:bmc_ssh_powerstatus: {{ foreman_proxy_bmc_ssh_powerstatus }} +:bmc_ssh_powercycle: {{ foreman_proxy_bmc_ssh_powercycle }} +{% endif %} diff --git a/tests/conftest.py b/tests/conftest.py index 392d07914..e6f3d5a96 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -193,22 +193,20 @@ def wait_for_tasks(foremanapi, search=None): def wait_for_metadata_generate(foremanapi): wait_for_tasks(foremanapi, 'label = Actions::Katello::Repository::MetadataGenerate') - -def is_iop_enabled(): +def enabled_features(): test_dir = os.path.dirname(os.path.abspath(__file__)) foremanctl_dir = os.path.dirname(test_dir) params_file = os.path.join(foremanctl_dir, '.var', 'lib', 'foremanctl', 'parameters.yaml') - if os.path.exists(params_file): with open(params_file, 'r') as f: - params = yaml.safe_load(f) - features = params.get('features', []) + features = yaml.safe_load(f).get('features', []) if isinstance(features, str): features = features.split() - return 'iop' in features - - return False + return features + return [] +def is_iop_enabled(): + return 'iop' in enabled_features() def pytest_configure(config): config.addinivalue_line("markers", "iop: tests requiring IOP to be enabled") diff --git a/tests/foreman_proxy_test.py b/tests/foreman_proxy_test.py index 4cf886dcb..71d5546d2 100644 --- a/tests/foreman_proxy_test.py +++ b/tests/foreman_proxy_test.py @@ -1,9 +1,24 @@ import datetime import json import pytest +import yaml +from conftest import enabled_features FOREMAN_PROXY_PORT = 8443 +def get_proxy_feature_setting(server, feature): + cmd = server.run(f"podman exec foreman-proxy cat /etc/foreman-proxy/settings.d/{feature}.yml") + if cmd.succeeded: + return yaml.safe_load(cmd.stdout) + return {} + +def is_bmc_enabled(): + return 'bmc' in enabled_features() + +def get_default_bmc_provider(server): + bmc_setting = get_proxy_feature_setting(server, 'bmc') + return bmc_setting.get(':bmc_default_provider') + def test_foreman_proxy_features(server, certificates, server_fqdn): cmd = server.run(f"curl --cacert {certificates['server_ca_certificate']} --silent https://{server_fqdn}:{FOREMAN_PROXY_PORT}/features") assert cmd.succeeded @@ -11,6 +26,8 @@ def test_foreman_proxy_features(server, certificates, server_fqdn): assert "logs" in features assert "script" in features assert "dynflow" in features + if is_bmc_enabled(): + assert "bmc" in features def test_foreman_proxy_service(server): foreman_proxy = server.service("foreman-proxy") @@ -33,3 +50,7 @@ def test_foreman_proxy_client_auth_to_foreman(server, certificates, server_fqdn) ) assert cmd.succeeded assert cmd.stdout == '201' + +@pytest.mark.skipif("not is_bmc_enabled()") +def test_bmc_default_provider(server): + assert get_default_bmc_provider(server) == 'ipmitool'