Skip to content

Linux

Linux #9666

Workflow file for this run

name: Linux
on:
workflow_call:
schedule:
# Daily at 00:34 UTC
- cron: 34 0 * * *
permissions:
contents: read
concurrency:
group: linux-${{ github.workflow }}-${{ github.head_ref || github.run_id }}
cancel-in-progress: true
jobs:
GetMatrix:
runs-on: ubuntu-latest
outputs:
matrix: ${{ steps.set-matrix.outputs.matrix }}
steps:
- name: Determine job matrix
id: set-matrix
uses: actions/github-script@v9
with:
script: |
const matrix = { include: [] };
matrix.include.push({
"build-type": "Debug",
"cmake-preset": "ci-snap-debug"
}, {
"build-type": "Release",
"cmake-preset": "ci-snap"
});
if (context.eventName !== 'merge_group' &&
context.eventName !== 'schedule' &&
!context.ref.startsWith('refs/heads/release/') &&
context.repo.owner === 'canonical' &&
context.repo.repo === 'multipass') {
matrix.include.push({
"build-type": "Coverage",
"cmake-preset": "ci-snap-coverage"
});
}
core.setOutput('matrix', JSON.stringify(matrix));
BuildAndTest:
needs: GetMatrix
permissions:
contents: read
packages: write
if: ${{ !cancelled() }}
outputs:
label: ${{ steps.build-params.outputs.label }}
channel: ${{ steps.build-params.outputs.channel }}
snap-file: ${{ steps.build-snap.outputs.snap-file }}
strategy:
matrix: ${{ fromJSON(needs.GetMatrix.outputs.matrix) }}
fail-fast: ${{ github.event_name == 'merge_group' }}
runs-on: ubuntu-latest
env:
FEED_URL: https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json
SNAPCRAFT_BUILD_INFO: 1
USERNAME: ${{ github.repository_owner }}
VCPKG_BINARY_SOURCES: "clear;nuget,https://nuget.pkg.github.com/${{ github.repository_owner }}/index.json,readwrite"
timeout-minutes: 120
steps:
# Free some disk space to avoid the "No space left on device" error.
- name: Free Disk Space
uses: jlumbroso/free-disk-space@v1.3.1
with:
large-packages: false
swap-storage: false
- name: Install Snapcraft
uses: samuelmeuli/action-snapcraft@v3
- name: Install LXD
uses: canonical/setup-lxd@d492474f6c8ceed1b716bb34c8f575a428871c70
- name: Check out code
uses: actions/checkout@v6
with:
fetch-depth: 0 # Need full history to derive version
submodules: 'recursive'
- name: Determine build parameters
id: build-params
uses: ./.github/actions/build-params
- name: Read snapcraft.yml parameters
uses: ./.github/actions/read-snapcraft-yml-params
- name: Apply snapcraft-ci-override.yaml
env:
MULTIPASS_BUILD_LABEL: ${{ steps.build-params.outputs.label }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
CMAKE_PRESET: ${{ matrix.cmake-preset }}
MP_ALLOW_OPTIONAL_FEATURES: ${{ github.event_name == 'schedule' && 'OFF' || 'ON' }}
run: |
go install github.com/mikefarah/yq/v4@latest
# Substitute the environment variables in the snapcraft-ci-override.yaml
envsubst < snap/local/snapcraft-ci-override.yaml.in | yq eval 'del(.. | select(. == null or . == "")) | del(.. | select((tag == "!!map" or tag == "!!seq") and length == 0))' -P > snap/local/snapcraft-ci-override.yaml
# Merge / override the original snapcraft.yaml
yq eval-all '. as $item ireduce ({}; . *+ $item)' snap/snapcraft.yaml snap/local/snapcraft-ci-override.yaml > snap/snapcraft.yaml.tmp
mv snap/snapcraft.yaml.tmp snap/snapcraft.yaml
# Add CI=true environment variable to all parts' build-environment
yq -i '.parts |= with_entries(.value.build-environment += [{"CI": "true"}])' snap/snapcraft.yaml
- name: Set up vcpkg
id: setup-vcpkg
uses: lukka/run-vcpkg@v11
with:
vcpkgDirectory: '${{ github.workspace }}/3rd-party/vcpkg'
- name: Set up CCache
id: setup-ccache
run: |
sudo apt-get install -y ccache
ccache --max-size=2G
mkdir -p ${HOME}/.ccache
/snap/bin/lxc profile device add default ccache disk source=${HOME}/.ccache/ path=/root/.ccache
# Find common base between main and HEAD to use as cache key.
git -c protocol.version=2 fetch --no-tags --prune --progress --no-recurse-submodules origin main
echo "cache-key=$( git merge-base origin/main ${{ github.sha }} )" >> $GITHUB_OUTPUT
- name: CCache
uses: actions/cache@v5
with:
key: ccache-${{ runner.os }}-${{ matrix.build-type }}-${{ steps.setup-ccache.outputs.cache-key }}
restore-keys: |
ccache-${{ runner.os }}-${{ matrix.build-type }}-
path: ~/.ccache
- name: Set up coverage
id: coverage-setup
if: ${{ matrix.build-type == 'Coverage' }}
run: |
MULTIPASS_PART=${HOME}/multipass_part
mkdir --parents ${MULTIPASS_PART}
/snap/bin/lxc profile device add default build disk source=${MULTIPASS_PART} path=/root/parts/multipass
echo "build=${MULTIPASS_PART}/build" >> $GITHUB_OUTPUT
- name: Configure
# To alleviate the race condition in the Snapcraft's LXD
# integration where the snapd is auto-refreshing itself on
# container start.
# https://github.com/canonical/craft-providers/issues/391
uses: nick-fields/retry@v4
with:
# We have to set a value for this as it's not optional
# https://github.com/nick-fields/retry/issues/51
timeout_minutes: 720 # 12 hours
max_attempts: 5
retry_wait_seconds: 20
retry_on_exit_code: 42
command: |
run_snapcraft() {
tmpfile=$(mktemp)
"$@" |& tee "$tmpfile"
exit_code=${PIPESTATUS[0]}
if [ $exit_code -eq 0 ]; then
return 0
fi
if grep -qE "daemon is stopping to wait for socket activation|Failed to wait for snap refreshes" "$tmpfile"; then
exit 42
fi
exit $exit_code
}
# The auto-refresh race would manifest itself in the first pull attempt.
# Hence wrapping only the first call.
run_snapcraft /snap/bin/snapcraft pull --use-lxd inject-apt-mirrors
/snap/bin/snapcraft pull --use-lxd configure-nuget-cache
/snap/bin/snapcraft pull --use-lxd multipass
- name: Run clang-tidy through the diff
if: ${{ false && matrix.build-type == 'Debug' }}
run: |
/snap/bin/snapcraft pull --use-lxd run-clang-tidy
- name: Build
run: |
# Build the `multipass` part.
/snap/bin/snapcraft build --use-lxd multipass
- name: Clear CCache stats
run: ccache --show-stats --zero-stats
- name: Set /proc/sys/kernel/core_pattern
if: ${{ matrix.build-type == 'Debug' || matrix.build-type == 'Coverage' }}
run : |
# The LXC container share the same "/proc/sys/kernel/core_pattern"
# with the host and it can't be overridden inside the container. Hence
# we need to override it at the runner level.
sudo bash -c 'echo "/coredump/%e.%p.%t" > /proc/sys/kernel/core_pattern'
- name: Test
id: test
if: ${{ matrix.build-type == 'Debug' }}
timeout-minutes: 2
run: |
trap 'echo "MULTIPASS_TESTS_EXIT_CODE=$?" >> $GITHUB_ENV' EXIT
instance_name=`/snap/bin/lxc --project snapcraft --format=csv --columns=n list | grep multipass`
/snap/bin/lxc --project snapcraft start $instance_name
# Let's print the core pattern so we can check if it's successfully propagated to the container.
/snap/bin/lxc --project snapcraft exec $instance_name -- bash -c 'cat /proc/sys/kernel/core_pattern'
# Create the directory for the coredumps
/snap/bin/lxc --project snapcraft exec $instance_name -- bash -c 'mkdir -p /coredump'
# Enable coredumps by setting the core dump size to "unlimited", and run the tests.
/snap/bin/lxc --project snapcraft exec $instance_name -- bash -c "\
ulimit -c unlimited && \
env CTEST_OUTPUT_ON_FAILURE=1 \
LD_LIBRARY_PATH=/root/stage/usr/lib/x86_64-linux-gnu/:/root/stage/lib/:/root/parts/multipass/build/lib/ \
/root/parts/multipass/build/bin/multipass_tests"
- name: Measure coverage
id: measure-coverage
if: ${{ matrix.build-type == 'Coverage' }}
timeout-minutes: 5
run: |
trap 'echo "MULTIPASS_TESTS_EXIT_CODE=$?" >> $GITHUB_ENV' EXIT
instance_name=`/snap/bin/lxc --project snapcraft --format=csv --columns=n list | grep multipass`
/snap/bin/lxc --project snapcraft start $instance_name
# Wait for snapd to actually finish- in particular, that snaps are mounted
timeout 10 sh -c \
'while [ "$( /snap/bin/lxc --project snapcraft exec '$instance_name' -- \
systemctl show --property=ActiveState snapd )" != "ActiveState=active" ]; do sleep 1; done'
# Wait for LXD container network to be ready like Snapcraft does
timeout 40 sh -c \
'while /snap/bin/lxc --project snapcraft exec '$instance_name' -- getent hosts canonical.com ; \
[ $? -ne 0 ] ; do sleep 1; done'
# The following 2 commands workaround the issue in 20.04 where the default parsing of the coverage
# JSON file is extremely slow. This makes is use fast parsing.
/snap/bin/lxc --project snapcraft exec $instance_name -- apt-get -y install libjson-xs-perl sudo
/snap/bin/lxc --project snapcraft exec $instance_name -- \
sh -c "sudo sed -i \"s/use JSON::PP/use JSON::XS/\" \`which geninfo\`"
# Create the directory for the coredumps
/snap/bin/lxc --project snapcraft exec $instance_name -- bash -c 'mkdir -p /coredump'
/snap/bin/lxc --project snapcraft exec $instance_name -- bash -c "\
ulimit -c unlimited && \
env CTEST_OUTPUT_ON_FAILURE=1 \
cmake --build /root/parts/multipass/build --target covreport"
- name: Upload coverage
if: ${{ matrix.build-type == 'Coverage' }}
uses: codecov/codecov-action@v6
with:
directory: ${{ steps.coverage-setup.outputs.build }}
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
- name: Pull coredump and executable from LXC container
if: ${{ failure() && env.MULTIPASS_TESTS_EXIT_CODE != '0'}}
# do not cause job to fail if there are no coredumps available.
continue-on-error: true
run: |
set -o xtrace
# Check whether the test executable is crashed or not.
# If so, we'll need to pull the core dump and the executable from the container to the
# runner, so we can upload them as artifacts later on.
echo "Test executable crashed."
# Make a directory in tmp to pull the coredump(s) and the test executable.
# We'll need both to debug the crash.
mkdir -p /tmp/coredump
instance_name=`/snap/bin/lxc --project snapcraft --format=csv --columns=n list | grep multipass`
# Pull the crashed executable from the container
/snap/bin/lxc --project snapcraft file pull \
-p -r "$instance_name/root/parts/multipass/build/bin/multipass_tests" /tmp/coredump/multipass_tests
echo "Pulled the executable."
# Pull the coredump folder
/snap/bin/lxc --project snapcraft file pull -p -r "$instance_name/coredump" /tmp/coredump
echo "Pulled the coredumps folder."
set +o xtrace
- name: Upload test coredump
uses: actions/upload-artifact@v7
if: ${{ failure() && env.MULTIPASS_TESTS_EXIT_CODE != '0' }}
with:
name: buildandtest-test-crash-${{ runner.os }}-${{ matrix.build-type }}
path: /tmp/coredump/**
- name: Continue on Error comment
uses: mainmatter/continue-on-error-comment@v1
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
outcome: ${{ steps.measure-coverage.outcome }}
test-id: Error with measuring coverage in ${{ matrix.build-type }} build
- name: Build and verify the snap
id: build-snap
if: ${{ matrix.build-type == 'Release' }}
env:
SNAP_ENFORCE_RESQUASHFS: 0
run: |
# Actually build the snap.
/snap/bin/snapcraft --use-lxd
sudo snap install review-tools
/snap/bin/review-tools.snap-review --plugs=snap/local/plugs.json *.snap
echo "snap-file=$( ls *.snap )" >> $GITHUB_OUTPUT
- name: Upload the snap
uses: actions/upload-artifact@v7
if: ${{ matrix.build-type == 'Release' }}
with:
name: ${{ steps.build-snap.outputs.snap-file }}
path: ${{ steps.build-snap.outputs.snap-file }}
if-no-files-found: error
retention-days: 30
# Publish the snap to the store if all is good, a channel was determined, and we have access to secrets.
Publish-Snap:
needs: BuildAndTest
if: ${{
!cancelled()
&& success()
&& github.repository == 'canonical/multipass'
&& needs.BuildAndTest.outputs.channel != ''
&& (github.event_name == 'push'
|| github.event_name == 'merge_group'
|| github.event.pull_request.head.repo.full_name == github.repository)
}}
runs-on: ubuntu-latest
timeout-minutes: 15
steps:
- name: Download the built snap
uses: actions/download-artifact@v8
with:
name: ${{ needs.BuildAndTest.outputs.snap-file }}
- name: Install Snapcraft and log in
uses: samuelmeuli/action-snapcraft@v3
- name: Publish the snap
env:
SNAPCRAFT_STORE_CREDENTIALS: ${{ secrets.SNAPCRAFT_TOKEN }}
run: |
snapcraft upload *.snap --release ${{ needs.BuildAndTest.outputs.channel }}
- name: Delete unused artifacts from github
uses: geekyeggo/delete-artifact@v6
with:
name: ${{ needs.BuildAndTest.outputs.snap-file }}
failOnError: false
Report-Workflow-Failure:
needs: BuildAndTest
if: ${{ !cancelled() && !success() && github.event_name == 'schedule' }}
runs-on: ubuntu-latest
steps:
- name: Report workflow failure
uses: mattermost/action-mattermost-notify@master
with:
MATTERMOST_WEBHOOK_URL: ${{ secrets.MATTERMOST_WEBHOOK_URL }}
MATTERMOST_CHANNEL: multipass
TEXT: |
:red_circle: @mp
Scheduled [Linux](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}) workflow exited before completing.
MATTERMOST_USERNAME: ${{ github.triggering_actor }}
MATTERMOST_ICON_URL: https://www.flaticon.com/free-icon/github-logo_25231
Dispatch-CLI-Tests-Workflow:
permissions:
contents: read
actions: read
checks: write
secrets: inherit
needs:
- BuildAndTest
- Publish-Snap
uses: ./.github/workflows/cli-tests.yml
with:
snap-channel: ${{ needs.BuildAndTest.outputs.channel }}