name: ci
on:
pull_request: {}
push:
tags:
- "v*"
branches:
- main
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
env:
CARGO_TERM_COLOR: always
jobs:
build:
name: build / ${{ matrix.profile }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- profile: debug
make_target: build
cache_suffix: ""
- profile: release
make_target: build-release
cache_suffix: "-release"
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 - uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo${{ matrix.cache_suffix }}-${{ hashFiles('**/Cargo.lock') }}
- run: make ${{ matrix.make_target }}
build-cross:
name: build / cross / ${{ matrix.arch }}
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
include:
- arch: x86_64
target: x86_64-unknown-linux-gnu
strip: strip
- arch: aarch64
target: aarch64-unknown-linux-gnu
strip: aarch64-linux-gnu-strip
- arch: armv7
target: armv7-unknown-linux-gnueabihf
strip: arm-linux-gnueabihf-strip
- arch: ppc64le
target: powerpc64le-unknown-linux-gnu
strip: powerpc64le-linux-gnu-strip
- arch: s390x
target: s390x-unknown-linux-gnu
strip: s390x-linux-gnu-strip
- arch: riscv64
target: riscv64gc-unknown-linux-gnu
strip: riscv64-linux-gnu-strip
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 - uses: taiki-e/install-action@7627fb428e65e78e2ec9a24ae5c5bd5f8553f182 with:
tool: cross
- uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ matrix.target }}-${{ hashFiles('**/Cargo.lock') }}
- run: make build-cross CROSS_TARGET=${{ matrix.target }}
- name: Strip binary
run: |
docker run --rm \
-v $PWD/target/${{ matrix.target }}/release:/target \
ghcr.io/cross-rs/${{ matrix.target }}:main \
${{ matrix.strip }} -s /target/kubernix
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f with:
name: kubernix-${{ matrix.arch }}
path: target/${{ matrix.target }}/release/kubernix
deploy:
name: deploy / release
runs-on: ubuntu-latest
needs: build-cross
if: startsWith(github.ref, 'refs/tags/v')
permissions:
contents: write
steps:
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with:
path: artifacts
- name: Prepare release binaries
run: |
mkdir -p release
for dir in artifacts/kubernix-*; do
target=$(basename "$dir" | sed 's/^kubernix-//')
cp "$dir/kubernix" "release/kubernix-$target"
done
ls -la release/
- name: Upload release binaries
uses: softprops/action-gh-release@153bb8e04406b158c6c84fc1615b65b24149a1fe with:
files: release/*
docs:
name: docs / build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 - uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-docs-${{ hashFiles('**/Cargo.lock') }}
- run: make docs
- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f with:
name: docs
path: target/doc
docs-publish:
name: docs / publish
runs-on: ubuntu-latest
needs: docs
if: github.ref == 'refs/heads/main'
permissions:
contents: write
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with:
name: docs
path: doc
- uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./doc
lint-clippy:
name: lint / clippy
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 with:
components: clippy
- uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-clippy-${{ hashFiles('**/Cargo.lock') }}
- run: make lint-clippy
lint-rustfmt:
name: lint / rustfmt
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 with:
components: rustfmt
- run: make lint-rustfmt
lint-audit:
name: lint / audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - uses: taiki-e/install-action@7627fb428e65e78e2ec9a24ae5c5bd5f8553f182 with:
tool: cargo-audit
- run: make lint-audit
lint-deny:
name: lint / deny
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - uses: EmbarkStudios/cargo-deny-action@3fd3802e88374d3fe9159b834c7714ec57d6c979
lint-dependencies:
name: lint / dependencies
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - run: make lint-dependencies
test-unit:
name: test / unit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - uses: dtolnay/rust-toolchain@631a55b12751854ce901bb631d5902ceb48146f7 - uses: taiki-e/install-action@7627fb428e65e78e2ec9a24ae5c5bd5f8553f182 with:
tool: cargo-llvm-cov
- uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-test-${{ hashFiles('**/Cargo.lock') }}
- uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 with:
path: |
~/go/bin
~/go/pkg
~/bin
key: ${{ runner.os }}-test-tools-cfssl-1.6.5
- name: Install test dependencies
run: |
go install github.com/cloudflare/cfssl/cmd/cfssl@v1.6.5
go install github.com/cloudflare/cfssl/cmd/cfssljson@v1.6.5
echo "$(go env GOPATH)/bin" >> $GITHUB_PATH
- name: Generate code coverage
run: cargo llvm-cov --all-features --lib --lcov --output-path lcov.info
- name: Upload Results
uses: codecov/codecov-action@1af58845a975a7985b0beb0cbe6fbbb71a41dbad with:
files: lcov.info
token: ${{ secrets.CODECOV_TOKEN }}
test-integration:
name: test / integration / ${{ matrix.name }}
runs-on: ubuntu-latest
needs: build-cross
strategy:
fail-fast: false
matrix:
include:
- name: single
nodes: 1
- name: multi
nodes: 2
steps:
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd - uses: cachix/install-nix-action@51f3067b56fe8ae331890c77d4e454f6d60615ff with:
extra_nix_config: |
experimental-features = nix-command flakes
- uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c with:
name: kubernix-x86_64
- run: chmod +x kubernix
- name: Set hostname
run: |
echo "127.0.0.1 test" | sudo tee -a /etc/hosts
sudo hostnamectl set-hostname test
- name: Prepare the system
run: sudo contrib/prepare-system
- name: Run ${{ matrix.name }} integration test
run: |
sudo -E env "PATH=$PATH" ./kubernix --log-level=debug --no-shell --addons --nodes=${{ matrix.nodes }} &
KUBERNIX_PID=$!
timeout 300 bash -c 'while [ ! -f kubernix-run/kubernix.pid ]; do sleep 1; done'
echo "Cluster is up, running checks"
export KUBECONFIG=$PWD/kubernix-run/kubeconfig/admin.kubeconfig
echo "Asserting all nodes are Ready..."
READY_COUNT=$(kubectl get nodes -o go-template='{{range .items}}{{range .status.conditions}}{{if eq .type "Ready"}}{{if eq .status "True"}}x{{end}}{{end}}{{end}}{{end}}' | wc -c)
if [ "$READY_COUNT" -ne "${{ matrix.nodes }}" ]; then
echo "FAIL: expected ${{ matrix.nodes }} ready nodes, got $READY_COUNT"
exit 1
fi
echo "Asserting all pods are healthy..."
timeout 60 bash -c 'until [ "$(kubectl get pods -A -o go-template="{{range .items}}{{if and (ne .status.phase \"Running\") (ne .status.phase \"Succeeded\")}}x{{end}}{{end}}" | wc -c)" -eq 0 ]; do sleep 2; done'
UNHEALTHY=$(kubectl get pods -A -o go-template='{{range .items}}{{if and (ne .status.phase "Running") (ne .status.phase "Succeeded")}}{{.metadata.name}}({{.status.phase}}) {{end}}{{end}}')
if [ -n "$UNHEALTHY" ]; then
echo "FAIL: unhealthy pods: $UNHEALTHY"
exit 1
fi
echo "All assertions passed"
sudo kill $KUBERNIX_PID
wait $KUBERNIX_PID || true
timeout-minutes: 10