diff --git a/.ostree/README.md b/.ostree/README.md new file mode 100644 index 0000000..f5e6931 --- /dev/null +++ b/.ostree/README.md @@ -0,0 +1,3 @@ +*NOTE*: The `*.txt` files are used by `get_ostree_data.sh` to create the lists +of packages, and to find other system roles used by this role. DO NOT use them +directly. diff --git a/.ostree/get_ostree_data.sh b/.ostree/get_ostree_data.sh new file mode 100755 index 0000000..cec08b0 --- /dev/null +++ b/.ostree/get_ostree_data.sh @@ -0,0 +1,132 @@ +#!/bin/bash + +set -euo pipefail + +ostree_dir="${OSTREE_DIR:-"$(dirname "$(realpath "$0")")"}" + +if [ -z "${4:-}" ] || [ "${1:-}" = help ] || [ "${1:-}" = -h ]; then + cat <&2 echo ERROR - could not find role "$role" - please use ANSIBLE_COLLECTIONS_PATH + exit 2 +} + +get_packages() { + local ostree_dir pkgtype pkgfile rolefile + ostree_dir="$1" + for pkgtype in "${pkgtypes[@]}"; do + for suff in "" "-$distro" "-${distro}-${major_ver}" "-${distro}-${ver}"; do + pkgfile="$ostree_dir/packages-${pkgtype}${suff}.txt" + if [ -f "$pkgfile" ]; then + cat "$pkgfile" + fi + done + rolefile="$ostree_dir/roles-${pkgtype}.txt" + if [ -f "$rolefile" ]; then + local roles role rolepath + roles="$(cat "$rolefile")" + for role in $roles; do + rolepath="$(get_rolepath "$ostree_dir" "$role")" + if [ -z "$rolepath" ]; then + 1>&2 echo ERROR - could not find role "$role" - please use ANSIBLE_COLLECTIONS_PATH + exit 2 + fi + get_packages "$rolepath" + done + fi + done | sort -u +} + +format_packages_json() { + local comma pkgs pkg + comma="" + pkgs="[" + while read -r pkg; do + pkgs="${pkgs}${comma}\"${pkg}\"" + comma=, + done + pkgs="${pkgs}]" + echo "$pkgs" +} + +format_packages_raw() { + cat +} + +format_packages_yaml() { + while read -r pkg; do + echo "- $pkg" + done +} + +format_packages_toml() { + while read -r pkg; do + echo "[[packages]]" + echo "name = \"$pkg\"" + echo "version = \"*\"" + done +} + +distro="${distro_ver%%-*}" +ver="${distro_ver##*-}" +if [[ "$ver" =~ ^([0-9]*) ]]; then + major_ver="${BASH_REMATCH[1]}" +else + echo ERROR: cannot parse major version number from version "$ver" + exit 1 +fi + +"get_$category" "$ostree_dir" | "format_${category}_$format" diff --git a/.ostree/packages-runtime.txt b/.ostree/packages-runtime.txt new file mode 100644 index 0000000..cad88af --- /dev/null +++ b/.ostree/packages-runtime.txt @@ -0,0 +1,2 @@ +iproute +libreswan diff --git a/.ostree/roles-runtime.txt b/.ostree/roles-runtime.txt new file mode 100644 index 0000000..a41c34a --- /dev/null +++ b/.ostree/roles-runtime.txt @@ -0,0 +1,2 @@ +firewall +selinux diff --git a/.sanity-ansible-ignore-2.10.txt b/.sanity-ansible-ignore-2.10.txt index ce6e654..6b7cab0 100644 --- a/.sanity-ansible-ignore-2.10.txt +++ b/.sanity-ansible-ignore-2.10.txt @@ -1,3 +1,4 @@ plugins/filter/vpn_ipaddr.py no-unicode-literals!skip tests/vpn/unit/test_vpn_ipaddr.py no-unicode-literals!skip lsr_role2coll_extra_script-vpn shebang!skip +roles/vpn/.ostree/get_ostree_data.sh shebang!skip diff --git a/.sanity-ansible-ignore-2.11.txt b/.sanity-ansible-ignore-2.11.txt index ce6e654..6b7cab0 100644 --- a/.sanity-ansible-ignore-2.11.txt +++ b/.sanity-ansible-ignore-2.11.txt @@ -1,3 +1,4 @@ plugins/filter/vpn_ipaddr.py no-unicode-literals!skip tests/vpn/unit/test_vpn_ipaddr.py no-unicode-literals!skip lsr_role2coll_extra_script-vpn shebang!skip +roles/vpn/.ostree/get_ostree_data.sh shebang!skip diff --git a/.sanity-ansible-ignore-2.12.txt b/.sanity-ansible-ignore-2.12.txt index ce6e654..6b7cab0 100644 --- a/.sanity-ansible-ignore-2.12.txt +++ b/.sanity-ansible-ignore-2.12.txt @@ -1,3 +1,4 @@ plugins/filter/vpn_ipaddr.py no-unicode-literals!skip tests/vpn/unit/test_vpn_ipaddr.py no-unicode-literals!skip lsr_role2coll_extra_script-vpn shebang!skip +roles/vpn/.ostree/get_ostree_data.sh shebang!skip diff --git a/.sanity-ansible-ignore-2.13.txt b/.sanity-ansible-ignore-2.13.txt index ce6e654..6b7cab0 100644 --- a/.sanity-ansible-ignore-2.13.txt +++ b/.sanity-ansible-ignore-2.13.txt @@ -1,3 +1,4 @@ plugins/filter/vpn_ipaddr.py no-unicode-literals!skip tests/vpn/unit/test_vpn_ipaddr.py no-unicode-literals!skip lsr_role2coll_extra_script-vpn shebang!skip +roles/vpn/.ostree/get_ostree_data.sh shebang!skip diff --git a/.sanity-ansible-ignore-2.14.txt b/.sanity-ansible-ignore-2.14.txt index ce6e654..6b7cab0 100644 --- a/.sanity-ansible-ignore-2.14.txt +++ b/.sanity-ansible-ignore-2.14.txt @@ -1,3 +1,4 @@ plugins/filter/vpn_ipaddr.py no-unicode-literals!skip tests/vpn/unit/test_vpn_ipaddr.py no-unicode-literals!skip lsr_role2coll_extra_script-vpn shebang!skip +roles/vpn/.ostree/get_ostree_data.sh shebang!skip diff --git a/.sanity-ansible-ignore-2.15.txt b/.sanity-ansible-ignore-2.15.txt index ce6e654..6b7cab0 100644 --- a/.sanity-ansible-ignore-2.15.txt +++ b/.sanity-ansible-ignore-2.15.txt @@ -1,3 +1,4 @@ plugins/filter/vpn_ipaddr.py no-unicode-literals!skip tests/vpn/unit/test_vpn_ipaddr.py no-unicode-literals!skip lsr_role2coll_extra_script-vpn shebang!skip +roles/vpn/.ostree/get_ostree_data.sh shebang!skip diff --git a/.sanity-ansible-ignore-2.9.txt b/.sanity-ansible-ignore-2.9.txt index ce6e654..6b7cab0 100644 --- a/.sanity-ansible-ignore-2.9.txt +++ b/.sanity-ansible-ignore-2.9.txt @@ -1,3 +1,4 @@ plugins/filter/vpn_ipaddr.py no-unicode-literals!skip tests/vpn/unit/test_vpn_ipaddr.py no-unicode-literals!skip lsr_role2coll_extra_script-vpn shebang!skip +roles/vpn/.ostree/get_ostree_data.sh shebang!skip diff --git a/README-ostree.md b/README-ostree.md new file mode 100644 index 0000000..a9f0185 --- /dev/null +++ b/README-ostree.md @@ -0,0 +1,66 @@ +# rpm-ostree + +The role supports running on [rpm-ostree](https://coreos.github.io/rpm-ostree/) +systems. The primary issue is that the `/usr` filesystem is read-only, and the +role cannot install packages. Instead, it will just verify that the necessary +packages and any other `/usr` files are pre-installed. The role will change the +package manager to one that is compatible with `rpm-ostree` systems. + +## Building + +To build an ostree image for a particular operating system distribution and +version, use the script `.ostree/get_ostree_data.sh` to get the list of +packages. If the role uses other system roles, then the script will include the +packages for the other roles in the list it outputs. The list of packages will +be sorted in alphanumeric order. + +Usage: + +```bash +.ostree/get_ostree_data.sh packages runtime DISTRO-VERSION FORMAT +``` + +`DISTRO-VERSION` is in the format that Ansible uses for `ansible_distribution` +and `ansible_distribution_version` - for example, `Fedora-38`, `CentOS-8`, +`RedHat-9.4` + +`FORMAT` is one of `toml`, `json`, `yaml`, `raw` + +* `toml` - each package in a TOML `[[packages]]` element + +```toml +[[packages]] +name = "package-a" +version = "*" +[[packages]] +name = "package-b" +version = "*" +... +``` + +* `yaml` - a YAML list of packages + +```yaml +- package-a +- package-b +... +``` + +* `json` - a JSON list of packages + +```json +["package-a","package-b",...] +``` + +* `raw` - a plain text list of packages, one per line + +```bash +package-a +package-b +... +``` + +What format you choose depends on which image builder you are using. For +example, if you are using something based on +[osbuild-composer](https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/9/html-single/composing_installing_and_managing_rhel_for_edge_images/index#creating-an-image-builder-blueprint-for-a-rhel-for-edge-image-using-the-command-line-interface_composing-a-rhel-for-edge-image-using-image-builder-command-line), +you will probably want to use the `toml` output format. diff --git a/README.md b/README.md index 89e6cc0..e0b22de 100644 --- a/README.md +++ b/README.md @@ -33,15 +33,15 @@ uses the python3 built-in `ipaddress` module. ### Collection requirements The role requires the `firewall` role and the `selinux` role from the -`fedora.linux_system_roles` collection, if `vpn_manage_firewall` -and `vpn_manage_selinux` is set to true, respectively. -(Please see also the variables in the [`Firewall and Selinux`](#firewall-and-selinux) section.) +`fedora.linux_system_roles` collection, if `vpn_manage_firewall` and +`vpn_manage_selinux` are set to true, respectively. (Please see also the +variables in the [`Firewall and Selinux`](#firewall-and-selinux) section.) The +role requires additional collections to manage `rpm-ostree` systems. -If the `vpn` is a role from the `fedora.linux_system_roles` -collection or from the Fedora RPM package, the requirement is already -satisfied. +If using the `vpn` role from the `fedora.linux_system_roles` collection or from +the Fedora RPM package, the requirements are already satisfied. -Otherwise, please run the following command line to install the collection. +Otherwise, please run the following command line to install the collections. ```bash ansible-galaxy collection install -r meta/collection-requirements.yml @@ -430,6 +430,10 @@ If neither `public_key_src` nor `public_key_content` is populated, the role will Minimum acceptable algorithms are AES, MODP2048 and SHA2. +## rpm-ostree + +See README-ostree.md + ## License MIT. diff --git a/meta/collection-requirements.yml b/meta/collection-requirements.yml index d2b6e5b..0e6f8ea 100644 --- a/meta/collection-requirements.yml +++ b/meta/collection-requirements.yml @@ -1,4 +1,5 @@ # SPDX-License-Identifier: MIT --- collections: + - ansible.posix - fedora.linux_system_roles diff --git a/tasks/main.yml b/tasks/main.yml index 00dc16a..b9b81bc 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -7,6 +7,8 @@ package: name: "{{ __vpn_packages }}" state: present + use: "{{ (__vpn_is_ostree | d(false)) | + ternary('ansible.posix.rhel_rpm_ostree', omit) }}" tags: packages - name: Configure firewall diff --git a/tasks/set_vars.yml b/tasks/set_vars.yml index 4aaf253..1aa7697 100644 --- a/tasks/set_vars.yml +++ b/tasks/set_vars.yml @@ -5,6 +5,18 @@ when: __vpn_required_facts | difference(ansible_facts.keys() | list) | length > 0 +- name: Determine if system is ostree and set flag + when: not __vpn_is_ostree is defined + block: + - name: Check if system is ostree + ansible.builtin.stat: + path: /run/ostree-booted + register: __ostree_booted_stat + + - name: Set flag to indicate system is ostree + ansible.builtin.set_fact: + __vpn_is_ostree: "{{ __ostree_booted_stat.stat.exists }}" + - name: Set platform/version specific variables include_vars: "{{ __vpn_vars_file }}" loop: diff --git a/tests/tasks/cleanup.yml b/tests/tasks/cleanup.yml index 871e2d8..17f6098 100644 --- a/tests/tasks/cleanup.yml +++ b/tests/tasks/cleanup.yml @@ -20,6 +20,7 @@ name: "{{ item }}" state: absent loop: "{{ __vpn_packages | d([]) }}" + when: not __vpn_is_ostree | d(false) - name: Clean up files vars: diff --git a/tests/tasks/setup_test.yml b/tests/tasks/setup_test.yml index 2929952..6df7949 100644 --- a/tests/tasks/setup_test.yml +++ b/tests/tasks/setup_test.yml @@ -60,3 +60,20 @@ path: "/etc/ipsec.d/policies/clear" state: touch mode: "0600" + +# ostree installs firewall by default because the image must +# have all packages used by all tests - but for some tests +# we need to ensure firewall isn't running +- name: Ensure firewalld not running if not testing firewall + service: + name: firewalld + state: stopped + enabled: false + register: __firewalld_status + failed_when: + - __firewalld_status is failed + - not __no_such_service in __firewalld_status.msg + vars: + __no_such_service: >- + Could not find the requested service firewalld: + when: not vpn_manage_firewall | d(false) diff --git a/vars/main.yml b/vars/main.yml index 0f76bc1..b9c16b5 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -1,5 +1,6 @@ --- __vpn_packages: + - iproute # for default_ipvX facts - libreswan __vpn_services: