diff --git a/.github/workflows/pr_testing.yaml b/.github/workflows/pr_testing.yaml index 1364f0a..5b8222f 100644 --- a/.github/workflows/pr_testing.yaml +++ b/.github/workflows/pr_testing.yaml @@ -41,7 +41,7 @@ jobs: uses: ./.github/actions/bolt with: os-codename: ${{ matrix.os-details.codename }} - - name: Run openvox-agent install task + - name: Run install task for openvox-agent run: bolt task run openvox_bootstrap::install --targets localhost --run-as root - name: Verify openvox-agent is installed run: bolt task run openvox_bootstrap::check --targets localhost --run-as root @@ -71,7 +71,7 @@ jobs: path: openvox_bootstrap - id: prep uses: ./openvox_bootstrap/.github/actions/container_task_prep - - name: Run openvox-agent install task manually + - name: Run install task manually for openvox-agent env: PT_collection: openvox8 run: ./openvox_bootstrap/tasks/install_linux.sh @@ -104,7 +104,7 @@ jobs: path: openvox_bootstrap - id: prep uses: ./openvox_bootstrap/.github/actions/container_task_prep - - name: Run openvox-agent install task manually + - name: Run install task manually for openvox-agent env: PT_version: "8.14.0" run: ./openvox_bootstrap/tasks/install_linux.sh @@ -137,7 +137,7 @@ jobs: path: openvox_bootstrap - id: prep uses: ./openvox_bootstrap/.github/actions/container_task_prep - - name: Run openvox-agent install task manually + - name: Run install task manually for openvox-server env: PT_package: "openvox-server" run: ./openvox_bootstrap/tasks/install_linux.sh @@ -168,7 +168,7 @@ jobs: path: openvox_bootstrap - id: prep uses: ./openvox_bootstrap/.github/actions/container_task_prep - - name: Run openvox-agent install task manually + - name: Run install task manually for openvox-server env: PT_package: "openvox-server" PT_version: "8.8.0" diff --git a/.github/workflows/pr_testing_with_nested_vms.yml b/.github/workflows/pr_testing_with_nested_vms.yml index 193b51a..1089b71 100644 --- a/.github/workflows/pr_testing_with_nested_vms.yml +++ b/.github/workflows/pr_testing_with_nested_vms.yml @@ -70,3 +70,64 @@ jobs: - name: Verify openvox-agent is installed run: |- bolt task run openvox_bootstrap::check version=8 test=gt --inventory inventory.yaml --targets test-agent-1 + + # The rockylinux containers aren't set up for interacting with systemd + # so using nested_vms for this test. + test-install-and-stop: + strategy: + fail-fast: false + matrix: + os: + - [debian, '12'] + - [rocky, '9'] + - [ubuntu, '24.04'] + runs-on: ubuntu-22.04 + steps: + - uses: actions/checkout@v4 + - id: install-bolt + uses: ./.github/actions/bolt + with: + os-codename: jammy + - id: vm-cluster + uses: jpartlow/nested_vms@v1 + with: + os: ${{ matrix.os[0] }} + os-version: ${{ matrix.os[1] }} + os-arch: ${{ matrix.os[2] || 'x86_64' }} + image_version: ${{ matrix.os[3] }} + host-root-access: true + ruby-version: '3.3' + install-openvox: false + # Note: the cpu_mode is set to host-model for the sake of + # el-9 which expects at least x86_64-2 arch. This depends on + # the runner's architecture being sufficient, and there is + # probably a better way to get this set on the libvirt + # domain instead. + vms: |- + [ + { + "role": "agent", + "count": 1, + "cpus": 2, + "mem_mb": 4096, + "cpu_mode": "host-model" + } + ] + - name: Capture dereferenced inventory for use with openvox_bootstrap + working-directory: kvm_automation_tooling + run: |- + bolt inventory --inventory terraform/instances/inventory.test.yaml show --format json --detail | \ + jq '.inventory | with_entries(select(.key == "targets")) | del(.targets[0].groups)' | \ + yq -P > ../inventory.yaml + - name: Run openvox_bootstrap::install task on nested vm + run: |- + bolt task run openvox_bootstrap::install --inventory inventory.yaml --targets test-agent-1 stop_service=true + - name: Verify openvox-agent is installed + run: |- + bolt task run openvox_bootstrap::check version=8 test=gt --inventory inventory.yaml --targets test-agent-1 + - name: Verify service state + run: |- + set -e + bolt command run '/opt/puppetlabs/bin/puppet resource service openvox-agent' --inventory inventory.yaml --targets test-agent-1 > service.state + grep -E "ensure [ ]*=> [ ]*'stopped'" service.state + grep -E "enable [ ]*=> [ ]*'false'" service.state diff --git a/REFERENCE.md b/REFERENCE.md index ac0c572..0855361 100644 --- a/REFERENCE.md +++ b/REFERENCE.md @@ -123,7 +123,7 @@ Installs an openvox package. By default, this will be the latest openvox-agent f ##### `package` -Data type: `String[1]` +Data type: `Optional[String]` The name of the package to install. @@ -131,7 +131,7 @@ The name of the package to install. Data type: `Optional[String]` -The version of the openvox-agent package to install. Defaults to latest. +The version of the openvox-agent package to install. ##### `collection` @@ -151,6 +151,12 @@ Data type: `Optional[String]` The yum source repository to retrieve rpm packages from. +##### `stop_service` + +Data type: `Optional[Boolean]` + +Whether to stop the given service after install. (Requires puppet on the system.) + ### `install_build_artifact` Downloads and installs a package directly from the openvox build artifact server. diff --git a/files/common.sh b/files/common.sh index 358c1ae..8aa9976 100644 --- a/files/common.sh +++ b/files/common.sh @@ -510,3 +510,43 @@ set_artifacts_package_url() { export package_url # quiets shellcheck SC2034 assigned 'package_url' } + +# Stop and disable the service for the given package. +# +# Only intended to work for openvox-agent, openvoxdb and +# openvox-server. +# +# Will fail if openvox isn't installed. +# +# (voxpupuli/puppet-openvox_bootstrap#35) +# Implemented for integration with openbolt. +stop_and_disable_service() { + local _package="$1" + # Using the full path here because openvox is installed into opt, + # and if we've just installed, the shell's PATH will not include it + # yet. + local _puppet="${2:-/opt/puppetlabs/bin/puppet}" + + case "${_package}" in + openvox-agent) + local _service='puppet' + ;; + openvoxdb) + local _service='puppetdb' + ;; + openvox-server) + local _service='puppetserver' + ;; + *) + fail "Cannot stop service. Unknown service for package: '${_package}'" + ;; + esac + + info "Stopping and disabling service '${_service}' for package '${_package}'" + + if [ -x "${_puppet}" ]; then + exec_and_capture "${_puppet}" resource service "${_service}" ensure=stopped enable=false + else + fail "Puppet executable not found at '${_puppet}'. Cannot stop and disable service '${_service}'." + fi +} diff --git a/spec/unit/bash/common_sh_spec.rb b/spec/unit/bash/common_sh_spec.rb index 8e24e74..7257c6f 100644 --- a/spec/unit/bash/common_sh_spec.rb +++ b/spec/unit/bash/common_sh_spec.rb @@ -577,4 +577,48 @@ end end end + + context 'stop_and_disable_service' do + it 'fails for an unknown package' do + output, status = test('stop_and_disable_service unknown-package') + + expect(status.success?).to be(false) + expect(output.strip).to include("Unknown service for package: 'unknown-package'") + end + + it 'fails if puppet executable not found' do + output, status = test('stop_and_disable_service openvox-agent /no/openvox') + + expect(status.success?).to be(false) + expect(output.strip).to include("Puppet executable not found at '/no/openvox'") + end + + context 'with puppet executable' do + let(:mock_puppet) { "#{tmpdir}/puppet" } + + before do + # The little BashRspec lib isn't sophisticated enough + # to deal with an absolute path, so using this instead of + # allow_script.to receive_command(mock_puppet)... + File.write(mock_puppet, <<~EOF) + #!/bin/sh + echo "Stopping ${3} service" + EOF + File.chmod(0o755, mock_puppet) + end + + [ + %w[openvox-agent puppet], + %w[openvox-server puppetserver], + %w[openvoxdb puppetdb], + ].each do |package, service| + it "stops the #{service} service for #{package}" do + output, status = test("stop_and_disable_service #{package} #{mock_puppet}") + + expect(status.success?).to be(true) + expect(output.strip).to include(service) + end + end + end + end end diff --git a/tasks/install.json b/tasks/install.json index 7752851..1fa9226 100644 --- a/tasks/install.json +++ b/tasks/install.json @@ -3,12 +3,13 @@ "parameters": { "package": { "description": "The name of the package to install.", - "type": "String[1]", + "type": "Optional[String]", "default": "openvox-agent" }, "version": { - "description": "The version of the openvox-agent package to install. Defaults to latest.", - "type": "Optional[String]" + "description": "The version of the openvox-agent package to install.", + "type": "Optional[String]", + "default": "latest" }, "collection": { "description": "The openvox collection to install from.", @@ -24,6 +25,11 @@ "description": "The yum source repository to retrieve rpm packages from.", "type": "Optional[String]", "default": "https://yum.voxpupuli.org" + }, + "stop_service": { + "description": "Whether to stop the given service after install. (Requires puppet on the system.)", + "type": "Optional[Boolean]", + "default": false } }, "implementations": [ diff --git a/tasks/install_linux.sh b/tasks/install_linux.sh index 43b4b88..fbfc930 100755 --- a/tasks/install_linux.sh +++ b/tasks/install_linux.sh @@ -9,6 +9,7 @@ version=${PT_version:-latest} collection=${PT_collection:-openvox8} yum_source=${PT_yum_source:-https://yum.voxpupuli.org} apt_source=${PT_apt_source:-https://apt.voxpupuli.org} +stop_service=${PT_stop_service:-'false'} # shellcheck source=files/common.sh source "${PT__installdir}/openvox_bootstrap/files/common.sh" @@ -75,5 +76,9 @@ download "${package_url}" "${local_release_package}" # The release package has the repository metadata needed to install # packages from the collection using the platform package manager. install_release_package "${local_release_package}" -# Use the platform package manager to install openvox-agent +# Use the platform package manager to install $package install_package "${package}" "${version}" "${os_family}" "${os_full_version}" +# If a service stop is requested, stop the service now +if [[ "${stop_service}" = 'true' ]]; then + stop_and_disable_service "${package}" +fi