name: RustFS Pool Expansion / Decommission Test on: workflow_dispatch: inputs: rustfs_version: description: 'RustFS release tag to test (e.g. 1.0.0-rc.3)' required: false default: '1.0.0-rc.3' package_url: description: 'Direct .deb URL (nightly/R2/dev). Overrides rustfs_version.' required: false type: string pools: description: 'Number of pools to expand to (2 = first rebalance only)' type: choice options: - '2' - '3' default: '3' storage_threshold: description: 'Stop writing when storage usage reaches N%' required: false default: '50' warp_duration: description: 'warp write duration (e.g. 5m, 10m)' required: false default: '10m' run_decommission: description: 'Run the pool decommission step (3-pool topology only)' type: boolean default: true stop_node_gb: description: 'Heal: stop the outage node when surviving nodes reach N GiB' required: false default: '15' warp_stop_gb: description: 'Heal: stop warp when surviving nodes reach N GiB' required: false default: '40' heal_target_gb: description: 'Heal: outage node must reach N GiB after heal' required: false default: '40' cleanup_before: description: 'Reset the nodes before the test (DESTROYS existing data/config)' type: boolean default: true cleanup_after: description: 'Reset the nodes after the test (DESTROYS test data/config)' type: boolean default: true workflow_run: # Run after the nightly build completes: pool expansion first, then heal. workflows: ["Nightly GNU Build"] types: [completed] permissions: contents: read # Only one pool-expansion test at a time: the workflow mutates a shared # test environment, so concurrent runs must not clobber each other. concurrency: group: rustfs-pool-expansion-test cancel-in-progress: false defaults: run: shell: bash env: RUSTFS_ACCESS_KEY: ${{ secrets.RUSTFS_ACCESS_KEY }} RUSTFS_SECRET_KEY: ${{ secrets.RUSTFS_SECRET_KEY }} RUSTFS_API_ENDPOINT: ${{ secrets.RUSTFS_API_ENDPOINT || vars.RUSTFS_API_ENDPOINT || vars.RUSTFS_RC_ENDPOINT }} RUSTFS_NODES: ${{ secrets.RUSTFS_NODES || vars.RUSTFS_NODES }} RUSTFS_SSH_USER: ${{ secrets.RUSTFS_SSH_USER || vars.RUSTFS_SSH_USER }} # Package used by the nightly run (workflow_dispatch inputs are empty for # workflow_run events), i.e. the latest nightly deb published by nightly-gnu.yml. RUSTFS_NIGHTLY_PACKAGE_URL: ${{ vars.RUSTFS_NIGHTLY_PACKAGE_URL || 'https://dl.rustfs.com/artifacts/rustfs/packages/nightly/rustfs-nightly-latest.deb' }} jobs: pool-expansion-test: runs-on: smoke-testing timeout-minutes: 360 # Run on manual dispatch, or when the nightly build completed successfully # (its deb is what the tests install). Skipped when nightly failed. if: ${{ github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success' }} steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 with: persist-credentials: false ref: ${{ github.event.workflow_run.head_sha || github.ref }} - name: Show environment run: | uname -a jq --version openssl version warp --version || true df -h /data | tail -1 - name: Reset test environment (before) if: ${{ inputs.cleanup_before != 'false' }} run: | chmod +x scripts/test/rustfs_pool_expand.sh ./scripts/test/rustfs_pool_expand.sh --reset -y - name: Install RustFS package & start first pool run: | ARGS=(--steps "1,2,3" -y --endpoint "${{ env.RUSTFS_API_ENDPOINT }}") if [ -n "${{ inputs.package_url }}" ]; then ARGS+=(--package-url "${{ inputs.package_url }}") elif [ -n "${{ inputs.rustfs_version }}" ]; then ARGS+=(--version "${{ inputs.rustfs_version }}") else ARGS+=(--package-url "${{ env.RUSTFS_NIGHTLY_PACKAGE_URL }}") fi ./scripts/test/rustfs_pool_expand.sh "${ARGS[@]}" - name: Preflight checks run: | ARGS=(--preflight --endpoint "${{ env.RUSTFS_API_ENDPOINT }}") if [ -n "${{ inputs.package_url }}" ]; then ARGS+=(--package-url "${{ inputs.package_url }}") elif [ -n "${{ inputs.rustfs_version }}" ]; then ARGS+=(--version "${{ inputs.rustfs_version }}") else ARGS+=(--package-url "${{ env.RUSTFS_NIGHTLY_PACKAGE_URL }}") fi ./scripts/test/rustfs_pool_expand.sh "${ARGS[@]}" - name: Run pool expansion & decommission test id: pool_test run: | set -o pipefail STEPS="4,5,6" if [ "${{ inputs.pools || '3' }}" = "3" ]; then STEPS="$STEPS,7,8" if [ "${{ inputs.run_decommission != 'false' }}" = "true" ]; then STEPS="$STEPS,9" fi fi ./scripts/test/rustfs_pool_expand.sh \ --steps "$STEPS" --with-warp -y \ --endpoint "${{ env.RUSTFS_API_ENDPOINT }}" \ --storage-threshold "${{ inputs.storage_threshold || '50' }}" \ --warp-duration "${{ inputs.warp_duration || '10m' }}" \ --log-file /tmp/rustfs-pool-test.log - name: Upload test logs if: always() uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: rustfs-pool-test-${{ github.run_id }} path: | /tmp/rustfs-pool-test*.log /tmp/rustfs-warp.*.log if-no-files-found: warn - name: Reset test environment (after) if: ${{ always() && inputs.cleanup_after != 'false' }} run: | ./scripts/test/rustfs_pool_expand.sh --reset -y - name: Notify on failure if: failure() run: | echo "RustFS pool expansion test failed" echo "Package source: ${{ inputs.package_url || inputs.rustfs_version || 'nightly (R2 latest)' }}" echo "See the uploaded log artifact for details." # Heal regression runs after the pool test regardless of its outcome: a pool # failure must be reported (it makes the run red) but must not block heal. heal-test: name: Heal test (after pool test) runs-on: smoke-testing timeout-minutes: 480 needs: pool-expansion-test if: ${{ always() && (github.event_name == 'workflow_dispatch' || github.event.workflow_run.conclusion == 'success') }} steps: - name: Checkout uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7 with: persist-credentials: false ref: ${{ github.event.workflow_run.head_sha || github.ref }} - name: Reset test environment (before) if: ${{ inputs.cleanup_before != 'false' }} run: | chmod +x scripts/test/rustfs_heal_test.sh ./scripts/test/rustfs_heal_test.sh --reset -y - name: Install RustFS package & start cluster run: | ARGS=(--steps "1,2" -y --endpoint "${{ env.RUSTFS_API_ENDPOINT }}") if [ -n "${{ inputs.package_url }}" ]; then ARGS+=(--package-url "${{ inputs.package_url }}") else ARGS+=(--package-url "${{ env.RUSTFS_NIGHTLY_PACKAGE_URL }}") fi ./scripts/test/rustfs_heal_test.sh "${ARGS[@]}" - name: Preflight checks run: | ARGS=(--preflight --endpoint "${{ env.RUSTFS_API_ENDPOINT }}") if [ -n "${{ inputs.package_url }}" ]; then ARGS+=(--package-url "${{ inputs.package_url }}") else ARGS+=(--package-url "${{ env.RUSTFS_NIGHTLY_PACKAGE_URL }}") fi ./scripts/test/rustfs_heal_test.sh "${ARGS[@]}" - name: Run heal test (write -> outage -> heal -> verify) run: | ./scripts/test/rustfs_heal_test.sh \ --steps 3,4,5,6,7 -y \ --endpoint "${{ env.RUSTFS_API_ENDPOINT }}" \ --stop-node-gb "${{ inputs.stop_node_gb || '15' }}" \ --warp-stop-gb "${{ inputs.warp_stop_gb || '40' }}" \ --heal-target-gb "${{ inputs.heal_target_gb || '40' }}" \ --log-file /tmp/rustfs-heal-test.log - name: Upload test logs if: always() uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6 with: name: rustfs-heal-test-${{ github.run_id }} path: | /tmp/rustfs-heal-test.log /tmp/rustfs-warp.*.log if-no-files-found: warn - name: Reset test environment (after) if: ${{ always() && inputs.cleanup_after != 'false' }} run: | ./scripts/test/rustfs_heal_test.sh --reset -y - name: Notify on failure if: failure() run: | echo "RustFS heal test failed" echo "See the uploaded log artifact for details."