diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 134288fe1..a40c5f98f 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -19,7 +19,12 @@ jobs: if: ${{ github.repository == 'canonical/lxd-pkg-snap' && github.event_name == 'push' && github.actor != 'dependabot[bot]' }} steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 + + - name: Install Go + uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 + with: + go-version: 'stable' - name: Setup Launchpad SSH access env: @@ -36,11 +41,6 @@ jobs: ssh-keyscan git.launchpad.net >> ~/.ssh/known_hosts ssh-keygen -qlF git.launchpad.net | grep -xF 'git.launchpad.net RSA SHA256:UNOzlP66WpDuEo34Wgs8mewypV0UzqHLsIFoqwe8dYo' - - name: Install Go - uses: actions/setup-go@v5 - with: - go-version: 1.22.x - - name: Trigger Launchpad snap build env: SSH_AUTH_SOCK: /tmp/ssh_agent.sock diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3a82673f1..8400c3f76 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -1,13 +1,14 @@ name: Tests on: - push: pull_request: + paths: + - 'snapcraft/**' permissions: contents: read concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} cancel-in-progress: true defaults: @@ -22,20 +23,20 @@ jobs: runs-on: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: # A non-shallow clone is needed for the Differential ShellCheck fetch-depth: 0 - id: ShellCheck name: Differential ShellCheck - uses: redhat-plumbers-in-action/differential-shellcheck@v5 + uses: redhat-plumbers-in-action/differential-shellcheck@cc6721c45a8800cc666de45493545a07a638d121 # v5.4.0 with: token: ${{ secrets.GITHUB_TOKEN }} if: github.event_name == 'pull_request' - name: Upload artifact with ShellCheck defects in SARIF format - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # v4.4.3 with: name: Differential ShellCheck SARIF path: ${{ steps.ShellCheck.outputs.sarif }} diff --git a/snapcraft.yaml b/snapcraft.yaml index 498c1f068..a2b817916 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -6,6 +6,7 @@ version: git grade: devel summary: LXD - container and VM manager license: AGPL-3.0 +title: LXD description: |- LXD is a system container and virtual machine manager. @@ -51,6 +52,7 @@ description: |- - openvswitch.external: Use the system's OVS tools (ignores openvswitch.builtin) [default=false] - ovn.builtin: Use snap-specific OVN configuration [default=false] - ui.enable: Enable the web interface [default=true] + - zfs.external: Use the system's ZFS tools [default=false] For system-wide configuration of the CLI, place your configuration in /var/snap/lxd/common/global-conf/ (config.yml and servercerts) @@ -191,14 +193,19 @@ parts: - libatomic plugin: nil stage-packages: + # XXX: explicitly depend on libsnappy1v5 due to https://bugs.launchpad.net/ubuntu/+source/ceph/+bug/2072656 - on amd64: - ceph-common + - libsnappy1v5 - on arm64: - ceph-common + - libsnappy1v5 - on ppc64el: - ceph-common + - libsnappy1v5 - on s390x: - ceph-common + - libsnappy1v5 organize: usr/bin/: bin/ usr/lib/: lib/ @@ -247,11 +254,13 @@ parts: - lib/*/librtmp.so* - lib/*/libsasl2.so* - lib/*/libsnappy.so* - - lib/*/libncurses.so* + - lib/*/libssh.so* + - lib/*/libtcmalloc.so* + - lib/*/libunwind.so* criu: source: https://github.com/checkpoint-restore/criu - source-commit: f8b14286b092853a4485813e1efd564109df9123 # v3.19 + source-commit: c2b48ff423aa663b3534a5ba96907366e4c1b408 # v4.0 source-depth: 1 source-type: git plugin: nil @@ -278,7 +287,10 @@ parts: [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && [ "$(uname -m)" != "ppc64le" ] && [ "$(uname -m)" != "s390x" ] && [ "$(uname -m)" != "armv7l" ] && exit 0 set -ex - make USERCFLAGS=-Wno-error=format-truncation criu + git config user.email "noreply@lists.canonical.com" + git config user.name "LXD snap builder" + + make criu mkdir -p "${CRAFT_PART_INSTALL}/criu/" cp criu/criu "${CRAFT_PART_INSTALL}/criu/" organize: @@ -552,6 +564,25 @@ parts: sbin/: bin/ usr/lib/: lib/ usr/sbin/: bin/ + override-build: |- + # Patch lvm.conf + # lvm.conf changes for lvm2 from 22.04/core22 + sed -i \ + -e "s%\(# \)\?obtain_device_list_from_udev = 1%obtain_device_list_from_udev = 0%" \ + -e "s%\(# \)\?cache_file_prefix = \"\"%cache_file_prefix = \"lxd\"%" \ + "${CRAFT_PART_INSTALL}/etc/lvm/lvm.conf" + + # Generic lvm.conf changes + sed -i \ + -e "s%\(# \)\?udev_sync = 1%udev_sync = 0%" \ + -e "s%\(# \)\?udev_rules = 1%udev_rules = 0%" \ + -e "s%\(# \)\?use_lvmetad = 1%use_lvmetad = 0%" \ + -e "s%\(# \)\?monitoring = 1%monitoring = 0%" \ + -e "/# .*_\?executable =/s/# //" \ + -e "s%\(/usr\)\?/s\?bin/%/snap/lxd/current/bin/%" \ + "${CRAFT_PART_INSTALL}/etc/lvm/lvm.conf" + + craftctl default prime: - bin/cache_* - bin/dmeventd @@ -567,6 +598,7 @@ parts: - -bin/lvmetad - -bin/lvmpolld - etc/lvm/lvm.conf + - etc/lvm/profile/* - lib/*/device-mapper/* - lib/*/libaio.so* - lib/*/libdevmapper* @@ -634,12 +666,12 @@ parts: nvidia-container: source: https://github.com/NVIDIA/libnvidia-container - source-commit: 63d366ee3b4183513c310ac557bf31b05b83328f # v1.17.1 + source-commit: 63d366ee3b4183513c310ac557bf31b05b83328f # v1.17.2 source-depth: 1 source-type: git plugin: make build-environment: - - GIT_TAG: "1.17.1" # Enables source-depth: 1, should match git tag without "v" prefix. + - GIT_TAG: "1.17.2" # Enables source-depth: 1, should match git tag without "v" prefix. build-packages: - bmake - curl @@ -676,6 +708,32 @@ parts: - bin/nvidia-container-cli* - lib/libnvidia-container*.so* + nvidia-container-toolkit: + source: https://github.com/NVIDIA/nvidia-container-toolkit + source-depth: 1 + source-commit: fa66e4cd562804509055e44a88f666673e6d27c0 # v1.17.2 + source-type: git + build-snaps: + - go + plugin: make + override-prime: |- + [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && [ "$(uname -m)" != "ppc64le" ] && [ "$(uname -m)" != "s390x" ] && exit 0 + craftctl default + override-pull: |- + [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && [ "$(uname -m)" != "ppc64le" ] && [ "$(uname -m)" != "s390x" ] && exit 0 + craftctl default + override-build: |- + [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && [ "$(uname -m)" != "ppc64le" ] && [ "$(uname -m)" != "s390x" ] && exit 0 + set -ex + + make binaries + mkdir -p "${CRAFT_PART_INSTALL}/bin/" + cp nvidia-ctk "${CRAFT_PART_INSTALL}/bin/" + organize: + usr/bin/: bin/ + prime: + - bin/nvidia-ctk + nvme: plugin: nil stage-packages: @@ -1194,7 +1252,7 @@ parts: zfs-2-2: source: https://github.com/openzfs/zfs - source-commit: 2566592045780e7be7afc899c2496b1ae3af4f4d # zfs-2.2.4 + source-commit: baa50314567afd986a00838f0fa65fdacbd12daf # zfs-2.2.6 source-depth: 1 source-type: git plugin: autotools @@ -1241,7 +1299,7 @@ parts: apparmor: source: https://gitlab.com/apparmor/apparmor.git - source-commit: 84a6bc1b6dcdfeabb1ed3597f01e314f3bcee5c1 # v4.0.2 + source-commit: b4dfdf50f50ed1d64161424d036a2453645f0cfe # v4.0.3 source-depth: 1 source-type: git plugin: autotools @@ -1393,7 +1451,7 @@ parts: - qemu-ovmf-secureboot - nftables source: https://github.com/awslabs/python-uefivars - source-commit: 9679002a4392d8e7831d2dbda3fab41ccc5c6b8c # v1.0.0 + source-commit: ec1eab1717c65ea36ca7160c96fe0e10e071fb66 # v1.2 source-depth: 1 source-type: git plugin: python @@ -1408,6 +1466,7 @@ parts: craftctl default organize: lib/python3.10/site-packages/: lib/python3/dist-packages/ + bin/uefivars: bin/uefivars.py prime: - bin/uefivars.py - lib/python3/dist-packages/google_crc32c* @@ -1464,7 +1523,7 @@ parts: ln -s "$(pwd)" "${GOPATH}/src/github.com/canonical/lxd" # Download the dependencies - go get -d -v ./... + go get -v ./... override-build: | set -ex @@ -1481,10 +1540,19 @@ parts: # Build the binaries go build -trimpath -o "${CRAFT_PART_INSTALL}/bin/lxc" github.com/canonical/lxd/lxc - go build -trimpath -o "${CRAFT_PART_INSTALL}/bin/lxd" -tags=libsqlite3 github.com/canonical/lxd/lxd + + # Build LXD server binary into ${CRAFT_PART_INSTALL}/sbin/lxd so that it does not conflict with the + # lxd-stophook wrapper script which is stored in ${CRAFT_PART_INSTALL}/bin/lxd. + # This way when a container stops it will call "/snap/lxd/current/bin/lxd callhook" which is handled by the + # lxd-stophook script, which in turn will execute "/snap/lxd/current/bin/lxd-user callhook" to notify LXD. + go build -trimpath -o "${CRAFT_PART_INSTALL}/sbin/lxd" -tags=libsqlite3 github.com/canonical/lxd/lxd + + # Build static binaries CGO_ENABLED=0 go build -trimpath -o "${CRAFT_PART_INSTALL}/bin/lxd-agent" -tags=agent,netgo github.com/canonical/lxd/lxd-agent - go build -trimpath -o "${CRAFT_PART_INSTALL}/bin/lxd-user" github.com/canonical/lxd/lxd-user + CGO_ENABLED=0 go build -trimpath -o "${CRAFT_PART_INSTALL}/bin/lxd-user" -tags netgo github.com/canonical/lxd/lxd-user + # Some python dependencies are not available for riscv64 or just require a build from source. + # Not worth the effort for now. if [ "$(uname -m)" != "riscv64" ]; then # Build the static website make doc @@ -1495,21 +1563,31 @@ parts: rm doc/_build/.buildinfo rm -rf doc/_build/_sphinx_design_static/ - # Stage the static website - mkdir -p "${CRAFT_STAGE}/share/lxd-documentation" - cp -a doc/_build/. "${CRAFT_STAGE}/share/lxd-documentation/" + # Copy the static website + mkdir -p "${CRAFT_PART_INSTALL}/share/lxd-documentation" + cp -a doc/_build/. "${CRAFT_PART_INSTALL}/share/lxd-documentation/" fi # Setup bash completion mkdir -p "${CRAFT_PART_INSTALL}/etc/bash_completion.d/" - cp scripts/bash/lxd-client "${CRAFT_PART_INSTALL}/etc/bash_completion.d/snap.lxd.lxc" + # Snapd requires the unaliased command `lxd.lxc` to be supplied as the first command for completion to be detected + set_cmds='s/^\s*complete.*__start_lxc /&lxd.lxc /' + # When executed by snapd, the COLUMNS shell value is unset, so use $(tput cols) instead + set_cols='s/# $COLUMNS.*/COLUMN="$(tput cols)" \# store the current shell width./' + # When executed by snapd, the `compopt` support detection doesn't work so fake that it is always `builtin` + set_compopt='s|$(type -t compopt)|"builtin"|' + # Modify requestComp variable to use lxc based on context ($SNAP/bin/lxc in Snap environment) + set_request_comp='s|requestComp="${words\[0\]} __complete ${args\[\*\]}"|requestComp="/snap/lxd/current/bin/lxc __complete ${args[*]}"|' + # Generate completions script + "${CRAFT_PART_INSTALL}/bin/lxc" completion bash | sed -e "${set_cmds}" -e "${set_cols}" -e "${set_compopt}" -e "${set_request_comp}" > "${CRAFT_PART_INSTALL}/etc/bash_completion.d/snap.lxd.lxc" organize: usr/bin/: bin/ usr/lib/: lib/ usr/share/misc/: share/misc/ var/lib/usbutils/usb.ids: share/misc/ usr/sbin/: bin/ - sbin/: bin/ + sbin/iw: bin/ # core22 installs iw in sbin (not needed for core24 which installs to usr/sbin) + sbin/sgdisk: bin/ prime: - bin/dnsmasq - bin/getfattr @@ -1525,13 +1603,14 @@ parts: - etc/bash_completion.d/snap.lxd.lxc + - share/lxd-documentation* - share/misc/pci.ids - share/misc/usb.ids - bin/lxc - - bin/lxd - bin/lxd-agent - bin/lxd-user + - sbin/lxd lxd-ui: source: https://github.com/canonical/lxd-ui @@ -1595,6 +1674,7 @@ parts: - criu - lxd - shmounts + - nvidia-container-toolkit plugin: nil override-prime: | set -x @@ -1606,10 +1686,12 @@ parts: rm -rf "${CRAFT_PRIME}/usr/share/" # Strip binaries (excluding shell scripts and LXCFS) + # The "${CRAFT_PRIME}/bin/lxd" file is ignored as that is the lxd-stophook wrapper script. find "${CRAFT_PRIME}"/bin -type f \ -not -path "${CRAFT_PRIME}/bin/ceph" \ -not -path "${CRAFT_PRIME}/bin/editor" \ -not -path "${CRAFT_PRIME}/bin/lxc-checkconfig" \ + -not -path "${CRAFT_PRIME}/bin/lxd" \ -not -path "${CRAFT_PRIME}/bin/nvidia-container-cli" \ -not -path "${CRAFT_PRIME}/bin/remote-viewer" \ -not -path "${CRAFT_PRIME}/bin/snap-query" \ @@ -1618,7 +1700,11 @@ parts: -not -path "${CRAFT_PRIME}/bin/xfs_admin" \ -not -path "${CRAFT_PRIME}/bin/uefivars.py" \ -not -path "${CRAFT_PRIME}/bin/lxcfs" \ - -exec strip -s {} + + -not -path "${CRAFT_PRIME}/bin/gpu-2404-custom-wrapper" \ + -exec strip --strip-all {} + + + # This is the actual LXD binary. + strip --strip-all "${CRAFT_PRIME}/sbin/lxd" # Strip binaries not under bin/ due to being dynamically # added to the path with `snap set lxd`, like `criu.enable=true` @@ -1639,13 +1725,6 @@ parts: -not -path "${CRAFT_PRIME}/lib/liblxcfs.so" \ -exec strip -s {} + - if [ "$(uname -m)" != "riscv64" ]; then - # Prime the documentation only if the arch is not riscv64. - # Some python dependencies are not available for riscv64 or just require a build from source. - # Not worth the effort for now. - cp -r "${CRAFT_STAGE}/share/lxd-documentation" "${CRAFT_PRIME}/share/" - fi - # Delete empty directories find "${CRAFT_PRIME}/" -type d -empty -print -delete @@ -1668,6 +1747,7 @@ parts: organize: commands/snap-query: bin/ hooks/: snap/hooks/ + wrappers/lxd-stophook: bin/lxd wrappers/editor: bin/ wrappers/remote-viewer: bin/ wrappers/sshfs: bin/ diff --git a/snapcraft/commands/daemon.start b/snapcraft/commands/daemon.start index db84d98b9..e2afd68a2 100755 --- a/snapcraft/commands/daemon.start +++ b/snapcraft/commands/daemon.start @@ -23,7 +23,7 @@ export HOME="/tmp/" export LXD_DIR="${SNAP_COMMON}/lxd/" export LXD_LXC_TEMPLATE_CONFIG="${SNAP_CURRENT}/lxc/config/" export LXD_LXC_HOOK="${SNAP_CURRENT}/lxc/hooks/" -export LXD_EXEC_PATH="${SNAP_CURRENT}/bin/lxd" +export LXD_EXEC_PATH="${SNAP_CURRENT}/sbin/lxd" export LD_LIBRARY_PATH="${LD_LIBRARY_PATH:-}:${SNAP_CURRENT}/lib:${SNAP_CURRENT}/lib/${ARCH}:${SNAP_CURRENT}/lib/${ARCH}/ceph" export PATH="${PATH}:${SNAP_CURRENT}/bin" export LXD_CLUSTER_UPDATE="${SNAP_CURRENT}/commands/refresh" @@ -204,6 +204,12 @@ if [ "${lvm_external:-"false"}" = "true" ]; then ln -s "${SNAP}/wrappers/run-host" "/run/bin/lvresize" fi +if [ "${zfs_external:-"false"}" = "true" ]; then + ln -s "${SNAP}/wrappers/run-host" "/run/bin/zfs" + ln -s "${SNAP}/wrappers/run-host" "/run/bin/zpool" + ln -s "${SNAP}/wrappers/run-host" "/run/bin/zvol_id" +fi + # Detect presence of sideloaded lxd-agent executable. if [ -x "${SNAP_COMMON}/lxd-agent.debug" ]; then echo "==> WARNING: Using a custom debug lxd-agent binary!" @@ -311,19 +317,16 @@ else fi # Setup for LVM -echo "==> Setting up LVM configuration" -mkdir -p /etc/lvm/ -sed \ - -e "s#obtain_device_list_from_udev = 1#obtain_device_list_from_udev = 0#g" \ - -e "s#cache_file_prefix = \"\"#cache_file_prefix = \"lxd\"#g" \ - -e "s#udev_sync = 1#udev_sync = 0#g" \ - -e "s#udev_rules = 1#udev_rules = 0#g" \ - -e "s#use_lvmetad = 1#use_lvmetad = 0#g" \ - -e "s#monitoring = 1#monitoring = 0#g" \ - -e "s%# executable = \"/sbin/dmeventd\"%executable = \"${SNAP}/bin/dmeventd\"%g" \ - -e "/# .*_executable =/s/# //g" \ - -e "s#/usr/sbin/#${SNAP}/bin/#g" \ - "${SNAP}/etc/lvm/lvm.conf" > /etc/lvm/lvm.conf +if [ "${lvm_external:-"false"}" = "false" ]; then + echo "==> Setting up LVM configuration" + # XXX: the directory ${SNAP}/etc/lvm cannot be symlink'ed as LVM tools try + # to create /etc/lvm/{archive,backup} dirs which is not possible as ${SNAP} + # is read-only. + mkdir -p /etc/lvm + ln -sf "${SNAP}/etc/lvm/lvm.conf" /etc/lvm/ + # the /etc/lvm/profile dir is however only read from so a symlink is OK + ln -sf "${SNAP}/etc/lvm/profile" /etc/lvm/ +fi # Setup for OVN echo "==> Setting up OVN configuration" @@ -370,22 +373,28 @@ echo "==> Rotating logs" logrotate -f "${SNAP}/etc/logrotate.conf" -s "/etc/logrotate.status" || true # Setup for ZFS -if [ -e /sys/module/zfs/version ]; then - read -r VERSION < /sys/module/zfs/version -else - VERSION=$(nsenter -t 1 -m modinfo -F version zfs 2>/dev/null || true) -fi +if [ "${zfs_external:-"false"}" = "false" ]; then + if [ -e /sys/module/zfs/version ]; then + read -r VERSION < /sys/module/zfs/version + else + VERSION=$(nsenter -t 1 -m modinfo -F version zfs 2>/dev/null || true) + fi -ZFS_VER="$(echo "${VERSION}" | cut -c 1-3)" + ZFS_VER="$(echo "${VERSION}" | cut -c 1-3)" -if [ -d "${SNAP_CURRENT}/zfs-${ZFS_VER}/bin" ]; then - echo "==> Setting up ZFS (${ZFS_VER})" - export LD_LIBRARY_PATH="${SNAP_CURRENT}/zfs-${ZFS_VER}/lib/:${LD_LIBRARY_PATH}" - export PATH="${SNAP_CURRENT}/zfs-${ZFS_VER}/bin:${PATH}" -elif [ -n "${ZFS_VER}" ]; then - echo "==> Unsupported ZFS version (${ZFS_VER})" + if [ -d "${SNAP_CURRENT}/zfs-${ZFS_VER}/bin" ]; then + echo "==> Setting up ZFS (${ZFS_VER})" + export LD_LIBRARY_PATH="${SNAP_CURRENT}/zfs-${ZFS_VER}/lib/:${LD_LIBRARY_PATH}" + export PATH="${SNAP_CURRENT}/zfs-${ZFS_VER}/bin:${PATH}" + elif [ -n "${ZFS_VER}" ]; then + echo "==> Unsupported ZFS version (${ZFS_VER})" + echo "Consider installing ZFS tools in the host and use zfs.external" + else + echo "==> No ZFS support" + echo "Consider installing ZFS tools in the host and use zfs.external" + fi else - echo "==> No ZFS support" + echo "==> Using ZFS tools from the host system" fi # Escape resource limits diff --git a/snapcraft/hooks/configure b/snapcraft/hooks/configure index 62e074d81..9a3208f59 100755 --- a/snapcraft/hooks/configure +++ b/snapcraft/hooks/configure @@ -58,6 +58,7 @@ openvswitch_builtin=$(get_bool "$(snapctl get openvswitch.builtin)") openvswitch_external=$(get_bool "$(snapctl get openvswitch.external)") ovn_builtin=$(get_bool "$(snapctl get ovn.builtin)") ui_enable=$(get_bool "$(snapctl get ui.enable)") +zfs_external=$(get_bool "$(snapctl get zfs.external)") # Special-handling of daemon.preseed daemon_preseed=$(snapctl get daemon.preseed) @@ -89,6 +90,7 @@ openvswitch_builtin=${openvswitch_builtin:-"false"} openvswitch_external=${openvswitch_external:-"false"} ovn_builtin=${ovn_builtin:-"false"} ui_enable=${ui_enable:-"true"} +zfs_external=${zfs_external:-"false"} EOC # Set socket ownership in case it changed diff --git a/snapcraft/wrappers/lxd-stophook b/snapcraft/wrappers/lxd-stophook new file mode 100755 index 000000000..fbb01f418 --- /dev/null +++ b/snapcraft/wrappers/lxd-stophook @@ -0,0 +1,9 @@ +#!/bin/sh +# Use exec so that this script process is replaced. +# This avoids polluting the process tree with this wrapper script. +if [ "$1" = "callhook" ]; then + exec /snap/lxd/current/bin/lxd-user "$@" +fi + +echo "lxd-stophook: Invalid argument: ${1}" >&2 +exit 1