diff --git a/.github/labeler.yml b/.github/labeler.yml new file mode 100644 index 000000000..610a6a813 --- /dev/null +++ b/.github/labeler.yml @@ -0,0 +1,8 @@ +"5.21 LTS": +- base-branch: '^5\.21-.+$' + +"5.0 LTS": +- base-branch: '^5\.0-.+$' + +"4.0 LTS": +- base-branch: '^4\.0-.+$' diff --git a/.github/workflows/builds.yml b/.github/workflows/builds.yml index 3bae31b38..60a7f24b1 100644 --- a/.github/workflows/builds.yml +++ b/.github/workflows/builds.yml @@ -1,6 +1,5 @@ name: Builds on: - pull_request: push: branches: - latest-candidate @@ -9,72 +8,37 @@ permissions: contents: read concurrency: - group: ${{ github.workflow }}-${{ github.ref }} + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} cancel-in-progress: true jobs: - lxd-migrate: - name: Test lxd-migrate build - runs-on: ubuntu-22.04 - steps: - - name: Checkout code - uses: actions/checkout@v4 - - - name: Install Go - uses: actions/setup-go@v5 - with: - go-version: 1.20.x - - - name: Test lxd-migrate build - run: | - set -eux - cd ~/work/lxd-pkg-snap/lxd-pkg-snap/lxd-migrate - CGO_ENABLED=0 go build -v -tags netgo - snap: name: Trigger snap build - runs-on: ubuntu-22.04 - needs: lxd-migrate - if: ${{ github.repository == 'canonical/lxd-pkg-snap' && github.event_name == 'push' && github.actor != 'dependabot[bot]' }} + runs-on: ubuntu-24.04 + if: ${{ github.repository == 'canonical/lxd-pkg-snap' && github.actor != 'dependabot[bot]' }} + env: + SSH_AUTH_SOCK: /tmp/ssh_agent.sock + PACKAGE: "lxd" + REPO: "git+ssh://lxdbot@git.launchpad.net/~lxd-snap/lxd" + BRANCH: ${{ github.ref_name }} steps: - name: Checkout code - uses: actions/checkout@v3 - - - name: Setup Launchpad SSH access - env: - SSH_AUTH_SOCK: /tmp/ssh_agent.sock - LAUNCHPAD_LXD_BOT_KEY: ${{ secrets.LAUNCHPAD_LXD_BOT_KEY }} - run: | - ssh-agent -a "${SSH_AUTH_SOCK}" > /dev/null - ssh-add - <<< "${{ secrets.LAUNCHPAD_LXD_BOT_KEY }}" - mkdir -m 0700 -p ~/.ssh/ - # In ephemeral environments like GitHub Action runners, relying on TOFU isn't providing any security - # so require the key obtained by `ssh-keyscan` to match the expected hash from https://help.launchpad.net/SSHFingerprints - ssh-keyscan git.launchpad.net >> ~/.ssh/known_hosts - ssh-keygen -qlF git.launchpad.net | grep -xF 'git.launchpad.net RSA SHA256:UNOzlP66WpDuEo34Wgs8mewypV0UzqHLsIFoqwe8dYo' + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Install Go - uses: actions/setup-go@v5 + - uses: canonical/lxd/.github/actions/lp-snap-build@main with: - go-version: 1.20.x + ssh-key: "${{ secrets.LAUNCHPAD_LXD_BOT_KEY}}" - name: Trigger Launchpad snap build - env: - SSH_AUTH_SOCK: /tmp/ssh_agent.sock - TARGET: ${{ github.ref_name }} run: | - set -x - git config --global user.name "Canonical LXD Bot" - git config --global user.email "lxd@lists.canonical.com" - localRev=$(git rev-parse HEAD) - go install github.com/canonical/lxd-ci/lxd-snapcraft@latest - git clone -b "${TARGET}" git+ssh://lxdbot@git.launchpad.net/~canonical-lxd/lxd ~/lxd-pkg-snap-lp - originVer=($(lxd-snapcraft -get-version -file snapcraft.yaml)) - rsync -a --exclude .git --delete . ~/lxd-pkg-snap-lp/ - cd ~/lxd-pkg-snap-lp - lxd-snapcraft -set-version "${originVer[0]}-${localRev:0:7}" -set-source-commit "" + set -eux + localRev="$(git rev-parse HEAD)" + # XXX: `originVer` contains an array with the 2 versions + originVer=($(lxd-snapcraft -package "${PACKAGE}" -get-version -file snapcraft.yaml)) + rsync -a --exclude .git --delete . ~/"${PACKAGE}-pkg-snap-lp"/ + cd ~/"${PACKAGE}-pkg-snap-lp" + lxd-snapcraft -package lxd -set-version "${originVer[0]}-${localRev:0:7}" -set-source-commit "" git add --all - git commit --all --quiet -s --allow-empty -m "Automatic upstream build (${TARGET})" -m "Upstream commit: ${localRev}" + git commit --all --quiet -s --allow-empty -m "Automatic upstream build (${BRANCH})" -m "Upstream commit: ${localRev}" git show git push --quiet - diff --git a/.github/workflows/commits.yml b/.github/workflows/commits.yml index bacbcb17a..15352701e 100644 --- a/.github/workflows/commits.yml +++ b/.github/workflows/commits.yml @@ -6,31 +6,18 @@ permissions: contents: read jobs: - dco-check: - permissions: - pull-requests: read # for tim-actions/get-pr-commits to get list of commits from the PR - name: Signed-off-by (DCO) and branch target - runs-on: ubuntu-22.04 + commits: + name: Branch target + runs-on: ubuntu-24.04 steps: - - name: Get PR Commits - id: 'get-pr-commits' - uses: tim-actions/get-pr-commits@master - with: - token: ${{ secrets.GITHUB_TOKEN }} - - - name: Check that all commits are signed-off - uses: tim-actions/dco@master - with: - commits: ${{ steps.get-pr-commits.outputs.commits }} - - name: Check branch target env: TARGET: ${{ github.event.pull_request.base.ref }} TITLE: ${{ github.event.pull_request.title }} if: ${{ github.actor != 'dependabot[bot]' }} run: | - set -x - TARGET_FROM_PR_TITLE="$(echo "${TITLE}" | sed -n 's/.*(\(\(latest\|[0-9]\.[0-9]\)-\(edge\|candidate\)\))$/\1/p')" + set -eux + TARGET_FROM_PR_TITLE="$(echo "${TITLE}" | sed -n 's/.*(\(\(latest\|[0-9]\+\.[0-9]\+\)-\(edge\|candidate\)\))$/\1/p')" if [ -z "${TARGET_FROM_PR_TITLE}" ]; then TARGET_FROM_PR_TITLE="latest-edge" else diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml new file mode 100644 index 000000000..97282f04f --- /dev/null +++ b/.github/workflows/tests.yml @@ -0,0 +1,46 @@ +name: Tests +on: + pull_request: + paths: + - 'snapcraft/**' + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }}-${{ github.event_name }} + cancel-in-progress: true + +defaults: + run: + # Make sure bash is always invoked with `-eo pipefail` + # https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsshell + shell: bash + +jobs: + code-tests: + name: Code + runs-on: ubuntu-24.04 + steps: + - name: Checkout + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + # A non-shallow clone is needed for the Differential ShellCheck + fetch-depth: 0 + + - name: Require GHA pinning + uses: canonical/lxd/.github/actions/require-gha-pinning@main + + - id: ShellCheck + name: Differential ShellCheck + uses: redhat-plumbers-in-action/differential-shellcheck@d965e66ec0b3b2f821f75c8eff9b12442d9a7d1e # v5.5.6 + with: + token: ${{ secrets.GITHUB_TOKEN }} + if: github.event_name == 'pull_request' + + - name: Upload artifact with ShellCheck defects in SARIF format + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + with: + name: Differential ShellCheck SARIF + path: ${{ steps.ShellCheck.outputs.sarif }} + if: github.event_name == 'pull_request' diff --git a/.gitignore b/.gitignore index 85710b6fa..130ae666c 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ snap/ stage/ *.snap edk2-vars-generator/UEFI/__pycache__/ +.github/dependabot.yml +renovate.json diff --git a/README.md b/README.md new file mode 100644 index 000000000..2f7df8a75 --- /dev/null +++ b/README.md @@ -0,0 +1,23 @@ +# LXD + +LXD is a modern, secure and powerful system container and virtual machine manager. + +This is the snap packaging repository that is used to build the [LXD snap](https://snapcraft.io/lxd). The LXD repository is available [here](https://github.com/canonical/lxd). + +# Build the LXD snap locally + +Local build require the LXD snap to be installed as `snapcraft` creates a container to use as build environment. Here's how to do a local build for the native architecture: + +``` +snapcraft +``` + +# Build the LXD snap on Launchpad + +To build the snap for multiple architectures, Launchpad builders can be used. + +They are available for various architectures (`amd64`, `armhf`, `arm64`, `ppc64el`, `riscv64` and `s390x`) and you can ask for multiple to be built in parallel. Here's how to build for both `amd64` and `arm64`: + +``` +snapcraft remote-build --launchpad-accept-public-upload --build-for amd64,arm64 +``` diff --git a/edk2-vars-generator/UEFI/Qemu.py b/edk2-vars-generator/UEFI/Qemu.py index d4d866848..72d5ee5fe 100644 --- a/edk2-vars-generator/UEFI/Qemu.py +++ b/edk2-vars-generator/UEFI/Qemu.py @@ -37,7 +37,7 @@ class QemuEfiVariant(enum.Enum): class QemuEfiFlashSize(enum.Enum): - DEFAULT = enum.auto + DEFAULT = enum.auto() SIZE_2MB = enum.auto() SIZE_4MB = enum.auto() diff --git a/lxd-migrate/db.go b/lxd-migrate/db.go deleted file mode 100644 index 41c287726..000000000 --- a/lxd-migrate/db.go +++ /dev/null @@ -1,68 +0,0 @@ -package main - -import ( - "database/sql" - "fmt" - "os" - "path/filepath" - "strings" - - _ "github.com/mattn/go-sqlite3" - - "github.com/canonical/lxd/shared" -) - -func dbRewritePoolSource(src *lxdDaemon, dst *lxdDaemon, pool string, path string) error { - if strings.HasPrefix(src.info.Environment.ServerVersion, "2.") { - // LXD 2.x target - db, err := sql.Open("sqlite3", filepath.Join(dst.path, "lxd.db")) - if err != nil { - return err - } - - _, err = db.Exec("UPDATE storage_pools_config SET value=? WHERE key='source' AND storage_pool_id=(SELECT id FROM storage_pools WHERE name=?);", path, pool) - if err != nil { - return err - } - - err = db.Close() - if err != nil { - return err - } - - return nil - } - - // Recent LXD target - if !shared.PathExists(filepath.Join(dst.path, "database")) { - err := os.MkdirAll(filepath.Join(dst.path, "database"), 0700) - if err != nil { - return err - } - } - - // Get the node name - nodeName := "none" - if src.info.Environment.ServerClustered { - nodeName = src.info.Environment.ServerName - } - - // Setup the DB patch - patchPath := filepath.Join(dst.path, "database", "patch.global.sql") - patch, err := os.OpenFile(patchPath, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0600) - if err != nil { - return err - } - - _, err = patch.WriteString(fmt.Sprintf("UPDATE storage_pools_config SET value='%s' WHERE key='source' AND storage_pool_id=(SELECT id FROM storage_pools WHERE name='%s') AND node_id=(SELECT id FROM nodes WHERE name='%s');\n", path, pool, nodeName)) - if err != nil { - return err - } - - err = patch.Close() - if err != nil { - return err - } - - return nil -} diff --git a/lxd-migrate/go.mod b/lxd-migrate/go.mod deleted file mode 100644 index e5777b237..000000000 --- a/lxd-migrate/go.mod +++ /dev/null @@ -1,45 +0,0 @@ -module github.com/canonical/lxd-pkg-snap/lxd-migrate - -go 1.20 - -replace google.golang.org/grpc/naming => google.golang.org/grpc v1.59.0 - -require ( - github.com/canonical/lxd v0.0.0-20231211123743-7294d23f5359 - github.com/mattn/go-sqlite3 v1.14.18 -) - -require ( - github.com/flosch/pongo2 v0.0.0-20200913210552-0d938eb266f3 // indirect - github.com/go-macaroon-bakery/macaroon-bakery/v3 v3.0.1 // indirect - github.com/go-macaroon-bakery/macaroonpb v1.0.0 // indirect - github.com/golang/protobuf v1.5.3 // indirect - github.com/google/uuid v1.4.0 // indirect - github.com/gorilla/schema v1.2.1 // indirect - github.com/gorilla/securecookie v1.1.2 // indirect - github.com/gorilla/websocket v1.5.1 // indirect - github.com/juju/webbrowser v1.0.0 // indirect - github.com/julienschmidt/httprouter v1.3.0 // indirect - github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect - github.com/kr/fs v0.1.0 // indirect - github.com/muhlemmer/gu v0.3.1 // indirect - github.com/pkg/sftp v1.13.6 // indirect - github.com/pkg/xattr v0.4.9 // indirect - github.com/robfig/cron/v3 v3.0.1 // indirect - github.com/rogpeppe/fastuuid v1.2.0 // indirect - github.com/sirupsen/logrus v1.9.3 // indirect - github.com/zitadel/oidc/v2 v2.12.0 // indirect - golang.org/x/crypto v0.16.0 // indirect - golang.org/x/net v0.19.0 // indirect - golang.org/x/oauth2 v0.15.0 // indirect - golang.org/x/sys v0.15.0 // indirect - golang.org/x/term v0.15.0 // indirect - golang.org/x/text v0.14.0 // indirect - google.golang.org/appengine v1.6.8 // indirect - google.golang.org/protobuf v1.31.0 // indirect - gopkg.in/errgo.v1 v1.0.1 // indirect - gopkg.in/httprequest.v1 v1.2.1 // indirect - gopkg.in/macaroon.v2 v2.1.0 // indirect - gopkg.in/square/go-jose.v2 v2.6.0 // indirect - gopkg.in/yaml.v2 v2.4.0 // indirect -) diff --git a/lxd-migrate/go.sum b/lxd-migrate/go.sum deleted file mode 100644 index b5fff4b5f..000000000 --- a/lxd-migrate/go.sum +++ /dev/null @@ -1,224 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/canonical/lxd v0.0.0-20231211123743-7294d23f5359 h1:hPbnAhwSZK/9GxCDo6VlDNEB3gQm4UahuXmq6NixQTw= -github.com/canonical/lxd v0.0.0-20231211123743-7294d23f5359/go.mod h1:UxfHGKFoRjgu1NUA9EFiR++dKvyAiT0h9HT0ffMlzjc= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= -github.com/flosch/pongo2 v0.0.0-20200913210552-0d938eb266f3 h1:fmFk0Wt3bBxxwZnu48jqMdaOR/IZ4vdtJFuaFV8MpIE= -github.com/flosch/pongo2 v0.0.0-20200913210552-0d938eb266f3/go.mod h1:bJWSKrZyQvfTnb2OudyUjurSG4/edverV7n82+K3JiM= -github.com/frankban/quicktest v1.0.0/go.mod h1:R98jIehRai+d1/3Hv2//jOVCTJhW1VBavT6B6CuGq2k= -github.com/frankban/quicktest v1.2.2/go.mod h1:Qh/WofXFeiAFII1aEBu529AtJo6Zg2VHscnEsbBnJ20= -github.com/frankban/quicktest v1.7.2/go.mod h1:jaStnuzAqU1AJdCO0l53JDCJrVDKcS03DbaAcR7Ks/o= -github.com/frankban/quicktest v1.10.0/go.mod h1:ui7WezCLWMWxVWr1GETZY3smRy0G4KWq9vcPtJmFl7Y= -github.com/frankban/quicktest v1.11.3 h1:8sXhOn0uLys67V8EsXLc6eszDs8VXWxL3iRvebPhedY= -github.com/go-logr/logr v1.3.0 h1:2y3SDp0ZXuc6/cjLSZ+Q3ir+QB9T/iG5yYRXqsagWSY= -github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= -github.com/go-macaroon-bakery/macaroon-bakery/v3 v3.0.1 h1:uvQJoKTHrFFu8zxoaopNKedRzwdy3+8H72we4T/5cGs= -github.com/go-macaroon-bakery/macaroon-bakery/v3 v3.0.1/go.mod h1:H59IYeChwvD1po3dhGUPvq5na+4NVD7SJlbhGKvslr0= -github.com/go-macaroon-bakery/macaroonpb v1.0.0 h1:It9exBaRMZ9iix1iJ6gwzfwsDE6ExNuwtAJ9e09v6XE= -github.com/go-macaroon-bakery/macaroonpb v1.0.0/go.mod h1:UzrGOcbiwTXISFP2XDLDPjfhMINZa+fX/7A2lMd31zc= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= -github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= -github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= -github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= -github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= -github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= -github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg= -github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/go-cmp v0.2.1-0.20190312032427-6f77996f0c42/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= -github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0= -github.com/google/uuid v1.4.0 h1:MtMxsa51/r9yyhkyLsVeVt0B+BGQZzpQiTQ4eHZ8bc4= -github.com/google/uuid v1.4.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gorilla/mux v1.8.1 h1:TuBL49tXwgrFYWhqrNgrUNEY92u81SPhu7sTdzQEiWY= -github.com/gorilla/schema v1.2.1 h1:tjDxcmdb+siIqkTNoV+qRH2mjYdr2hHe5MKXbp61ziM= -github.com/gorilla/schema v1.2.1/go.mod h1:Dg5SSm5PV60mhF2NFaTV1xuYYj8tV8NOPRo4FggUMnM= -github.com/gorilla/securecookie v1.1.2 h1:YCIWL56dvtr73r6715mJs5ZvhtnY73hBvEF8kXD8ePA= -github.com/gorilla/securecookie v1.1.2/go.mod h1:NfCASbcHqRSY+3a8tlWJwsQap2VX5pwzwo4h3eOamfo= -github.com/gorilla/websocket v1.5.1 h1:gmztn0JnHVt9JZquRuzLw3g4wouNVzKL15iLr/zn/QY= -github.com/gorilla/websocket v1.5.1/go.mod h1:x3kM2JMyaluk02fnUJpQuwD2dCS5NDG2ZHL0uE0tcaY= -github.com/jeremija/gosubmit v0.2.7 h1:At0OhGCFGPXyjPYAsCchoBUhE099pcBXmsb4iZqROIc= -github.com/juju/qthttptest v0.1.1/go.mod h1:aTlAv8TYaflIiTDIQYzxnl1QdPjAg8Q8qJMErpKy6A4= -github.com/juju/qthttptest v0.1.3 h1:M0HdpwsK/UTHRGRcIw5zvh5z+QOgdqyK+ecDMN+swwM= -github.com/juju/webbrowser v1.0.0 h1:JLdmbFtCGY6Qf2jmS6bVaenJFGIFkdF1/BjUm76af78= -github.com/juju/webbrowser v1.0.0/go.mod h1:RwVlbBcF91Q4vS+iwlkJ6bZTE3EwlrjbYlM3WMVD6Bc= -github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= -github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= -github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= -github.com/kr/fs v0.1.0 h1:Jskdu9ieNAYnjxsi0LbQp1ulIKZV1LAFgK1tWhpZgl8= -github.com/kr/fs v0.1.0/go.mod h1:FFnZGqtBN9Gxj7eW1uZ42v5BccTP0vu6NEaFoC2HwRg= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.2.0/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI= -github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/mattn/go-sqlite3 v1.14.18 h1:JL0eqdCOq6DJVNPSvArO/bIV9/P7fbGrV00LZHc+5aI= -github.com/mattn/go-sqlite3 v1.14.18/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= -github.com/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM= -github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM= -github.com/muhlemmer/httpforwarded v0.1.0 h1:x4DLrzXdliq8mprgUMR0olDvHGkou5BJsK/vWUetyzY= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e h1:fD57ERR4JtEqsWbfPhv4DMiApHyliiK5xCTNVSPiaAs= -github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= -github.com/pkg/sftp v1.13.6 h1:JFZT4XbOU7l77xGSpOdW+pwIMqP044IyjXX6FGyEKFo= -github.com/pkg/sftp v1.13.6/go.mod h1:tz1ryNURKu77RL+GuCzmoJYxQczL3wLNNpPWagdg4Qk= -github.com/pkg/xattr v0.4.9 h1:5883YPCtkSd8LFbs13nXplj9g9tlrwoJRjgpgMu1/fE= -github.com/pkg/xattr v0.4.9/go.mod h1:di8WF84zAKk8jzR1UBTEWh9AUlIZZ7M/JNt8e9B6ktU= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= -github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs= -github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro= -github.com/rogpeppe/fastuuid v1.2.0 h1:Ppwyp6VYCF1nvBTXL3trRso7mXMlRrw9ooo375wvi2s= -github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= -github.com/rs/cors v1.10.1 h1:L0uuZVXIKlI1SShY2nhFfo44TYvDPQ1w4oFkUJNfhyo= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= -github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= -github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -github.com/zitadel/oidc/v2 v2.12.0 h1:4aMTAy99/4pqNwrawEyJqhRb3yY3PtcDxnoDSryhpn4= -github.com/zitadel/oidc/v2 v2.12.0/go.mod h1:LrRav74IiThHGapQgCHZOUNtnqJG0tcZKHro/91rtLw= -go.opentelemetry.io/otel v1.21.0 h1:hzLeKBZEL7Okw2mGzZ0cc4k/A7Fta0uoPgaJCr8fsFc= -go.opentelemetry.io/otel/metric v1.21.0 h1:tlYWfeo+Bocx5kLEloTjbcDwBuELRrIFxwdQ36PlJu4= -go.opentelemetry.io/otel/trace v1.21.0 h1:WD9i5gzvoUPuXIXH24ZNBudiarZDKuekPqi/E8fpfLc= -golang.org/x/crypto v0.0.0-20180723164146-c126467f60eb/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.1.0/go.mod h1:RecgLatLF4+eUMCP1PoPZQb+cVrJcOPbHkTkbkB9sbw= -golang.org/x/crypto v0.16.0 h1:mMMrFzRSCF0GvB7Ne27XVtVAaXLrPmgPC7/v0tkwHaY= -golang.org/x/crypto v0.16.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/net v0.0.0-20200505041828-1ed23360d12c/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco= -golang.org/x/net v0.19.0 h1:zTwKpTd2XuCqf8huc7Fo2iSy+4RHPd10s4KzeTnVr1c= -golang.org/x/net v0.19.0/go.mod h1:CfAk/cbD4CthTvqiEl8NpboMuiuOYsAr/7NOjZJtv1U= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.15.0 h1:s8pnnxNVzjWyrvYdFUQq5llS1PX2zhPXmccZv99h7uQ= -golang.org/x/oauth2 v0.15.0/go.mod h1:q48ptWNTY5XWf+JNten23lcvHpLJ0ZSxF5ttTHKVCAM= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220408201424-a24fb2fb8a0f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= -golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4= -golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= -golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= -golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= -golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= -google.golang.org/appengine v1.6.8/go.mod h1:1jJ3jBArFh5pcgW8gCtRJnepW8FzD1V44FJffLiz/Ds= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= -google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= -google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= -google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= -google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= -google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= -google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c= -google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= -google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= -google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8= -google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b h1:QRR6H1YWRnHb4Y/HeNFCTJLFVxaq6wH4YuVdsUOr75U= -gopkg.in/check.v1 v1.0.0-20200902074654-038fdea0a05b/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v1 v1.0.0/go.mod h1:CxwszS/Xz1C49Ucd2i6Zil5UToP1EmyrFhKaMVbg1mk= -gopkg.in/errgo.v1 v1.0.1 h1:oQFRXzZ7CkBGdm1XZm/EbQYaYNNEElNBOd09M6cqNso= -gopkg.in/errgo.v1 v1.0.1/go.mod h1:3NjfXwocQRYAPTq4/fzX+CwUhPRcR/azYRhj8G+LqMo= -gopkg.in/httprequest.v1 v1.2.1 h1:pEPLMdF/gjWHnKxLpuCYaHFjc8vAB2wrYjXrqDVC16E= -gopkg.in/httprequest.v1 v1.2.1/go.mod h1:x2Otw96yda5+8+6ZeWwHIJTFkEHWP/qP8pJOzqEtWPM= -gopkg.in/macaroon.v2 v2.1.0 h1:HZcsjBCzq9t0eBPMKqTN/uSN6JOm78ZJ2INbqcBQOUI= -gopkg.in/macaroon.v2 v2.1.0/go.mod h1:OUb+TQP/OP0WOerC2Jp/3CwhIKyIa9kQjuc7H24e6/o= -gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22 h1:VpOs+IwYnYBaFnrNAeB8UUWtL3vEUnzSCL1nVjPhqrw= -gopkg.in/mgo.v2 v2.0.0-20190816093944-a6b53ec6cb22/go.mod h1:yeKp02qBN3iKW1OzL3MGk2IdtZzaj7SFntXj72NppTA= -gopkg.in/square/go-jose.v2 v2.6.0 h1:NGk74WTnPKBNUhNzQX7PYcTLUjoq7mzKk2OKbvwk2iI= -gopkg.in/square/go-jose.v2 v2.6.0/go.mod h1:M9dMgbHiYLoDGQrXy7OpJDJWiKiU//h+vD76mk0e1AI= -gopkg.in/yaml.v2 v2.2.7/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= -gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= -gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/lxd-migrate/lxd.go b/lxd-migrate/lxd.go deleted file mode 100644 index 171e8879d..000000000 --- a/lxd-migrate/lxd.go +++ /dev/null @@ -1,535 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "io/ioutil" - "os" - "path/filepath" - "sort" - "strings" - "syscall" - "time" - - "github.com/canonical/lxd/client" - "github.com/canonical/lxd/shared" - "github.com/canonical/lxd/shared/api" -) - -type lxdDaemon struct { - s lxd.ContainerServer - path string - - info *api.Server - containers []api.Container - images []api.Image - networks []api.Network - storagePools []api.StoragePool -} - -func lxdConnect(path string) (*lxdDaemon, error) { - // Connect to the LXD daemon - s, err := lxd.ConnectLXDUnix(fmt.Sprintf("%s/unix.socket", path), nil) - if err != nil { - return nil, err - } - - // Setup our internal struct - d := &lxdDaemon{s: s, path: path} - - // Get a bunch of data from the daemon - err = d.update() - if err != nil { - return nil, err - } - - return d, nil -} - -func (d *lxdDaemon) update() error { - // Daemon - info, _, err := d.s.GetServer() - if err != nil { - return err - } - - d.info = info - - // Containers - containers, err := d.s.GetContainers() - if err != nil { - return err - } - - d.containers = containers - - // Images - images, err := d.s.GetImages() - if err != nil { - return err - } - - d.images = images - - // Networks - if d.s.HasExtension("network") { - networks, err := d.s.GetNetworks() - if err != nil { - return err - } - - // We only care about the managed ones - d.networks = []api.Network{} - for _, network := range networks { - if network.Managed { - d.networks = append(d.networks, network) - } - } - } - - // Storage pools - if d.s.HasExtension("storage") { - pools, err := d.s.GetStoragePools() - if err != nil { - return err - } - - d.storagePools = pools - } - - return nil -} - -func (d *lxdDaemon) checkEmpty() error { - // Containers - if len(d.containers) > 0 { - return fmt.Errorf("Target LXD already has containers, aborting.") - } - - // Images - if len(d.images) > 0 { - return fmt.Errorf("Target LXD already has images, aborting.") - } - - // Networks - if d.networks != nil { - if len(d.networks) > 0 { - return fmt.Errorf("Target LXD already has networks, aborting.") - } - } - - // Storage pools - if d.storagePools != nil { - if len(d.storagePools) > 0 { - return fmt.Errorf("Target LXD already has storage pools, aborting.") - } - } - - return nil -} - -func (d *lxdDaemon) showReport() error { - // Print a basic report to the console - fmt.Printf("LXD version: %s\n", d.info.Environment.ServerVersion) - fmt.Printf("LXD PID: %d\n", d.info.Environment.ServerPid) - fmt.Printf("Resources:\n") - fmt.Printf(" Containers: %d\n", len(d.containers)) - fmt.Printf(" Images: %d\n", len(d.images)) - if d.networks != nil { - fmt.Printf(" Networks: %d\n", len(d.networks)) - } - if d.storagePools != nil { - fmt.Printf(" Storage pools: %d\n", len(d.storagePools)) - } - - return nil -} - -func (d *lxdDaemon) shutdown() error { - // Send the shutdown request - _, _, err := d.s.RawQuery("PUT", "/internal/shutdown", nil, "") - if err != nil { - return err - } - - // Wait for the daemon to exit - chMonitor := make(chan bool, 1) - go func() { - monitor, err := d.s.GetEvents() - if err != nil { - close(chMonitor) - return - } - - monitor.Wait() - close(chMonitor) - }() - - // Wait for the daemon to exit or timeout to be reached - select { - case <-chMonitor: - break - case <-time.After(time.Second * time.Duration(300)): - return fmt.Errorf("LXD still running after 5 minutes") - } - - return nil -} - -func (d *lxdDaemon) wait(clustered bool) error { - finger := make(chan error, 1) - go func() { - for { - c, err := lxd.ConnectLXDUnix(filepath.Join(d.path, "unix.socket"), nil) - if err != nil { - time.Sleep(500 * time.Millisecond) - continue - } - - _, _, err = c.RawQuery("GET", "/internal/ready", nil, "") - if err != nil { - time.Sleep(500 * time.Millisecond) - continue - } - - finger <- nil - return - } - }() - - timeout := time.Second * time.Duration(300) - if clustered { - timeout = time.Hour - } - - select { - case <-finger: - break - case <-time.After(time.Second * timeout): - return fmt.Errorf("LXD still not running after 5 minutes.") - } - - return nil -} - -func (d *lxdDaemon) reload() error { - // Reload or restart the relevant systemd units - if strings.HasPrefix(d.path, "/var/snap") { - return systemdCtl("reload", "snap.lxd.daemon.service") - } - - return systemdCtl("restart", "lxd.service", "lxd.socket") -} - -func (d *lxdDaemon) start() error { - // Start the relevant systemd units - if strings.HasPrefix(d.path, "/var/snap") { - return systemdCtl("start", "snap.lxd.daemon.service") - } - - return systemdCtl("start", "lxd.service", "lxd.socket") -} - -func (d *lxdDaemon) stop() error { - // Stop the relevant systemd units - if strings.HasPrefix(d.path, "/var/snap") { - if systemdCtl("is-active", "snap.lxd.daemon.unix.socket") == nil { - return systemdCtl("stop", "snap.lxd.daemon.unix.socket", "snap.lxd.daemon.service") - } - - return systemdCtl("stop", "snap.lxd.daemon.service") - } - - return systemdCtl("stop", "lxd.service", "lxd.socket") -} - -func (d *lxdDaemon) uninstall() error { - // Remove the LXD package - if strings.HasPrefix(d.path, "/var/snap") { - _, err := shared.RunCommand("snap", "remove", "lxd") - return err - } - - // Actively kill the old systemd units in case they get stuck during removal - chDone := make(chan struct{}, 1) - defer close(chDone) - - go func() { - for { - select { - case <-chDone: - return - case <-time.After(10 * time.Second): - shared.RunCommand("systemctl", "kill", "-s", "SIGKILL", "lxd-containers.service") - shared.RunCommand("systemctl", "kill", "-s", "SIGKILL", "lxd.service") - } - } - }() - - // Remove LXD itself - _, err := shared.RunCommand("apt-get", "remove", "--purge", "--yes", "lxd", "lxd-client") - if err != nil { - return err - } - - return nil -} - -func (d *lxdDaemon) wipe() error { - // Check if the path is already gone - if !shared.PathExists(d.path) { - return nil - } - - return os.RemoveAll(d.path) -} - -func (d *lxdDaemon) moveFiles(dst string) error { - // Create the logs directory if missing (needed by LXD) - if !shared.PathExists(filepath.Join(d.path, "logs")) { - err := os.MkdirAll(filepath.Join(d.path, "logs"), 0755) - if err != nil { - return err - } - } - - // Move the daemon path to a new target - _, err := shared.RunCommand("mv", d.path, dst) - if err != nil { - return err - } - - return nil -} - -func (d *lxdDaemon) cleanMounts() error { - mounts := []string{} - - // Get all the mounts under the daemon path - f, err := os.Open("/proc/self/mountinfo") - if err != nil { - return err - } - defer f.Close() - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - s := strings.Split(scanner.Text(), " ") - if strings.HasPrefix(s[4], d.path) { - mounts = append(mounts, s[4]) - } - } - - // Reverse the list - sort.Sort(sort.Reverse(sort.StringSlice(mounts))) - - // Attempt to lazily unmount them all - for _, mount := range mounts { - if mount == d.path { - continue - } - - err = syscall.Unmount(mount, syscall.MNT_DETACH) - if err != nil { - return fmt.Errorf("Unable to unmount: %s: %v", mount, err) - } - } - - return nil -} - -func (d *lxdDaemon) remount(dst string) error { - // Create the logs directory if missing (needed by LXD) - if !shared.PathExists(filepath.Join(d.path, "logs")) { - err := os.MkdirAll(filepath.Join(d.path, "logs"), 0755) - if err != nil { - return err - } - } - - // Attempt a simple rename (for btrfs subvolumes) - err := os.Rename(d.path, dst) - if err == nil { - return nil - } - - // Create the target - err = os.MkdirAll(dst, 0755) - if err != nil { - return err - } - - // Bind-mount to the new target - err = syscall.Mount(d.path, dst, "none", syscall.MS_BIND|syscall.MS_REC, "") - if err != nil { - return err - } - - // Attempt to unmount the source path - err = syscall.Unmount(d.path, syscall.MNT_DETACH) - if err != nil { - // If unmounting fails, then the source may have been a subvolume, in this case, just hide it - err = syscall.Mount("tmpfs", d.path, "tmpfs", 0, "size=100k,mode=700") - if err != nil { - return err - } - } - - return nil -} - -func (d *lxdDaemon) rewriteStorage(dst *lxdDaemon) error { - // Symlink rewrite function - rewriteSymlink := func(path string) error { - target, err := os.Readlink(path) - if err != nil { - // Not a symlink, skipping - return nil - } - - newTarget := convertPath(target, d.path, dst.path) - if target != newTarget { - err = os.Remove(path) - if err != nil { - return err - } - - err = os.Symlink(newTarget, path) - if err != nil { - return err - } - } - - return nil - } - - // ZFS rewrite function - zfsRewrite := func(zpool string) error { - output, err := runSnapCommand("zfs", "list", "-H", "-t", "all", "-o", "name,mountpoint", "-r", zpool) - if err != nil { - // Print a clear error message but don't fail as that'd leave a broken LXD - fmt.Println("") - fmt.Printf("ERROR: Unable to access the '%s' ZPOOL at this time: %v\n", zpool, err) - fmt.Printf(" Container mountpoints will need to be manually corrected.\n\n") - return nil - } - - for _, line := range strings.Split(output, "\n") { - fields := strings.Fields(line) - if len(fields) < 2 { - continue - } - - name := fields[0] - mountpoint := fields[1] - - if mountpoint == "none" || mountpoint == "-" { - continue - } - - mountpoint = convertPath(mountpoint, d.path, dst.path) - _, err := runSnapCommand("zfs", "set", fmt.Sprintf("mountpoint=%s", mountpoint), name) - if err != nil { - return err - } - } - - return nil - } - - // Rewrite the container links - containers, err := ioutil.ReadDir(filepath.Join(dst.path, "containers")) - if err != nil { - return err - } - - for _, ctn := range containers { - err := rewriteSymlink(filepath.Join(dst.path, "containers", ctn.Name())) - if err != nil { - return err - } - } - - // Handle older LXD daemons - if d.storagePools == nil { - zpool, ok := d.info.Config["storage.zfs_pool_name"] - if ok { - err := zfsRewrite(zpool.(string)) - if err != nil { - return err - } - } - - return nil - } - - for _, pool := range d.storagePools { - source := pool.Config["source"] - newSource := convertPath(source, d.path, dst.path) - if source != newSource { - err := dbRewritePoolSource(d, dst, pool.Name, newSource) - if err != nil { - return err - } - - pool.Config["source"] = newSource - } - - if pool.Driver == "zfs" { - // For ZFS we must rewrite all the mountpoints - zpool := pool.Config["zfs.pool_name"] - if zpool == "" { - zpool = pool.Config["source"] - } - - err = zfsRewrite(zpool) - if err != nil { - return err - } - - continue - } - - if pool.Driver == "dir" { - // For dir we must rewrite any symlink - err := rewriteSymlink(filepath.Join(dst.path, "storage-pools", pool.Name)) - if err != nil { - return err - } - - continue - } - } - - return nil -} - -func (d *lxdDaemon) backupDatabase() error { - for _, path := range []string{filepath.Join(d.path, "lxd.db"), filepath.Join(d.path, "raft"), filepath.Join(d.path, "database")} { - if !shared.PathExists(path) { - continue - } - - backupPath := fmt.Sprintf("%s.pre-migration", path) - if shared.PathExists(backupPath) { - err := os.RemoveAll(backupPath) - if err != nil { - return err - } - } - - if shared.IsDir(path) { - err := shared.DirCopy(path, backupPath) - if err != nil { - return err - } - } else { - err := shared.FileCopy(path, backupPath) - if err != nil { - return err - } - } - } - - return nil -} diff --git a/lxd-migrate/main.go b/lxd-migrate/main.go deleted file mode 100644 index 0e5ac5669..000000000 --- a/lxd-migrate/main.go +++ /dev/null @@ -1,275 +0,0 @@ -package main - -import ( - "bufio" - "flag" - "fmt" - "os" - "strings" - - "github.com/canonical/lxd/lxd/storage/filesystem" - "github.com/canonical/lxd/shared" - "github.com/canonical/lxd/shared/version" -) - -var argYes = flag.Bool("yes", false, "Answer yes to all questions") - -func main() { - flag.Parse() - - err := run() - if err != nil { - fmt.Fprintf(os.Stderr, "error: %v\n", err) - os.Exit(1) - } - - os.Exit(0) -} - -func run() error { - // Only run as root - if os.Geteuid() != 0 { - return fmt.Errorf("This tool must be run as root.") - } - - // Confirm we're on Ubuntu - if osID() != "ubuntu" { - return fmt.Errorf("Data migration is only supported on Ubuntu at this time.") - } - - // Unset the snap variables to avoid triggering wrong logic - os.Unsetenv("SNAP_NAME") - os.Unsetenv("SNAP") - - // Validate that nothing depends on the current LXD - err := packagesRemovable([]string{"lxd", "lxd-client"}) - if err != nil { - if os.Getenv("LXD_PREINST") == "" { - return err - } - - fmt.Printf("\nWARNING: %v\n", err) - } - - // Attempt to create /var/log/lxd if missing - if !shared.PathExists("/var/log/lxd") { - os.MkdirAll("/var/log/lxd", 0755) - } - - // Connect to the source LXD - fmt.Printf("=> Connecting to source server\n") - src, err := lxdConnect("/var/lib/lxd") - if err != nil { - return fmt.Errorf("Unable to connect to the source LXD: %v", err) - } - - // Connect to the destination LXD - fmt.Printf("=> Connecting to destination server\n") - dst, err := lxdConnect("/var/snap/lxd/common/lxd") - if err != nil { - return fmt.Errorf("Unable to connect to the destination LXD: %v", err) - } - - // Sanity checks - fmt.Printf("=> Running sanity checks\n") - if compareVersions(src.info.Environment.ServerVersion, dst.info.Environment.ServerVersion) > 0 { - return fmt.Errorf("The source server is running a more recent version than the destination.") - } - - err = src.checkEmpty() - if err == nil { - fmt.Printf("The source server is empty, no migration needed.\n") - - return removePackages(src, dst) - } - - err = dst.checkEmpty() - if err != nil { - return err - } - - // Show migration report - fmt.Printf("\n=== Source server\n") - err = src.showReport() - if err != nil { - return err - } - - fmt.Printf("\n=== Destination server\n") - err = dst.showReport() - if err != nil { - return err - } - - // Compare source and target version - minimumVersion, _ := version.NewDottedVersion("4.0.0") - v, err := version.NewDottedVersion(src.info.Environment.ServerVersion) - if err == nil && v.Compare(minimumVersion) == -1 { - return fmt.Errorf("LXD %s can't be directly upgraded to %s, please upgrade to LXD 4.0.x first.", src.info.Environment.ServerVersion, dst.info.Environment.ServerVersion) - } - - // Confirm that the user wants to go ahead - fmt.Printf("\nThe migration process will shut down all your containers then move your data to the destination LXD.\n") - fmt.Printf("Once the data is moved, the destination LXD will start and apply any needed updates.\n") - fmt.Printf("And finally your containers will be brought back to their previous state, completing the migration.\n") - - isMnt := filesystem.IsMountPoint(src.path) - if isMnt { - fmt.Printf("\nWARNING: /var/lib/lxd is a mountpoint. You will need to update that mount location after the migration.\n") - } - - fmt.Printf("\n") - if !*argYes && !askBool("Are you ready to proceed (yes/no) [default=no]? ", "no") { - return fmt.Errorf("Aborted by the user") - } - - // Shutting down the daemons - fmt.Printf("=> Shutting down the source LXD\n") - err = src.shutdown() - if err != nil { - return fmt.Errorf("Failed to shutdown the source LXD: %v", err) - } - - fmt.Printf("=> Stopping the source LXD units\n") - err = src.stop() - if err != nil { - return fmt.Errorf("Failed to stop the source LXD units: %v", err) - } - - fmt.Printf("=> Stopping the destination LXD unit\n") - err = dst.stop() - if err != nil { - return fmt.Errorf("Failed to stop the destination LXD units: %v", err) - } - - // Unmount any leftover mounts - fmt.Printf("=> Unmounting source LXD paths\n") - err = src.cleanMounts() - if err != nil { - return fmt.Errorf("Failed to unmount source LXD: %v", err) - } - - fmt.Printf("=> Unmounting destination LXD paths\n") - err = dst.cleanMounts() - if err != nil { - return fmt.Errorf("Failed to unmount destination LXD: %v", err) - } - - // Wipe the destination LXD - fmt.Printf("=> Wiping destination LXD clean\n") - err = dst.wipe() - if err != nil { - return fmt.Errorf("Failed to wipe the destination LXD: %v", err) - } - - // Backup the database - fmt.Printf("=> Backing up the database\n") - err = src.backupDatabase() - if err != nil { - return fmt.Errorf("Failed to backup the database: %v", err) - } - - // Move the data across - if !isMnt { - fmt.Printf("=> Moving the data\n") - err = src.moveFiles(dst.path) - if err != nil { - return fmt.Errorf("Failed to move the data: %v", err) - } - } else { - fmt.Printf("=> Moving the /var/lib/lxd mountpoint\n") - err = src.remount(dst.path) - if err != nil { - return fmt.Errorf("Failed to move the mountpoint: %v", err) - } - } - - // Deal with the storage backends - fmt.Printf("=> Updating the storage backends\n") - err = src.rewriteStorage(dst) - if err != nil { - return fmt.Errorf("Failed to update the storage pools: %v", err) - } - - // Start the destination LXD - fmt.Printf("=> Starting the destination LXD\n") - err = dst.start() - if err != nil { - return fmt.Errorf("Failed to start the destination LXD: %v", err) - } - - // Wait for LXD to be online - fmt.Printf("=> Waiting for LXD to come online\n") - - if src.info.Environment.ServerClustered { - fmt.Printf("\nWARNING: LXD cluster members must all run the exact same LXD version\n") - fmt.Printf("\n You may now need to perform the same operation on the other members\n") - fmt.Printf("\n The upgrade will hold here for up to an hour while you do so\n") - } - - err = dst.wait(src.info.Environment.ServerClustered) - if err != nil { - return err - } - - // Show the updated destination server - fmt.Printf("\n=== Destination server\n") - err = dst.update() - if err != nil { - return fmt.Errorf("Failed to update status of the destination LXD: %v", err) - } - - err = dst.showReport() - if err != nil { - return err - } - - // Mount warning - if isMnt { - fmt.Printf("\nWARNING: Make sure to update your system to mount your LXD directory at /var/snap/lxd/common/lxd\n") - } - - return removePackages(src, dst) -} - -func removePackages(src *lxdDaemon, dst *lxdDaemon) error { - // Check if called from the LXD preinst - if os.Getenv("LXD_PREINST") != "" { - return nil - } - - // Offer to remove LXD on the source - fmt.Printf("\nThe migration is now complete and your containers should be back online.\n") - if *argYes || askBool("Do you want to uninstall the old LXD (yes/no) [default=yes]? ", "yes") { - err := src.uninstall() - if err != nil { - return err - } - } - - // Final message - fmt.Printf("\nAll done. You may need to close your current shell and open a new one to have the \"lxc\" command work.\n") - fmt.Printf("To migrate your existing client configuration, move ~/.config/lxc to ~/snap/lxd/common/config\n") - - return nil -} - -func askBool(question string, default_ string) bool { - reader := bufio.NewReader(os.Stdin) - - for { - fmt.Printf(question) - input, _ := reader.ReadString('\n') - input = strings.TrimSuffix(input, "\n") - if input == "" { - input = default_ - } - if shared.ValueInSlice(strings.ToLower(input), []string{"yes", "y"}) { - return true - } else if shared.ValueInSlice(strings.ToLower(input), []string{"no", "n"}) { - return false - } - - fmt.Printf("Invalid input, try again.\n\n") - } -} diff --git a/lxd-migrate/mntns.go b/lxd-migrate/mntns.go deleted file mode 100644 index 13b3421a4..000000000 --- a/lxd-migrate/mntns.go +++ /dev/null @@ -1,74 +0,0 @@ -package main - -/* -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include - -void error(char *msg) -{ - int old_errno = errno; - - if (old_errno == 0) { - fprintf(stderr, "%s\n", msg); - fprintf(stderr, "errno: 0\n"); - return; - } - - perror(msg); - fprintf(stderr, "errno: %d\n", old_errno); -} - -int dosetns(int pid, char *nstype) { - int mntns; - char buf[PATH_MAX]; - - sprintf(buf, "/proc/%d/ns/%s", pid, nstype); - mntns = open(buf, O_RDONLY); - if (mntns < 0) { - error("error: open mntns"); - return -1; - } - - if (setns(mntns, 0) < 0) { - error("error: setns"); - close(mntns); - return -1; - } - close(mntns); - - return 0; -} - -int attach_mntns() { - if (dosetns(1, "mnt") < 0) { - error("error: setns"); - return -1; - } - - if (chdir("/") < 0) { - error("error: chdir"); - return -1; - } - - return 0; -} - -__attribute__((constructor)) void init(void) { - int ret = 0; - - if (geteuid() == 0) { - ret = attach_mntns(); - } - - if (ret < 0) { - _exit(ret); - } -} -*/ -import "C" diff --git a/lxd-migrate/utils.go b/lxd-migrate/utils.go deleted file mode 100644 index e2779ceae..000000000 --- a/lxd-migrate/utils.go +++ /dev/null @@ -1,168 +0,0 @@ -package main - -import ( - "bufio" - "fmt" - "os" - "path/filepath" - "strconv" - "strings" - - "github.com/canonical/lxd/shared" -) - -func runSnapCommand(name string, arg ...string) (string, error) { - args := []string{"--mount=/run/snapd/ns/lxd.mnt", name} - args = append(args, arg...) - - return shared.RunCommand("nsenter", args...) -} - -func compareVersions(a string, b string) int { - aFields := strings.Split(a, ".") - bFields := strings.Split(b, ".") - - fields := len(aFields) - if len(bFields) > fields { - fields = len(bFields) - } - - // Iterate over parts of both versions - for i := 0; i < fields; i++ { - var err error - - // Parse the left part - aInt := int64(0) - if len(aFields) > i { - aInt, err = strconv.ParseInt(aFields[i], 10, 64) - if err != nil { - aInt = 0 - } - } - - // Parse the right part - bInt := int64(0) - if len(bFields) > i { - bInt, err = strconv.ParseInt(bFields[i], 10, 64) - if err != nil { - bInt = 0 - } - } - - // Compare versions - if aInt == bInt { - continue - } else if aInt < bInt { - return -1 - } else if aInt > bInt { - return 1 - } - } - - return 0 -} - -func systemdCtl(action string, units ...string) error { - args := []string{} - args = append(args, action) - args = append(args, units...) - - // Run systemctl - _, err := shared.RunCommand("systemctl", args...) - return err -} - -func convertPath(path string, src string, dst string) string { - // Relative paths are handled by LXD - if !strings.HasPrefix(path, "/") { - return path - } - - // /dev is always available - if strings.HasPrefix(path, "/dev/") { - return path - } - - // Somehow the path is already correct - if strings.HasPrefix(path, dst) { - return path - } - - // Prefixed with old path - if strings.HasPrefix(path, src) { - return fmt.Sprintf("%s%s", dst, strings.TrimPrefix(path, src)) - } - - // Requires host access - return fmt.Sprintf("/var/lib/snapd/hostfs%s", path) -} - -func osID() string { - f, err := os.Open("/etc/os-release") - if err != nil { - return "unknown" - } - defer f.Close() - - scanner := bufio.NewScanner(f) - for scanner.Scan() { - s := strings.Split(scanner.Text(), "=") - if len(s) >= 2 && s[0] == "ID" { - return s[1] - } - } - - return "unknown" -} - -func osInit() string { - initExe, err := os.Readlink("/proc/1/exe") - if err != nil { - return "unknown" - } - - fields := strings.Split(initExe, " ") - init := filepath.Base(fields[0]) - - return init -} - -func packagesRemovable(names []string) error { - rdepends := []string{} - - // Get all reverse depends - output, err := shared.RunCommand("apt-cache", append([]string{"-i", "rdepends"}, names...)...) - if err != nil { - return err - } - - for _, line := range strings.Split(output, "\n") { - if !strings.HasPrefix(line, " ") { - continue - } - - pkg := strings.TrimSpace(line) - if !shared.ValueInSlice(pkg, rdepends) && !shared.ValueInSlice(pkg, names) { - rdepends = append(rdepends, pkg) - } - } - - // Check for what's installed - problems := []string{} - for _, pkg := range rdepends { - output, err := shared.RunCommand("dpkg-query", "-W", "-f=${Status}", pkg) - if err == nil && strings.HasSuffix(output, " installed") { - if shared.ValueInSlice(pkg, []string{"adapt", "autopkgtest", "lxc2", "nova-compute-lxd", "snapcraft", "ubuntu-server"}) { - continue - } - - problems = append(problems, pkg) - } - } - - if len(problems) > 0 { - return fmt.Errorf("The following packages depend on %v: %s", names, strings.Join(problems, ", ")) - } - - return nil -} diff --git a/lxd-qemu-snap/README.md b/lxd-qemu-snap/README.md new file mode 100644 index 000000000..50c9a8617 --- /dev/null +++ b/lxd-qemu-snap/README.md @@ -0,0 +1,69 @@ +# External QEMU snap for LXD snap + +## How to build and use + +``` +cd lxd-qemu-snap + +# clean up previous builds +rm -f qemu-for-lxd_*.snap + +# build +snapcraft + +# install +sudo snap install qemu-for-lxd_*.snap --devmode + +# connect snaps +sudo snap connect lxd:gpu-2404 mesa-2404:gpu-2404 +sudo snap connect lxd:qemu-external qemu-for-lxd:qemu-external +``` + +## How to use with virgl (only specific to this example of snapcraft.yaml) + +``` +lxc init images:ubuntu/noble/desktop desktop -c limits.memory=8GiB --vm + +# modify instance configuration: +lxc config edit desktop + +# choose an appropriate renderer: +ls -la /dev/dri/by-path/*-render + +# for example, on my system it is /dev/dri/by-path/pci-0000:67:00.0-render +# lspci | grep -E "(3D|VGA)" shows: +# 67:00.0 VGA compatible controller: Advanced Micro Devices, Inc. [AMD/ATI] Rembrandt (rev d8) + +# add the following lines: + raw.apparmor: |- + /snap/lxd/*/gpu-2404/** mr, + /dev/dri/ r, + /dev/dri/card[0-9]* rw, + /dev/dri/renderD[0-9]* rw, + /run/udev/data/c226:[0-9]* r, # 226 drm + /sys/devices/** r, + /sys/bus/** r, + raw.qemu: -display egl-headless,rendernode=/dev/dri/by-path/pci-0000:67:00.0-render + raw.qemu.conf: |- + [device "qemu_gpu"] + driver = "virtio-vga-gl" + +# try it +lxc start desktop --console=vga + +# you can check output from: +dmesg | grep -i drm +# if you see: +# [drm] features: +virgl ... +# it's a good sign + +glxinfo | grep -i vir +# it should show something like: +# Device: virgl ... +``` + +## References: + +https://github.com/snapcore/snapd/blob/5c8d8431baa425464b279ff26b8c44eecb9aab22/interfaces/builtin/opengl.go#L41 + +https://gitlab.gnome.org/GNOME/gnome-boxes/-/issues/586 \ No newline at end of file diff --git a/lxd-qemu-snap/snapcraft.yaml b/lxd-qemu-snap/snapcraft.yaml new file mode 100644 index 000000000..805a02093 --- /dev/null +++ b/lxd-qemu-snap/snapcraft.yaml @@ -0,0 +1,237 @@ +name: qemu-for-lxd +base: core24 +assumes: + - snapd2.63 +version: '1' +grade: devel +summary: External Qemu for LXD +description: |- + External Qemu for LXD + +contact: lxd@lists.canonical.com +issues: https://github.com/canonical/lxd/issues +source-code: https://github.com/canonical/lxd +website: https://ubuntu.com/lxd +confinement: strict + +slots: + qemu-external: + interface: content + content: qemu-external-binaries + read: + - $SNAP/external/qemu + +parts: + # + # This step is extremely important, as it ensures that no mesa libs will + # be provided with this snap to prevent any possible version mistmatches + # between this snap and mesa-2404 snap. + # If you the error like: + # DRI driver not from this Mesa build ('24.0.5-1ubuntu1' vs '24.0.9-0ubuntu0.1') + # this is a clear sign that you likely ship some mesa library along with your qemu-for-lxd + # snap and it has a version conflict with what you have in gpu-2404 interface snap. + # + gpu-2404: + after: + - virgl + - qemu + source: https://github.com/canonical/gpu-snap.git + plugin: dump + override-prime: | + set -ex + + CUSTOM_PREFIX="external/qemu" + CRAFT_PRIME_OVERRIDE="${CRAFT_PRIME}/${CUSTOM_PREFIX}" + + # cleanup script expects to see libraries in usr/lib, while we have them in lib + mkdir "${CRAFT_PRIME_OVERRIDE}/usr" + ln -s "${CRAFT_PRIME_OVERRIDE}/lib" "${CRAFT_PRIME_OVERRIDE}/usr/lib" + + # a bit hacky way to call a cleanup script forcing it to look in a right directory + CRAFT_PRIME="${CRAFT_PRIME_OVERRIDE}" ${CRAFT_PART_SRC}/bin/gpu-2404-cleanup mesa-2404 nvidia-2404 + + rm -rf "${CRAFT_PRIME_OVERRIDE}/usr" + + set +ex + + virgl: + source: https://gitlab.freedesktop.org/virgl/virglrenderer.git + source-tag: virglrenderer-1.1.0 + source-depth: 1 + plugin: meson + meson-parameters: + - --prefix=/external/qemu + build-packages: + - meson + - libgbm-dev + - libdrm-dev + + qemu: + after: + - virgl + source: https://gitlab.com/qemu-project/qemu + source-commit: ea35a5082a5fe81ce8fd184b0e163cd7b08b7ff7 # v9.2.2 + source-depth: 1 + source-submodules: [] + source-type: git + plugin: autotools + autotools-configure-parameters: + - --prefix=/external/qemu + - --enable-opengl + - --enable-virglrenderer + - --disable-smartcard +# options from LXD snap: + - --disable-bochs + - --disable-cloop + - --disable-dmg + - --disable-docs + - --disable-guest-agent + - --disable-parallels + - --disable-qed + - --disable-slirp + - --disable-user + - --disable-vdi + - --disable-vnc + - --disable-xen + - --enable-attr + - --enable-cap-ng + - --enable-kvm + - --enable-libusb + - --enable-usb-redir + - --enable-linux-aio +# - --enable-linux-io-uring + - --enable-numa + - --enable-pie + - --enable-rbd + - --enable-seccomp + - --enable-spice + - --enable-system + - --enable-tcg + - --enable-tools + - --enable-vhost-crypto + - --enable-vhost-kernel + - --enable-vhost-net + - --enable-vhost-user + - --enable-virtfs + - --firmwarepath=/snap/lxd/current/share/qemu/ + - --localstatedir=/var/ + build-environment: + - ACLOCAL_PATH: /usr/share/aclocal + - PKG_CONFIG_PATH: $CRAFT_STAGE/external/qemu/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/pkgconfig:$CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/pkgconfig:/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR/pkgconfig:/usr/lib/pkgconfig:/usr/share/pkgconfig${PKG_CONFIG_PATH:+:$PKG_CONFIG_PATH} + - PATH: /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games:/snap/bin:/snap/snapcraft/current/bin/scriptlet-bin:$PATH + - LD_LIBRARY_PATH: $CRAFT_STAGE/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR:/usr/lib/$CRAFT_ARCH_TRIPLET_BUILD_FOR${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH} + 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 + # Mangle the configure a bit + QEMUARCH="$(uname -m)" + [ "${QEMUARCH}" = "ppc64le" ] && QEMUARCH="ppc64" + + sed -i "s/^unset target_list$/target_list=\"${QEMUARCH}-softmmu\"/" configure + + set +ex + craftctl default + build-packages: + - bison + - flex + - gettext + - libaio-dev + - libbluetooth-dev + - libbrlapi-dev + - libbz2-dev + - libcap-dev + - libcap-ng-dev + - libcacard-dev + - libcurl4-gnutls-dev + - libepoxy-dev + - libfdt-dev + - libgtk-3-dev + - libglib2.0-dev + - libglusterfs-dev + - libibverbs-dev + - libiscsi-dev + - libjemalloc-dev + - libjpeg8-dev + - liblzo2-dev + - libncurses5-dev + - libnfs-dev + - libnuma-dev + - libpango1.0-dev + - libpixman-1-dev + - libpulse-dev + - librbd-dev + - librdmacm-dev + - libsasl2-dev + - libseccomp-dev + - libsdl2-dev + - libsdl2-image-dev + - libsnappy-dev + - libspice-protocol-dev + - libspice-server-dev + - libusb-1.0-0-dev + - libusbredirhost-dev + - libusbredirparser-dev + - libvde-dev + - libvdeplug-dev + - libvte-2.91-dev + - libxml2-dev + - libx11-dev + - libzstd-dev + - ninja-build + - zlib1g-dev + stage-packages: + - libepoxy0 + - libvte-2.91-0 + - libsndio7.0 + - libaio1t64 + - libasn1-8-heimdal + - libboost-iostreams1.74.0 + - libboost-thread1.74.0 + - libbrlapi0.8 + - libcurl3-gnutls + - libfdt1 + - libgfapi0 + - libgfrpc0 + - libgfxdr0 + - libgssapi3-heimdal + - libhcrypto5t64-heimdal + - libheimbase1-heimdal + - libheimntlm0-heimdal + - libhx509-5-heimdal + - libibverbs1 + - libiscsi7 + - libjemalloc2 + - libkrb5-26-heimdal + - libnfs14 + - libnghttp2-14 + - libnuma1 + - librados2 + - librbd1 + - librdmacm1 + - libroken19-heimdal + - librtmp1 + - libsasl2-2 + - libsdl2-2.0-0 + - libsdl2-image-2.0-0 + - libsnappy1v5 + - libspice-server1 + - libtirpc3 + - liburcu8 + - libusb-1.0-0 + - libusbredirhost1 + - libusbredirparser1 + - libvdeplug2 + - libwind0-heimdal + - seabios + organize: + lib/: external/qemu/lib/ + usr/bin/: external/qemu/bin/ + usr/lib/: external/qemu/lib/ + usr/local/bin/: external/qemu/bin/ + usr/local/lib/: external/qemu/lib/ + usr/local/libexec/: external/qemu/bin/ + usr/local/share/: external/qemu/share/ diff --git a/patches/edk2-0002-logo.bmp b/patches/edk2-0002-logo.bmp index a244621db..79e1dd8e1 100644 Binary files a/patches/edk2-0002-logo.bmp and b/patches/edk2-0002-logo.bmp differ diff --git a/patches/edk2-0007-Disable-the-Shell-when-SecureBoot-is-enabled.patch b/patches/edk2-0007-Disable-the-Shell-when-SecureBoot-is-enabled.patch new file mode 100644 index 000000000..45aeb8dbd --- /dev/null +++ b/patches/edk2-0007-Disable-the-Shell-when-SecureBoot-is-enabled.patch @@ -0,0 +1,94 @@ +From: Mate Kukri +Date: Wed, 6 Dec 2023 15:47:42 +0000 +Subject: Shell: Disable the Shell when SecureBoot is enabled and not in + SetupMode + +Signed-off-by: Mate Kukri +--- + ShellPkg/Application/Shell/Shell.c | 14 ++++++++++++++ + ShellPkg/Application/Shell/Shell.h | 3 +++ + ShellPkg/Application/Shell/Shell.inf | 2 ++ + ShellPkg/ShellPkg.dsc | 1 + + 4 files changed, 20 insertions(+) + +diff --git a/ShellPkg/Application/Shell/Shell.c b/ShellPkg/Application/Shell/Shell.c +index f95c799..502013d 100644 +--- a/ShellPkg/Application/Shell/Shell.c ++++ b/ShellPkg/Application/Shell/Shell.c +@@ -357,6 +357,20 @@ UefiMain ( + EFI_HANDLE ConInHandle; + EFI_SIMPLE_TEXT_INPUT_PROTOCOL *OldConIn; + SPLIT_LIST *Split; ++ UINT8 SetupMode; ++ ++ // ++ // Check for Secure Boot mode ++ // ++ if (IsSecureBootEnabled()) { ++ Status = GetSetupMode (&SetupMode); ++ if (EFI_ERROR (Status)) { ++ return (Status); ++ } ++ if (SetupMode != 1) { ++ return (EFI_SECURITY_VIOLATION); ++ } ++ } + + if (PcdGet8 (PcdShellSupportLevel) > 3) { + return (EFI_UNSUPPORTED); +diff --git a/ShellPkg/Application/Shell/Shell.h b/ShellPkg/Application/Shell/Shell.h +index 89b4ac6..595ec79 100644 +--- a/ShellPkg/Application/Shell/Shell.h ++++ b/ShellPkg/Application/Shell/Shell.h +@@ -11,9 +11,11 @@ + #define _SHELL_INTERNAL_HEADER_ + + #include ++#include + + #include + #include ++#include + + #include + #include +@@ -42,6 +44,7 @@ + #include + #include + #include ++#include + + #include "ShellParametersProtocol.h" + #include "ShellProtocol.h" +diff --git a/ShellPkg/Application/Shell/Shell.inf b/ShellPkg/Application/Shell/Shell.inf +index f1e41de..340585f 100644 +--- a/ShellPkg/Application/Shell/Shell.inf ++++ b/ShellPkg/Application/Shell/Shell.inf +@@ -47,6 +47,7 @@ + MdePkg/MdePkg.dec + ShellPkg/ShellPkg.dec + MdeModulePkg/MdeModulePkg.dec ++ SecurityPkg/SecurityPkg.dec + + [LibraryClasses] + BaseLib +@@ -66,6 +67,7 @@ + SortLib + HandleParsingLib + UefiHiiServicesLib ++ SecureBootVariableLib + + [Guids] + gShellVariableGuid ## SOMETIMES_CONSUMES ## GUID +diff --git a/ShellPkg/ShellPkg.dsc b/ShellPkg/ShellPkg.dsc +index dd0d886..28d6a87 100644 +--- a/ShellPkg/ShellPkg.dsc ++++ b/ShellPkg/ShellPkg.dsc +@@ -64,6 +64,7 @@ + DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf + DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf + ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf ++ SecureBootVariableLib|SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.inf + + [LibraryClasses.ARM,LibraryClasses.AARCH64] + # diff --git a/patches/edk2-0008-Revert-ArmVirtPkg-make-EFI_LOADER_DATA-non-execurable.patch b/patches/edk2-0008-Revert-ArmVirtPkg-make-EFI_LOADER_DATA-non-execurable.patch new file mode 100644 index 000000000..996d33242 --- /dev/null +++ b/patches/edk2-0008-Revert-ArmVirtPkg-make-EFI_LOADER_DATA-non-execurable.patch @@ -0,0 +1,35 @@ +commit 9d5f77121a2f2469ba3a9f473ee2a00ecf97c059 (HEAD) +Author: Simon Deziel +Date: 2025-02-05 17:56:48 -0500 + + Revert "ArmVirtPkg: make EFI_LOADER_DATA non-executable" + + This reverts commit 2997ae38739756ecba9b0de19e86032ebc689ef9. + +diff --git a/ArmVirtPkg/ArmVirt.dsc.inc b/ArmVirtPkg/ArmVirt.dsc.inc +index fe6488ee99..c0f69a26c2 100644 +--- a/ArmVirtPkg/ArmVirt.dsc.inc ++++ b/ArmVirtPkg/ArmVirt.dsc.inc +@@ -368,21 +368,21 @@ + # Enable strict image permissions for all images. (This applies + # only to images that were built with >= 4 KB section alignment.) + # + gEfiMdeModulePkgTokenSpaceGuid.PcdImageProtectionPolicy|0x3 + + # + # Enable NX memory protection for all non-code regions, including OEM and OS + # reserved ones, with the exception of LoaderData regions, of which OS loaders + # (i.e., GRUB) may assume that its contents are executable. + # +- gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0xC000000000007FD5 ++ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeNxMemoryProtectionPolicy|0xC000000000007FD1 + + gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard|TRUE + + [Components.common] + # + # Ramdisk support + # + MdeModulePkg/Universal/Disk/RamDiskDxe/RamDiskDxe.inf + + ShellPkg/DynamicCommand/TftpDynamicCommand/TftpDynamicCommand.inf { diff --git a/patches/qemu-0001-kvm-Allow-kvm_arch_get-put_registers-to-accept-Error.patch b/patches/qemu-0001-kvm-Allow-kvm_arch_get-put_registers-to-accept-Error.patch new file mode 100644 index 000000000..158a3939d --- /dev/null +++ b/patches/qemu-0001-kvm-Allow-kvm_arch_get-put_registers-to-accept-Error.patch @@ -0,0 +1,259 @@ +From e04094aafb65ecb0cc2bd71b64df1950fc372bcf Mon Sep 17 00:00:00 2001 +From: Julia Suvorova +Date: Fri, 27 Sep 2024 12:47:40 +0200 +Subject: [PATCH 1/2] kvm: Allow kvm_arch_get/put_registers to accept Error** + +This is necessary to provide discernible error messages to the caller. + +Signed-off-by: Julia Suvorova +Reviewed-by: Peter Xu +Link: https://lore.kernel.org/r/20240927104743.218468-2-jusual@redhat.com +Signed-off-by: Paolo Bonzini +(cherry picked from commit a1676bb3047f28b292ecbce3a378ccc0b4721d47) +(cherry picked from commit fc5c0b38724b2d4435696c6e4f254c4392311f42) +Signed-off-by: Gabriel Mougard +--- + accel/kvm/kvm-all.c | 41 +++++++++++++++++++++++++++++--------- + include/sysemu/kvm.h | 4 ++-- + target/arm/kvm64.c | 4 ++-- + target/i386/kvm/kvm.c | 4 ++-- + target/mips/kvm.c | 4 ++-- + target/ppc/kvm.c | 4 ++-- + target/riscv/kvm/kvm-cpu.c | 4 ++-- + target/s390x/kvm/kvm.c | 4 ++-- + 8 files changed, 46 insertions(+), 23 deletions(-) + +diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c +index e39a810a4e..e6a3bb67f7 100644 +--- a/accel/kvm/kvm-all.c ++++ b/accel/kvm/kvm-all.c +@@ -2700,9 +2700,15 @@ bool kvm_cpu_check_are_resettable(void) + static void do_kvm_cpu_synchronize_state(CPUState *cpu, run_on_cpu_data arg) + { + if (!cpu->vcpu_dirty) { +- int ret = kvm_arch_get_registers(cpu); ++ Error *err = NULL; ++ int ret = kvm_arch_get_registers(cpu, &err); + if (ret) { +- error_report("Failed to get registers: %s", strerror(-ret)); ++ if (err) { ++ error_reportf_err(err, "Failed to synchronize CPU state: "); ++ } else { ++ error_report("Failed to get registers: %s", strerror(-ret)); ++ } ++ + cpu_dump_state(cpu, stderr, CPU_DUMP_CODE); + vm_stop(RUN_STATE_INTERNAL_ERROR); + } +@@ -2720,9 +2726,15 @@ void kvm_cpu_synchronize_state(CPUState *cpu) + + static void do_kvm_cpu_synchronize_post_reset(CPUState *cpu, run_on_cpu_data arg) + { +- int ret = kvm_arch_put_registers(cpu, KVM_PUT_RESET_STATE); ++ Error *err = NULL; ++ int ret = kvm_arch_put_registers(cpu, KVM_PUT_RESET_STATE, &err); + if (ret) { +- error_report("Failed to put registers after reset: %s", strerror(-ret)); ++ if (err) { ++ error_reportf_err(err, "Restoring resisters after reset: "); ++ } else { ++ error_report("Failed to put registers after reset: %s", ++ strerror(-ret)); ++ } + cpu_dump_state(cpu, stderr, CPU_DUMP_CODE); + vm_stop(RUN_STATE_INTERNAL_ERROR); + } +@@ -2737,9 +2749,15 @@ void kvm_cpu_synchronize_post_reset(CPUState *cpu) + + static void do_kvm_cpu_synchronize_post_init(CPUState *cpu, run_on_cpu_data arg) + { +- int ret = kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE); ++ Error *err = NULL; ++ int ret = kvm_arch_put_registers(cpu, KVM_PUT_FULL_STATE, &err); + if (ret) { +- error_report("Failed to put registers after init: %s", strerror(-ret)); ++ if (err) { ++ error_reportf_err(err, "Putting registers after init: "); ++ } else { ++ error_report("Failed to put registers after init: %s", ++ strerror(-ret)); ++ } + exit(1); + } + +@@ -2835,10 +2853,15 @@ int kvm_cpu_exec(CPUState *cpu) + MemTxAttrs attrs; + + if (cpu->vcpu_dirty) { +- ret = kvm_arch_put_registers(cpu, KVM_PUT_RUNTIME_STATE); ++ Error *err = NULL; ++ ret = kvm_arch_put_registers(cpu, KVM_PUT_RUNTIME_STATE, &err); + if (ret) { +- error_report("Failed to put registers after init: %s", +- strerror(-ret)); ++ if (err) { ++ error_reportf_err(err, "Putting registers after init: "); ++ } else { ++ error_report("Failed to put registers after init: %s", ++ strerror(-ret)); ++ } + ret = -1; + break; + } +diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h +index d614878164..eaba7fc319 100644 +--- a/include/sysemu/kvm.h ++++ b/include/sysemu/kvm.h +@@ -326,7 +326,7 @@ int kvm_arch_handle_exit(CPUState *cpu, struct kvm_run *run); + + int kvm_arch_process_async_events(CPUState *cpu); + +-int kvm_arch_get_registers(CPUState *cpu); ++int kvm_arch_get_registers(CPUState *cpu, Error **errp); + + /* state subset only touched by the VCPU itself during runtime */ + #define KVM_PUT_RUNTIME_STATE 1 +@@ -335,7 +335,7 @@ int kvm_arch_get_registers(CPUState *cpu); + /* full state set, modified during initialization or on vmload */ + #define KVM_PUT_FULL_STATE 3 + +-int kvm_arch_put_registers(CPUState *cpu, int level); ++int kvm_arch_put_registers(CPUState *cpu, int level, Error **errp); + + int kvm_arch_get_default_type(MachineState *ms); + +diff --git a/target/arm/kvm64.c b/target/arm/kvm64.c +index 3c175c93a7..6b7560a194 100644 +--- a/target/arm/kvm64.c ++++ b/target/arm/kvm64.c +@@ -782,7 +782,7 @@ static int kvm_arch_put_sve(CPUState *cs) + return 0; + } + +-int kvm_arch_put_registers(CPUState *cs, int level) ++int kvm_arch_put_registers(CPUState *cs, int level, Error **errp) + { + uint64_t val; + uint32_t fpr; +@@ -968,7 +968,7 @@ static int kvm_arch_get_sve(CPUState *cs) + return 0; + } + +-int kvm_arch_get_registers(CPUState *cs) ++int kvm_arch_get_registers(CPUState *cs, Error **errp) + { + uint64_t val; + unsigned int el; +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index a0bc9ea7b1..ab0c6499f5 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -4552,7 +4552,7 @@ static int kvm_get_nested_state(X86CPU *cpu) + return ret; + } + +-int kvm_arch_put_registers(CPUState *cpu, int level) ++int kvm_arch_put_registers(CPUState *cpu, int level, Error **errp) + { + X86CPU *x86_cpu = X86_CPU(cpu); + int ret; +@@ -4640,7 +4640,7 @@ int kvm_arch_put_registers(CPUState *cpu, int level) + return 0; + } + +-int kvm_arch_get_registers(CPUState *cs) ++int kvm_arch_get_registers(CPUState *cs, Error **errp) + { + X86CPU *cpu = X86_CPU(cs); + int ret; +diff --git a/target/mips/kvm.c b/target/mips/kvm.c +index e22e24ed97..6bf2a9b76e 100644 +--- a/target/mips/kvm.c ++++ b/target/mips/kvm.c +@@ -1179,7 +1179,7 @@ static int kvm_mips_get_cp0_registers(CPUState *cs) + return ret; + } + +-int kvm_arch_put_registers(CPUState *cs, int level) ++int kvm_arch_put_registers(CPUState *cs, int level, Error **errp) + { + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; +@@ -1215,7 +1215,7 @@ int kvm_arch_put_registers(CPUState *cs, int level) + return ret; + } + +-int kvm_arch_get_registers(CPUState *cs) ++int kvm_arch_get_registers(CPUState *cs, Error **errp) + { + MIPSCPU *cpu = MIPS_CPU(cs); + CPUMIPSState *env = &cpu->env; +diff --git a/target/ppc/kvm.c b/target/ppc/kvm.c +index 9b1abe2fc4..c84a252f0a 100644 +--- a/target/ppc/kvm.c ++++ b/target/ppc/kvm.c +@@ -897,7 +897,7 @@ int kvmppc_put_books_sregs(PowerPCCPU *cpu) + return kvm_vcpu_ioctl(CPU(cpu), KVM_SET_SREGS, &sregs); + } + +-int kvm_arch_put_registers(CPUState *cs, int level) ++int kvm_arch_put_registers(CPUState *cs, int level, Error **errp) + { + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; +@@ -1202,7 +1202,7 @@ static int kvmppc_get_books_sregs(PowerPCCPU *cpu) + return 0; + } + +-int kvm_arch_get_registers(CPUState *cs) ++int kvm_arch_get_registers(CPUState *cs, Error **errp) + { + PowerPCCPU *cpu = POWERPC_CPU(cs); + CPUPPCState *env = &cpu->env; +diff --git a/target/riscv/kvm/kvm-cpu.c b/target/riscv/kvm/kvm-cpu.c +index 117e33cf90..529381dd5f 100644 +--- a/target/riscv/kvm/kvm-cpu.c ++++ b/target/riscv/kvm/kvm-cpu.c +@@ -964,7 +964,7 @@ const KVMCapabilityInfo kvm_arch_required_capabilities[] = { + KVM_CAP_LAST_INFO + }; + +-int kvm_arch_get_registers(CPUState *cs) ++int kvm_arch_get_registers(CPUState *cs, Error **errp) + { + int ret = 0; + +@@ -1004,7 +1004,7 @@ int kvm_riscv_sync_mpstate_to_kvm(RISCVCPU *cpu, int state) + return 0; + } + +-int kvm_arch_put_registers(CPUState *cs, int level) ++int kvm_arch_put_registers(CPUState *cs, int level, Error **errp) + { + int ret = 0; + +diff --git a/target/s390x/kvm/kvm.c b/target/s390x/kvm/kvm.c +index 33ab3551f4..26a5b4e804 100644 +--- a/target/s390x/kvm/kvm.c ++++ b/target/s390x/kvm/kvm.c +@@ -472,7 +472,7 @@ static int can_sync_regs(CPUState *cs, int regs) + #define KVM_SYNC_REQUIRED_REGS (KVM_SYNC_GPRS | KVM_SYNC_ACRS | \ + KVM_SYNC_CRS | KVM_SYNC_PREFIX) + +-int kvm_arch_put_registers(CPUState *cs, int level) ++int kvm_arch_put_registers(CPUState *cs, int level, Error **errp) + { + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; +@@ -599,7 +599,7 @@ int kvm_arch_put_registers(CPUState *cs, int level) + return 0; + } + +-int kvm_arch_get_registers(CPUState *cs) ++int kvm_arch_get_registers(CPUState *cs, Error **errp) + { + S390CPU *cpu = S390_CPU(cs); + CPUS390XState *env = &cpu->env; +-- +2.43.0 + diff --git a/patches/qemu-0002-target-i386-kvm-Report-which-action-failed-in-kvm_ar.patch b/patches/qemu-0002-target-i386-kvm-Report-which-action-failed-in-kvm_ar.patch new file mode 100644 index 000000000..aaebcc790 --- /dev/null +++ b/patches/qemu-0002-target-i386-kvm-Report-which-action-failed-in-kvm_ar.patch @@ -0,0 +1,169 @@ +From f680584567227c2af540cf93c7eacaf932a2b1a3 Mon Sep 17 00:00:00 2001 +From: Julia Suvorova +Date: Fri, 27 Sep 2024 12:47:41 +0200 +Subject: [PATCH 2/2] target/i386/kvm: Report which action failed in + kvm_arch_put/get_registers + +To help debug and triage future failure reports (akin to [1,2]) that +may occur during kvm_arch_put/get_registers, the error path of each +action is accompanied by unique error message. + +[1] https://issues.redhat.com/browse/RHEL-7558 +[2] https://issues.redhat.com/browse/RHEL-21761 + +Signed-off-by: Julia Suvorova +Reviewed-by: Peter Xu +Link: https://lore.kernel.org/r/20240927104743.218468-3-jusual@redhat.com +Signed-off-by: Paolo Bonzini +(cherry picked from commit fc058618d1596d29e89016750a1aaf64c9fe8832) +--- + target/i386/kvm/kvm.c | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/target/i386/kvm/kvm.c b/target/i386/kvm/kvm.c +index ab0c6499f5..b61b32ca01 100644 +--- a/target/i386/kvm/kvm.c ++++ b/target/i386/kvm/kvm.c +@@ -4567,6 +4567,7 @@ int kvm_arch_put_registers(CPUState *cpu, int level, Error **errp) + if (level >= KVM_PUT_RESET_STATE) { + ret = kvm_put_msr_feature_control(x86_cpu); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to set feature control MSR"); + return ret; + } + } +@@ -4574,12 +4575,14 @@ int kvm_arch_put_registers(CPUState *cpu, int level, Error **errp) + /* must be before kvm_put_nested_state so that EFER.SVME is set */ + ret = has_sregs2 ? kvm_put_sregs2(x86_cpu) : kvm_put_sregs(x86_cpu); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to set special registers"); + return ret; + } + + if (level >= KVM_PUT_RESET_STATE) { + ret = kvm_put_nested_state(x86_cpu); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to set nested state"); + return ret; + } + } +@@ -4597,6 +4600,7 @@ int kvm_arch_put_registers(CPUState *cpu, int level, Error **errp) + if (xen_mode == XEN_EMULATE && level == KVM_PUT_FULL_STATE) { + ret = kvm_put_xen_state(cpu); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to set Xen state"); + return ret; + } + } +@@ -4604,37 +4608,45 @@ int kvm_arch_put_registers(CPUState *cpu, int level, Error **errp) + + ret = kvm_getput_regs(x86_cpu, 1); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to set general purpose registers"); + return ret; + } + ret = kvm_put_xsave(x86_cpu); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to set XSAVE"); + return ret; + } + ret = kvm_put_xcrs(x86_cpu); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to set XCRs"); + return ret; + } + ret = kvm_put_msrs(x86_cpu, level); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to set MSRs"); + return ret; + } + ret = kvm_put_vcpu_events(x86_cpu, level); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to set vCPU events"); + return ret; + } + if (level >= KVM_PUT_RESET_STATE) { + ret = kvm_put_mp_state(x86_cpu); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to set MP state"); + return ret; + } + } + + ret = kvm_put_tscdeadline_msr(x86_cpu); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to set TSC deadline MSR"); + return ret; + } + ret = kvm_put_debugregs(x86_cpu); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to set debug registers"); + return ret; + } + return 0; +@@ -4649,6 +4661,7 @@ int kvm_arch_get_registers(CPUState *cs, Error **errp) + + ret = kvm_get_vcpu_events(cpu); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to get vCPU events"); + goto out; + } + /* +@@ -4657,44 +4670,54 @@ int kvm_arch_get_registers(CPUState *cs, Error **errp) + */ + ret = kvm_get_mp_state(cpu); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to get MP state"); + goto out; + } + ret = kvm_getput_regs(cpu, 0); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to get general purpose registers"); + goto out; + } + ret = kvm_get_xsave(cpu); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to get XSAVE"); + goto out; + } + ret = kvm_get_xcrs(cpu); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to get XCRs"); + goto out; + } + ret = has_sregs2 ? kvm_get_sregs2(cpu) : kvm_get_sregs(cpu); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to get special registers"); + goto out; + } + ret = kvm_get_msrs(cpu); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to get MSRs"); + goto out; + } + ret = kvm_get_apic(cpu); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to get APIC"); + goto out; + } + ret = kvm_get_debugregs(cpu); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to get debug registers"); + goto out; + } + ret = kvm_get_nested_state(cpu); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to get nested state"); + goto out; + } + #ifdef CONFIG_XEN_EMU + if (xen_mode == XEN_EMULATE) { + ret = kvm_get_xen_state(cs); + if (ret < 0) { ++ error_setg_errno(errp, -ret, "Failed to get Xen state"); + goto out; + } + } +-- +2.43.0 + diff --git a/patches/uefivars-Revert-Use-google-crc32c-instead-of-crc32c.patch b/patches/uefivars-Revert-Use-google-crc32c-instead-of-crc32c.patch new file mode 100644 index 000000000..c8fa51b78 --- /dev/null +++ b/patches/uefivars-Revert-Use-google-crc32c-instead-of-crc32c.patch @@ -0,0 +1,66 @@ +From: Mate Kukri +Date: Thu, 19 Oct 2023 11:48:21 +0100 +Subject: Revert "Use google-crc32c instead of crc32c" + +This reverts commit 9679002a4392d8e7831d2dbda3fab41ccc5c6b8c. + +google-crc32c isn't currently packaged in Ubuntu, crc32c however +is, and there isn't a seemingly good reason to use the former +outside of licensing appeal to upstream hence this patch. +--- + pyuefivars/aws.py | 9 ++++----- + setup.py | 2 +- + 2 files changed, 5 insertions(+), 6 deletions(-) + +diff --git a/pyuefivars/aws.py b/pyuefivars/aws.py +index 24bf4d8..9e430dc 100644 +--- a/pyuefivars/aws.py ++++ b/pyuefivars/aws.py +@@ -7,12 +7,11 @@ import os + import zlib + import base64 + import tempfile +-import google_crc32c as crc32c ++import crc32c + from .varstore import UEFIVar, UEFIVarStore + from .aws_v0 import UEFIVarStoreV0 + from .aws_file import AWSVarStoreFile + +- + class AWSUEFIVarStore(UEFIVarStore): + EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS = 0x20 + AMZNUEFI = 0x494645554e5a4d41 +@@ -34,7 +33,7 @@ class AWSUEFIVarStore(UEFIVarStore): + + # Validate crc32c + location = file.file.tell() +- comp_crc32 = crc32c.value(file.readall()) ++ comp_crc32 = crc32c.crc32(file.readall()) + if (comp_crc32 != crc32): + raise Exception("Invalid checksum, please check you copied all data") + file.file.seek(location, os.SEEK_SET) +@@ -96,8 +95,8 @@ class AWSUEFIVarStore(UEFIVarStore): + f = tempfile.SpooledTemporaryFile() + f = AWSVarStoreFile(f) + f.write64(self.AMZNUEFI) +- f.write32(crc32c.value(int(0).to_bytes(4, byteorder='little') + zdata)) +- f.write32(0) # Version 0 ++ f.write32(crc32c.crc32(int(0).to_bytes(4, byteorder='little') + zdata)) ++ f.write32(0) # Version 0 + f.write(zdata) + f.file.seek(0, os.SEEK_SET) + +diff --git a/setup.py b/setup.py +index df3da7b..5fc454c 100644 +--- a/setup.py ++++ b/setup.py +@@ -18,7 +18,7 @@ setuptools.setup( + long_description_content_type='text/markdown', + url="https://github.com/awslabs/python-uefivars", + packages=setuptools.find_packages(), +- install_requires=['google-crc32c', 'deepdiff'], ++ install_requires=['crc32c', 'deepdiff'], + entry_points={ + 'console_scripts': [ + 'uefivars = pyuefivars:main', + diff --git a/shmounts/setup-shmounts.c b/shmounts/setup-shmounts.c index c4ae80ab4..c5ceece03 100644 --- a/shmounts/setup-shmounts.c +++ b/shmounts/setup-shmounts.c @@ -66,6 +66,12 @@ int mkdir_p(const char *dir, mode_t mode) return 0; } +__attribute__((noreturn)) +static void die(const char *s) { + perror(s); + exit(1); +} + int setup_ns() { int wstatus; ssize_t ret; @@ -94,40 +100,41 @@ int setup_ns() { ret = lxc_read_nointr(pipe_fds[0], nspath, 1); close(pipe_fds[0]); if (ret < 0) { - return -1; + die("cannot read from pipe"); } // Create the mountpoint if (mkdir("/var/snap/lxd/common/ns", 0700) < 0 && errno != EEXIST) { - return -1; + die("cannot mkdir /var/snap/lxd/common/ns"); } // Mount a tmpfs if (mount("tmpfs", "/var/snap/lxd/common/ns", "tmpfs", 0, "size=1M,mode=0700") < 0) { - return -1; + die("cannot mount tmpfs on /var/snap/lxd/common/ns"); } // Mark the tmpfs mount as MS_PRIVATE if (mount("none", "/var/snap/lxd/common/ns", NULL, MS_REC|MS_PRIVATE, NULL) < 0) { - return -1; + die("cannot change propagation on /var/snap/lxd/common/ns"); } // Store reference to the mntns if (snprintf(nspath, PATH_MAX, "/proc/%u/ns/mnt", (unsigned)getppid()) < 0) { - return -1; + die("cannot capture reference to parent's mount ns"); } fd = open("/var/snap/lxd/common/ns/shmounts", O_CREAT | O_RDWR, 0600); if (fd < 0) { - return -1; + die("cannot open /var/snap/lxd/common/ns/shmounts"); } close(fd); if (mount(nspath, "/var/snap/lxd/common/ns/shmounts", NULL, MS_BIND, NULL) < 0) { - return -1; + die("cannot bind mount ns to /var/snap/lxd/common/ns/shmounts"); } - return 0; + /* the child is done */ + exit(0); } close(pipe_fds[0]); diff --git a/snap-query/snap-query.go b/snap-query/snap-query.go deleted file mode 100644 index 7b99227ab..000000000 --- a/snap-query/snap-query.go +++ /dev/null @@ -1,99 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "net" - "net/http" - "os" -) - -type snapChanges struct { - Type string `json:"type"` - StatusCode int `json:"status-code"` - Result []snapChangesResult `json:"result"` -} - -type snapChangesResult struct { - Kind string `json:"kind"` -} - -func main() { - if len(os.Args) != 3 { - fmt.Fprintf(os.Stderr, "Usage: %s \n", os.Args[0]) - os.Exit(1) - } - - change, err := getLastSnapChange(os.Args[1], os.Args[2]) - if err != nil { - fmt.Fprintf(os.Stderr, "Error: %v\n", err) - os.Exit(1) - } - - fmt.Printf("%s\n", change) -} - -func unixHTTPClient(path string) (*http.Client, error) { - // Setup a Unix socket dialer - unixDial := func(network, addr string) (net.Conn, error) { - raddr, err := net.ResolveUnixAddr("unix", path) - if err != nil { - return nil, err - } - - return net.DialUnix("unix", nil, raddr) - } - - // Define the http transport - transport := &http.Transport{ - Dial: unixDial, - DisableKeepAlives: true, - } - - // Define the http client - client := &http.Client{} - client.Transport = transport - - return client, nil -} - -func getLastSnapChange(path string, snap string) (string, error) { - // Connect to snapd - client, err := unixHTTPClient(path) - if err != nil { - return "", err - } - - // Prepare the request - req, err := http.NewRequest("GET", fmt.Sprintf("http://unix.socket/v2/changes?select=in-progress&for=%s", snap), nil) - if err != nil { - return "", err - } - - // Get the changes - resp, err := client.Do(req) - if err != nil { - return "", err - } - defer resp.Body.Close() - - // Parse the output - changes := snapChanges{} - decoder := json.NewDecoder(resp.Body) - err = decoder.Decode(&changes) - if err != nil { - return "", err - } - - // Check for errors - if changes.StatusCode != 200 { - return "", fmt.Errorf("Failed to retrieve changes, status=%d", changes.StatusCode) - } - - // Return entry - for _, change := range changes.Result { - return change.Kind, nil - } - - return "", nil -} diff --git a/snapcraft.yaml b/snapcraft.yaml index 6733f5403..3fa75cb9b 100644 --- a/snapcraft.yaml +++ b/snapcraft.yaml @@ -1,11 +1,12 @@ name: lxd -base: core22 +base: core24 assumes: - snapd2.39 -version: "5.20" +version: "6.6" grade: stable summary: LXD - container and VM manager -license: AGPL-3.0 +license: AGPL-3.0-only +title: LXD description: |- LXD is a system container and virtual machine manager. @@ -31,24 +32,27 @@ description: |- Supported configuration options for the snap (snap set lxd [=...]): + - apparmor.unprivileged-restrictions-disable: Whether to disable restrictions on unprivileged user namespaces [default=true] - ceph.builtin: Use snap-specific Ceph configuration [default=false] - ceph.external: Use the system's ceph tools (ignores ceph.builtin) [default=false] - - criu.enable: Enable experimental live-migration support [default=false] - daemon.debug: Increase logging to debug level [default=false] - daemon.group: Set group of users that have full control over LXD [default=lxd] - daemon.user.group: Set group of users that have restricted LXD access [default=lxd] - daemon.preseed: Pass a YAML configuration to `lxd init` on initial start - daemon.syslog: Send LXD log events to syslog [default=false] - daemon.verbose: Increase logging to verbose level [default=false] + - db.trace: Enable dqlite trace logging (very verbose) [default=false] - lvm.external: Use the system's LVM tools [default=false] - - lxcfs.pidfd: Start per-container process tracking [default=false] + - lxcfs.pidfd: Start per-container process tracking [default=true] - lxcfs.loadavg: Start tracking per-container load average [default=false] - lxcfs.cfs: Consider CPU shares for CPU usage [default=false] - lxcfs.debug: Increase logging to debug level [default=false] + - minio.path: Path to the directory containing the minio and mc binaries to use with LXD [default=""] - openvswitch.builtin: Run a snap-specific OVS daemon [default=false] - 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=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) @@ -63,6 +67,26 @@ plugs: ceph-conf: interface: content target: "$SNAP_DATA/microceph" + ovn-certificates: + interface: content + target: "$SNAP_DATA/microovn/certificates" + ovn-chassis: + interface: content + target: "$SNAP_DATA/microovn/chassis" + gpu-2404: + interface: content + target: $SNAP/gpu-2404 +# default-provider: mesa-2404 + qemu-external: + interface: content + content: qemu-external-binaries + target: $SNAP/external/qemu + +layout: + /usr/share/libdrm: + bind: $SNAP/gpu-2404/libdrm + /usr/share/drirc.d: + symlink: $SNAP/gpu-2404/drirc.d apps: # Main commands @@ -74,6 +98,8 @@ apps: - system-observe daemon: + command-chain: + - bin/gpu-2404-custom-wrapper command: commands/daemon.start reload-command: commands/daemon.reload stop-command: commands/daemon.stop @@ -107,7 +133,7 @@ apps: lxc: command: commands/lxc - completer: etc/bash_completion.d/snap.lxd.lxc + completer: lxc-completer.sh plugs: - lxd-support - system-observe @@ -119,11 +145,6 @@ apps: - system-observe # Sub-commands - benchmark: - command: commands/lxd-benchmark - plugs: - - lxd-support - - system-observe buginfo: command: commands/buginfo plugs: @@ -134,23 +155,37 @@ apps: plugs: - lxd-support - system-observe - lxc-to-lxd: - command: commands/lxc-to-lxd + +hooks: + connect-plug-ceph-conf: plugs: - lxd-support - system-observe - migrate: - command: commands/lxd-migrate + disconnect-plug-ceph-conf: plugs: - lxd-support - system-observe - -hooks: - connect-plug-ceph-conf: + connect-plug-ovn-certificates: plugs: - lxd-support - system-observe - disconnect-plug-ceph-conf: + disconnect-plug-ovn-certificates: + plugs: + - lxd-support + - system-observe + connect-plug-ovn-chassis: + plugs: + - lxd-support + - system-observe + disconnect-plug-ovn-chassis: + plugs: + - lxd-support + - system-observe + connect-plug-qemu-external: + plugs: + - lxd-support + - system-observe + disconnect-plug-qemu-external: plugs: - lxd-support - system-observe @@ -178,12 +213,34 @@ parts: - bin/mkfs.btrfs ceph: + after: + - libatomic plugin: nil stage-packages: - - ceph-common + # XXX: explicitly depend on libsnappy1v5 due to https://bugs.launchpad.net/ubuntu/+source/ceph/+bug/2072656 + - to armhf: [] + - else: + - ceph-common + - libsnappy1v5 organize: usr/bin/: bin/ usr/lib/: lib/ + override-stage: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + override-prime: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + override-pull: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + override-build: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default prime: - bin/ceph - bin/radosgw-admin @@ -197,14 +254,21 @@ parts: - lib/*/libboost_iostreams.so* - lib/*/libboost_program_options.so* - lib/*/libboost_thread.so* + - lib/*/libboost_url.so* + - lib/*/libbrotlicommon.so* + - lib/*/libbrotlidec.so* - lib/*/libcurl-gnutls.so* - lib/*/libdaxctl.so* - lib/*/libibverbs.so* - lib/*/libicudata.so* - lib/*/libicuuc.so* - lib/*/liblber-2.5.so* + - lib/*/liblber.so* - lib/*/libldap-2.5.so* - - lib/*/liblua5.3.so* + - lib/*/libldap.so* + - lib/*/liblmdb.so* + - lib/*/liblua5.4.so* + - lib/*/libncurses.so* - lib/*/libndctl.so* - lib/*/libnghttp2.so* - lib/*/liboath.so* @@ -218,103 +282,77 @@ parts: - lib/*/librtmp.so* - lib/*/libsasl2.so* - lib/*/libsnappy.so* - - criu: - source: https://github.com/checkpoint-restore/criu - source-tag: v3.19 - source-type: git - source-depth: 1 - plugin: nil - build-packages: - - asciidoc - - libcap-dev - - libnet1-dev - - libnl-3-dev - - libprotobuf-c-dev - - libprotobuf-dev - - protobuf-c-compiler - - protobuf-compiler - - xmlto - stage-packages: - - libnet1 - - libprotobuf-c1 - override-pull: |- - [ "$(uname -m)" != "x86_64" ] && \ - [ "$(uname -m)" != "armv7l" ] && \ - [ "$(uname -m)" != "aarch64" ] && \ - [ "$(uname -m)" != "s390x" ] && \ - [ "$(uname -m)" != "ppc64le" ] && exit 0 - craftctl default - override-build: |- - [ "$(uname -m)" != "x86_64" ] && \ - [ "$(uname -m)" != "armv7l" ] && \ - [ "$(uname -m)" != "aarch64" ] && \ - [ "$(uname -m)" != "s390x" ] && \ - [ "$(uname -m)" != "ppc64le" ] && exit 0 - set -ex - - make - mkdir -p "${CRAFT_PART_INSTALL}/criu/" - cp criu/criu "${CRAFT_PART_INSTALL}/criu/" - organize: - usr/lib/: lib/ - prime: - - criu/* - - lib/*/libnet* - - lib/*/libproto* + - lib/*/libssh.so* + - lib/*/libtcmalloc.so* + - lib/*/libunwind.so* dqlite: - after: - - raft - - sqlite source: https://github.com/canonical/dqlite - source-tag: v1.16.0 - source-type: git source-depth: 1 + source-commit: b0156f030b9273ae890b846f9a632cf696ace816 # v1.18.5 + source-type: git plugin: autotools autotools-configure-parameters: - --prefix= + - --enable-build-raft stage-packages: - - libuv1 + - liblz4-1 + - libuv1t64 + - sqlite3 build-packages: + - liblz4-dev + - libsqlite3-dev - libuv1-dev + - xfslibs-dev organize: + usr/bin/: bin/ usr/lib/: lib/ prime: + - bin/sqlite3 - lib/libdqlite*so* + - lib/*/libsqlite3*so* - lib/*/libuv* + #- lib/*/liblz4.so* # use liblz4.so from the base snap edk2: - after: - - nasm source: https://github.com/tianocore/edk2 - source-type: git - source-tag: IRRELEVANT source-depth: 1 + source-commit: 8736b8fdca85e02933cdb0a13309de14c9799ece # edk2-stable202311 + source-submodules: [] + source-type: git plugin: nil build-packages: - - on amd64: + - to amd64: + - g++ - acpica-tools + - nasm - uuid-dev - - on arm64: + - to arm64: + - g++ - acpica-tools + - nasm - uuid-dev - override-pull: |- + override-stage: |- [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && exit 0 - set -ex - git config --global transfer.fsckobjects true - git clone https://github.com/tianocore/edk2 . -b edk2-stable202305 - override-build: |- + craftctl default + override-prime: |- [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && exit 0 + craftctl default + override-pull: |- + [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && exit 0 + craftctl default + set -ex - # Git cherry-picks - git config user.email "noreply@lists.canonical.com" - git config user.name "LXD snap builder" + # Fix submodule sources + # see https://github.com/tianocore/edk2/commit/95d8a1c255cfb8e063d679930d08ca6426eb5701 + sed -i "s#https://github.com/Zeex/subhook.git#https://github.com/tianocore/edk2-subhook.git#g" .gitmodules - # Fix submodules - sed -i "s#https://git.cryptomilk.org/projects/cmocka#https://gitlab.com/cmocka/cmocka#g" .gitmodules + # Pull submodules after switching to source-commit git submodule update --init --recursive + override-build: |- + [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && exit 0 + set -ex # Apply patches patch -p1 < "${CRAFT_PROJECT_DIR}/patches/edk2-0001-force-DUID-LLT.patch" @@ -322,9 +360,10 @@ parts: patch -p1 < "${CRAFT_PROJECT_DIR}/patches/edk2-0003-boot-delay.patch" patch -p1 < "${CRAFT_PROJECT_DIR}/patches/edk2-0004-gcc-errors.patch" patch --binary -p1 < "${CRAFT_PROJECT_DIR}/patches/edk2-0005-disable-dynamic-mmio-winsize.patch" - # revert "ArmVirtPkg: make EFI_LOADER_DATA non-executable" as it breaks almost everything - git revert 2997ae38739756ecba9b0de19e86032ebc689ef9 patch --binary -p1 < "${CRAFT_PROJECT_DIR}/patches/edk2-0006-disable-EFI-memory-attributes-protocol.patch" + patch --binary -p1 < "${CRAFT_PROJECT_DIR}/patches/edk2-0007-Disable-the-Shell-when-SecureBoot-is-enabled.patch" + # revert "ArmVirtPkg: make EFI_LOADER_DATA non-executable" as it breaks almost everything + patch --binary -p1 < "${CRAFT_PROJECT_DIR}/patches/edk2-0008-Revert-ArmVirtPkg-make-EFI_LOADER_DATA-non-execurable.patch" # Arch-specific logic ARCH="X64" @@ -402,97 +441,22 @@ parts: prime: - share/qemu/* - libmnl: - source: https://git.netfilter.org/libmnl - source-type: git - source-tag: libmnl-1.0.5 - plugin: autotools - autotools-configure-parameters: - - --prefix= - organize: - usr/lib/: lib/ - prime: - - lib/libmnl*so* - - libnftnl: - after: - - libmnl - source: https://git.netfilter.org/libnftnl - source-type: git - source-tag: libnftnl-1.2.6 - plugin: autotools - autotools-configure-parameters: - - --prefix= - organize: - usr/lib/: lib/ - prime: - - lib/libnftnl*so* - override-build: | - craftctl default - - sed -i "s# /lib/libmnl.la# ${CRAFT_STAGE}/lib/libmnl.la#g" "${CRAFT_PART_INSTALL}/lib/libnftnl.la" - - libseccomp: - source: https://github.com/seccomp/libseccomp - source-type: git - source-tag: v2.5.5 - source-depth: 1 - plugin: autotools - autotools-configure-parameters: - - --prefix= - build-packages: - - gperf - organize: - usr/lib/: lib/ - prime: - - lib/libseccomp*so* - - libtpms: - source: https://github.com/stefanberger/libtpms - source-type: git - source-tag: v0.9.6 - source-depth: 1 - plugin: autotools - autotools-configure-parameters: - - --prefix= - - --with-tpm2 - - --with-openssl - organize: - usr/lib/: lib/ - prime: - - lib/libtpms*so* - - liburing: - source: https://github.com/axboe/liburing - source-type: git - source-tag: liburing-2.5 - source-depth: 1 - plugin: autotools - autotools-configure-parameters: - - --prefix= - override-pull: |- - [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && [ "$(uname -m)" != "ppc64le" ] && [ "$(uname -m)" != "s390x" ] && exit 0 + libatomic: + plugin: nil + override-stage: |- + [ "$(uname -m)" != "s390x" ] && exit 0 craftctl default - override-build: |- - [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && [ "$(uname -m)" != "ppc64le" ] && [ "$(uname -m)" != "s390x" ] && exit 0 + override-prime: |- + [ "$(uname -m)" != "s390x" ] && exit 0 craftctl default + stage-packages: + - to s390x: + - libatomic1 organize: usr/lib/: lib/ prime: - - lib/liburing*so* - - libusb: - source: https://github.com/libusb/libusb - source-type: git - source-tag: v1.0.26 - source-depth: 1 - plugin: autotools - autotools-configure-parameters: - - --prefix= - organize: - usr/lib/: lib/ - prime: - - lib/libusb*so* + # XXX: libatomic.so is only needed by Ceph/QEMU on s390x and no other arch. + - lib/*/libatomic.so* logrotate: plugin: nil @@ -517,6 +481,27 @@ parts: sbin/: bin/ usr/lib/: lib/ usr/sbin/: bin/ + override-build: |- + # Patch lvm.conf to: + # 1) Disable bits that don't apply in a snap'ed env. Handle commented + # out variants that represent builtin values. + # * udev_sync + # * udev_rules + # * use_lvmetad + # * monitoring + # 2) Uncomment all executable directives to override their builtin + # values. Replace paths in /usr/bin, /usr/sbin, /bin and /sbin + # by /snap/lxd/current/bin to use executables from the snap. + 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 @@ -532,114 +517,56 @@ parts: - -bin/lvmetad - -bin/lvmpolld - etc/lvm/lvm.conf + - etc/lvm/profile/* - lib/*/device-mapper/* - lib/*/libaio.so* - lib/*/libdevmapper* - lib/*/liblvm* - lib/*/libreadline.so* - minio: - source: https://github.com/minio/minio - source-type: git - source-tag: RELEASE.2023-11-20T22-40-07Z - source-depth: 1 - plugin: nil - build-snaps: - - go/1.21/stable - override-pull: | - [ "$(uname -m)" = "riscv64" ] && exit 0 - - craftctl default - override-build: | - [ "$(uname -m)" = "riscv64" ] && exit 0 - - set -ex - - # Setup build environment - export GOPATH="$(realpath ./.go)" - - # Build the binaries - make build - - # Install minio command - mkdir -p "${CRAFT_PART_INSTALL}/bin/" - cp minio "${CRAFT_PART_INSTALL}/bin/minio" - prime: - - bin/minio* - - nano: - plugin: nil - stage-packages: - - nano - organize: - usr/bin/: bin/ - prime: - - bin/nano - - etc/nanorc - - nasm: - source: https://github.com/netwide-assembler/nasm - source-type: git - source-tag: nasm-2.16.01 - source-depth: 1 - plugin: autotools - autotools-configure-parameters: - - --prefix= - organize: - usr/bin/: bin/ - prime: - - bin/nasm - override-build: | - patch -p1 < "${CRAFT_PROJECT_DIR}/patches/nasm-0000-disable-manpages.patch" - craftctl default - nftables: - after: - - libmnl - - libnftnl - source: https://git.netfilter.org/nftables - source-type: git - source-tag: v1.0.9 - plugin: autotools - autotools-configure-parameters: - - --prefix= - - --with-json - build-packages: - - libedit-dev - - libjansson-dev - - libreadline-dev + plugin: nil stage-packages: - - libjansson4 - override-build: | - set -ex - - # Git cherry-picks - git config user.email "noreply@lists.canonical.com" - git config user.name "LXD snap builder" - - set +ex - craftctl default + - nftables organize: - sbin/: bin/ usr/lib/: lib/ + usr/sbin/: bin/ prime: - bin/nft - lib/*/libjansson*so* - - lib/libnftables*so* + - lib/*/libnftables*so* nvidia-container: - after: - - libseccomp source: https://github.com/NVIDIA/libnvidia-container - source-type: git - source-tag: v1.14.3 + source-commit: 889a3bb5408c195ed7897ba2cb8341c7d249672f # v1.18.0 source-depth: 1 + source-type: git plugin: make + build-environment: + - GIT_TAG: "1.18.0" # Enables source-depth: 1, should match git tag without "v" prefix. build-packages: - - bmake - - curl - - libelf-dev - - lsb-release + - to amd64: + - bmake + - curl + - libelf-dev + - libseccomp-dev + - lsb-release + - libtirpc-dev + - to arm64: + - bmake + - curl + - libelf-dev + - libseccomp-dev + - lsb-release + - libtirpc-dev + build-snaps: + - go/1.25/stable + override-stage: |- + [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && exit 0 + craftctl default + override-prime: |- + [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && exit 0 + craftctl default override-pull: |- [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && exit 0 craftctl default @@ -647,6 +574,9 @@ parts: [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && exit 0 set -ex + # Setup build environment + export GOTOOLCHAIN="local" + # Git cherry-picks git config user.email "noreply@lists.canonical.com" git config user.name "LXD snap builder" @@ -664,69 +594,126 @@ parts: usr/local/lib: lib/ prime: - bin/nvidia-container-cli* - - lib/libnvidia-container*.so* + - lib/libnvidia-container.so* + - lib/libnvidia-container-go.so* # dlopen()'ed by libnvidia-container.so + + nvidia-container-toolkit: + source: https://github.com/NVIDIA/nvidia-container-toolkit + source-depth: 1 + source-commit: f8daa5e26de9fd7eb79259040b6dd5a52060048c # v1.18.0 + source-type: git + build-snaps: + - go/1.25/stable + plugin: make + override-stage: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + override-prime: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + override-pull: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + override-build: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + set -ex + + # Setup build environment + export GOTOOLCHAIN="local" + + 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: - nvme-cli + organize: + usr/lib/: lib/ + usr/sbin/: bin/ + prime: + - bin/nvme + - lib/*/libnvme* openvswitch: - source: https://github.com/openvswitch/ovs - source-type: git - source-tag: v3.2.1 - source-depth: 1 - plugin: autotools - autotools-configure-parameters: - - --enable-ssl - - --prefix= + plugin: nil stage-packages: - - uuid-runtime + - to armhf: [] + - else: + - openvswitch-common + - openvswitch-switch + override-stage: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + override-prime: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + override-pull: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + override-build: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default organize: sbin/: bin/ usr/bin/: bin/ + usr/lib/: lib/ + usr/share/: share/ prime: - - bin/ovs-appctl - bin/ovs-vsctl - - bin/ovs-vswitchd - - bin/ovsdb-* - - bin/uuidgen - - share/openvswitch/ + - lib/*/libunbound*so* + - share/openvswitch/*.ovsschema ovn: after: - openvswitch - source: https://github.com/ovn-org/ovn - source-type: git - source-tag: v23.09.1 - source-depth: 1 - plugin: autotools - autotools-configure-parameters: - - --enable-ssl - - --prefix= - - --with-ovs-source=../../openvswitch/build/ + plugin: nil + stage-packages: + - to armhf: [] + - else: + - ovn-common + override-stage: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + override-prime: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + override-pull: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + override-build: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + organize: + usr/bin/: bin/ + usr/lib/: lib/ prime: - bin/ovn-nbctl - bin/ovn-sbctl - - spice-protocol: - source: https://gitlab.freedesktop.org/spice/spice-protocol - source-type: git - source-tag: v0.14.4 - source-depth: 1 - plugin: meson - prime: [] - build-packages: - - meson - - ninja-build + - lib/*/libunbound*so* spice-server: - after: - - spice-protocol - source: https://gitlab.freedesktop.org/spice/spice - source-type: git - source-tag: v0.15.2 + source: https://git.launchpad.net/ubuntu/+source/spice + source-commit: 085ca6b2bf58014ad8be571f3b601465c85ae931 # import/0.15.1-1build2 source-depth: 1 + source-type: git plugin: meson meson-parameters: - --prefix=/ @@ -738,14 +725,41 @@ parts: - -Dsmartcard=disabled - -Dtests=false build-packages: - - libjpeg-turbo8-dev - - python3-pyparsing - - python3-six - - meson - - ninja-build + - to armhf: [] + - else: + - libspice-protocol-dev + - libjpeg-turbo8-dev + - python3-pyparsing + - python3-six + - meson + - ninja-build stage-packages: - - libjpeg-turbo8 - - libpixman-1-0 + - to armhf: [] + - else: + - libjpeg-turbo8 + - libpixman-1-0 + override-stage: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + override-prime: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + override-pull: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + override-build: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + + # Apply patches from Ubuntu sources. + cd ../src + QUILT_PATCHES=debian/patches quilt push -a + cd ../build + + craftctl default organize: sbin/: bin/ usr/lib: lib/ @@ -756,63 +770,58 @@ parts: - lib/*/libpixman*so* swtpm: - after: - - libseccomp - - libtpms - source: https://github.com/stefanberger/swtpm - source-type: git - source-tag: v0.8.1 - source-depth: 1 - plugin: autotools - autotools-configure-parameters: - - --prefix= - - --with-seccomp - - --with-openssl - - --without-cuse - build-packages: - - expect - - gawk - - iproute2 - - libjson-glib-dev - - python3-cryptography - - python3-setuptools - - socat + plugin: nil stage-packages: - - libjson-glib-1.0-0 + - swtpm organize: usr/bin/: bin/ usr/lib/: lib/ - lib/swtpm/: lib/ prime: - bin/swtpm - - lib/libswtpm*so* - - lib/*/libjson-glib-1.0.so* + - lib/*/swtpm/libswtpm*so* + - lib/*/libtpms*so* qemu: after: - - libseccomp - - liburing - - libusb - - spice-protocol + - libatomic - spice-server - source: https://gitlab.com/qemu-project/qemu - source-type: git - source-tag: v8.1.3 + source: https://git.launchpad.net/ubuntu/+source/qemu + source-commit: bc0011afab01de8c41ec80fc8c24dd33fb30cd90 # import/1%8.2.2+ds-0ubuntu1.10 source-depth: 1 + source-type: git plugin: autotools autotools-configure-parameters: + - --disable-auth-pam - --disable-bochs + - --disable-brlapi - --disable-cloop + - --disable-curl - --disable-dmg - --disable-docs + - --disable-fuse + - --disable-glusterfs + - --disable-gnutls + - --disable-gtk - --disable-guest-agent + - --disable-libiscsi + - --disable-libnfs + - --disable-libpmem + - --disable-libssh + - --disable-nettle + - --disable-oss - --disable-parallels + - --disable-pvrdma - --disable-qed + - --disable-sdl - --disable-slirp - --disable-user + - --disable-vde - --disable-vdi + - --disable-vmnet - --disable-vnc + - --disable-vvfat - --disable-xen + - --disable-xkbcommon - --enable-attr - --enable-cap-ng - --enable-kvm @@ -835,47 +844,80 @@ parts: - --enable-virtfs - --firmwarepath=/snap/lxd/current/share/qemu/ - --localstatedir=/var/ + - --disable-install-blobs # Ubuntu sources don't have the ROM blobs in them. build-packages: - - bison - - flex - - pkg-config - - libaio-dev - - libcap-ng-dev - - libglib2.0-dev - - libnuma-dev - - libpixman-1-dev - - librbd-dev - - libusbredirhost-dev + - to armhf: [] + - else: + - bison + - bzip2 + - flex + - pkg-config + - libaio-dev + - libcap-ng-dev + - libfdt-dev + - libglib2.0-dev + - libnuma-dev + - libpixman-1-dev + - libseccomp-dev + - liburing-dev + - libusb-1.0-0-dev + - libusbredirparser-dev + - quilt + - librbd-dev stage-packages: - - genisoimage - - libatomic1 - - libmagic1 - - libnuma1 - - libpixman-1-0 - - libusbredirhost1 - - libusbredirparser1 - - seabios + - to armhf: [] + - else: + - genisoimage + - ipxe-qemu # This is needed due to --disable-install-blobs. + - libfdt1 + - libmagic1t64 + - libnuma1 + - libpixman-1-0 + - libusb-1.0-0 + - libusbredirparser1t64 + - liburing2 + - seabios # This is needed due to --disable-install-blobs. + - qemu-system-data # This is needed due to --disable-install-blobs. + override-stage: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + override-prime: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default override-pull: |- - [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && [ "$(uname -m)" != "ppc64le" ] && [ "$(uname -m)" != "s390x" ] && exit 0 + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 craftctl default - override-build: |- - [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && [ "$(uname -m)" != "ppc64le" ] && [ "$(uname -m)" != "s390x" ] && exit 0 - + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 set -ex # Mangle the configure a bit QEMUARCH="$(uname -m)" [ "${QEMUARCH}" = "ppc64le" ] && QEMUARCH="ppc64" + + # Apply patches from Ubuntu sources. + QUILT_PATCHES=debian/patches quilt push -a + + # Apply custom patches + # These patches enable more accurate error message returned in case of CPU registers mismatches. + # This is backported from QEMU v9.2.2. + patch -p1 < "${CRAFT_PROJECT_DIR}/patches/qemu-0001-kvm-Allow-kvm_arch_get-put_registers-to-accept-Error.patch" + patch -p1 < "${CRAFT_PROJECT_DIR}/patches/qemu-0002-target-i386-kvm-Report-which-action-failed-in-kvm_ar.patch" + sed -i "s/^unset target_list$/target_list=\"${QEMUARCH}-softmmu\"/" configure sed -i 's#libseccomp_minver=".*#libseccomp_minver="0.0"#g' configure + # Extract efi-virtio.rom from ipxe-qemu. + # This doesn't work in the organize section below. + mkdir -p "${CRAFT_PART_INSTALL}"/share/qemu + mv "${CRAFT_PART_INSTALL}"/usr/lib/ipxe/qemu/efi-virtio.rom "${CRAFT_PART_INSTALL}"/share/qemu/ + set +ex craftctl default - set -ex - # we don't want to take this file from the qemu tree, but instead from the seabios package - rm "${CRAFT_PART_INSTALL}/usr/local/share/qemu/bios-256k.bin" - set +ex organize: usr/bin/: bin/ usr/lib/: lib/ @@ -883,7 +925,12 @@ parts: usr/local/lib/: lib/ usr/local/libexec/: bin/ usr/local/share/: share/ + usr/share/qemu/kvmvapic.bin: share/qemu/ + usr/share/qemu/s390-ccw.img: share/qemu/ + usr/share/qemu/s390-netboot.img: share/qemu/ + usr/share/qemu/slof.bin: share/qemu/ usr/share/seabios/bios-256k.bin: share/qemu/ + usr/share/seabios/vgabios-*: share/qemu/ prime: - bin/genisoimage* - bin/mkisofs* @@ -894,14 +941,22 @@ parts: - lib/*/libmagic*so* - lib/*/libnuma*so* - lib/*/libpixman*so* + - lib/*/liburing.so* - lib/*/libusbredir*so* - - share/qemu/keymaps* - - share/qemu/efi-virtio.rom* - - share/qemu/kvmvapic.bin* - - share/qemu/s390-*.img* - - share/qemu/slof.bin* - - share/qemu/vgabios-*.bin* - - share/qemu/bios-256k.bin* + - lib/*/libusb*so* + - lib/*/libfdt*.so* + - share/qemu/keymaps/* + - share/qemu/bios-256k.bin + - share/qemu/efi-virtio.rom + - share/qemu/kvmvapic.bin + - share/qemu/s390-ccw.img + - share/qemu/s390-netboot.img + - share/qemu/slof.bin + - share/qemu/vgabios-bochs-display.bin + - share/qemu/vgabios-qxl.bin + - share/qemu/vgabios-ramfb.bin + - share/qemu/vgabios-stdvga.bin + - share/qemu/vgabios-virtio.bin qemu-ovmf-secureboot: after: @@ -910,10 +965,22 @@ parts: source: edk2-vars-generator plugin: nil build-packages: - - dosfstools - - mtools - - python3-pexpect - - xorriso + - to amd64: + - dosfstools + - mtools + - python3-pexpect + - xorriso + - to arm64: + - dosfstools + - mtools + - python3-pexpect + - xorriso + override-stage: |- + [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && exit 0 + craftctl default + override-prime: |- + [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && exit 0 + craftctl default override-pull: |- [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && exit 0 craftctl default @@ -943,74 +1010,38 @@ parts: prime: - share/qemu/* - raft: - source: https://github.com/canonical/raft - source-tag: v0.18.0 - source-type: git - source-depth: 1 - plugin: autotools - autotools-configure-parameters: - - --prefix= + squashfs-tools-ng: + plugin: nil stage-packages: - - libuv1 - - liblz4-1 - build-packages: - - libuv1-dev - - liblz4-dev + - squashfs-tools-ng organize: + usr/bin/: bin/ usr/lib/: lib/ - prime: - - lib/libraft*so* - - lib/*/libuv.so* - - sqlite: - source: https://github.com/sqlite/sqlite - source-type: git - source-depth: 1 - source-tag: version-3.44.2 - plugin: autotools - autotools-configure-parameters: - - --prefix= - build-packages: - - tcl - prime: - - bin/sqlite3 - - lib/libsqlite3*so* - - squashfs-tools-ng: - source: https://github.com/AgentD/squashfs-tools-ng - source-type: git - source-tag: v1.2.0 - source-depth: 1 - plugin: autotools - autotools-configure-parameters: - - --prefix= - build-packages: - - liblzma-dev prime: - bin/sqfs2tar - bin/tar2sqfs - - lib/libsquashfs.so* + - lib/*/libsquashfs.so* virtiofsd: - source: https://gitlab.com/virtio-fs/virtiofsd - source-type: git - source-tag: v1.8.0 - source-depth: 1 - plugin: rust - build-packages: - - cargo - - libseccomp-dev - - rustc + plugin: nil + stage-packages: + - to amd64: + - virtiofsd organize: - usr/bin: bin/ + usr/libexec/: bin/ prime: - bin/virtiofsd* + override-stage: |- + [ "$(uname -m)" != "x86_64" ] && exit 0 + craftctl default + override-prime: |- + [ "$(uname -m)" != "x86_64" ] && exit 0 + craftctl default override-pull: |- - [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && [ "$(uname -m)" != "ppc64le" ] && [ "$(uname -m)" != "s390x" ] && exit 0 + [ "$(uname -m)" != "x86_64" ] && exit 0 craftctl default override-build: |- - [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && [ "$(uname -m)" != "ppc64le" ] && [ "$(uname -m)" != "s390x" ] && exit 0 + [ "$(uname -m)" != "x86_64" ] && exit 0 craftctl default xfs: @@ -1028,20 +1059,22 @@ parts: - bin/xfs_repair - bin/mkfs.xfs - lib/*/libinih.so* + - lib/*/liburcu.so* xtables: plugin: nil stage-packages: - arptables - ebtables + - netbase organize: usr/lib/ebtables/: lib/ usr/sbin/: bin/ prime: + #- etc/ethertypes # use ethertypes from the base snap + #- etc/protocols # use protocols from the base snap - bin/arptables-legacy - bin/ebtables-legacy - - etc/ethertypes - - etc/protocols - lib/libebtc.so.* xz: @@ -1062,73 +1095,42 @@ parts: # Include the lzma symlink ln -s xz "${CRAFT_PART_INSTALL}/usr/bin/lzma" - zfs-0-8: + zfs-2-1: source: https://github.com/openzfs/zfs - source-type: git - source-tag: zfs-0.8.6 + source-commit: a7186651d3306debca6b4f72797239eea61db36c # zfs-2.1.16 source-depth: 1 + source-type: git plugin: autotools autotools-configure-parameters: - --prefix=/ - --with-config=user build-packages: - - libblkid-dev - - libssl-dev - - uuid-dev - - zlib1g-dev - override-pull: |- - [ "$(uname -m)" != "x86_64" ] && \ - [ "$(uname -m)" != "aarch64" ] && \ - [ "$(uname -m)" != "s390x" ] && \ - [ "$(uname -m)" != "ppc64le" ] && exit 0 + - to armhf: [] + - else: + - libblkid-dev + - libssl-dev + - uuid-dev + - zlib1g-dev + - libtirpc-dev + override-stage: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 craftctl default - override-build: |- - [ "$(uname -m)" != "x86_64" ] && \ - [ "$(uname -m)" != "aarch64" ] && \ - [ "$(uname -m)" != "s390x" ] && \ - [ "$(uname -m)" != "ppc64le" ] && exit 0 + override-prime: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 craftctl default - set -ex - - ZFS_VER="0.8" - - mv "${CRAFT_PART_INSTALL}" "${CRAFT_PART_INSTALL}.tmp" - mkdir -p "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/bin" "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/lib" - mv "${CRAFT_PART_INSTALL}.tmp/sbin/zfs" "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/bin/" - mv "${CRAFT_PART_INSTALL}.tmp/sbin/zpool" "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/bin/" - mv "${CRAFT_PART_INSTALL}.tmp/lib/udev/zvol_id" "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/bin/" - mv "${CRAFT_PART_INSTALL}.tmp/lib/"*so* "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/lib/" - rm -Rf "${CRAFT_PART_INSTALL}.tmp" - - zfs-2-0: - source: https://github.com/openzfs/zfs - source-type: git - source-tag: zfs-2.0.7 - source-depth: 1 - plugin: autotools - autotools-configure-parameters: - - --prefix=/ - - --with-config=user - build-packages: - - libblkid-dev - - libssl-dev - - uuid-dev - - zlib1g-dev override-pull: |- - [ "$(uname -m)" != "x86_64" ] && \ - [ "$(uname -m)" != "aarch64" ] && \ - [ "$(uname -m)" != "s390x" ] && \ - [ "$(uname -m)" != "ppc64le" ] && exit 0 + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 craftctl default override-build: |- - [ "$(uname -m)" != "x86_64" ] && \ - [ "$(uname -m)" != "aarch64" ] && \ - [ "$(uname -m)" != "s390x" ] && \ - [ "$(uname -m)" != "ppc64le" ] && exit 0 + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 craftctl default set -ex - ZFS_VER="2.0" + ZFS_VER="2.1" mv "${CRAFT_PART_INSTALL}" "${CRAFT_PART_INSTALL}.tmp" mkdir -p "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/bin" "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/lib" @@ -1138,35 +1140,46 @@ parts: mv "${CRAFT_PART_INSTALL}.tmp/lib/"*so* "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/lib/" rm -Rf "${CRAFT_PART_INSTALL}.tmp" - zfs-2-1: + # unused .so + rm "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/lib/libzfsbootenv.so"* + rm "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/lib/libzpool.so"* + + zfs-2-2: source: https://github.com/openzfs/zfs - source-type: git - source-tag: zfs-2.1.14 + source-commit: 3e4a3e161c00273303cd9fa9e0dc09ead3499a8a # zfs-2.2.8 source-depth: 1 + source-type: git plugin: autotools autotools-configure-parameters: - --prefix=/ - --with-config=user build-packages: - - libblkid-dev - - libssl-dev - - uuid-dev - - zlib1g-dev + - to armhf: [] + - else: + - libblkid-dev + - libssl-dev + - uuid-dev + - zlib1g-dev + - libtirpc-dev + override-stage: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + override-prime: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default override-pull: |- - [ "$(uname -m)" != "x86_64" ] && \ - [ "$(uname -m)" != "aarch64" ] && \ - [ "$(uname -m)" != "s390x" ] && \ - [ "$(uname -m)" != "ppc64le" ] && exit 0 + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 craftctl default override-build: |- - [ "$(uname -m)" != "x86_64" ] && \ - [ "$(uname -m)" != "aarch64" ] && \ - [ "$(uname -m)" != "s390x" ] && \ - [ "$(uname -m)" != "ppc64le" ] && exit 0 + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 craftctl default set -ex - ZFS_VER="2.1" + ZFS_VER="2.2" mv "${CRAFT_PART_INSTALL}" "${CRAFT_PART_INSTALL}.tmp" mkdir -p "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/bin" "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/lib" @@ -1176,35 +1189,46 @@ parts: mv "${CRAFT_PART_INSTALL}.tmp/lib/"*so* "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/lib/" rm -Rf "${CRAFT_PART_INSTALL}.tmp" - zfs-2-2: + # unused .so + rm "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/lib/libzfsbootenv.so"* + rm "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/lib/libzpool.so"* + + zfs-2-3: source: https://github.com/openzfs/zfs - source-type: git - source-tag: zfs-2.2.2 + source-commit: 34f96a15c73eab27dd6ad17bb5f1263bf26e37d7 # zfs-2.3.4 source-depth: 1 + source-type: git plugin: autotools autotools-configure-parameters: - --prefix=/ - --with-config=user build-packages: - - libblkid-dev - - libssl-dev - - uuid-dev - - zlib1g-dev + - to armhf: [] + - else: + - libblkid-dev + - libssl-dev + - uuid-dev + - zlib1g-dev + - libtirpc-dev + override-stage: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + override-prime: |- + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default override-pull: |- - [ "$(uname -m)" != "x86_64" ] && \ - [ "$(uname -m)" != "aarch64" ] && \ - [ "$(uname -m)" != "s390x" ] && \ - [ "$(uname -m)" != "ppc64le" ] && exit 0 + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 craftctl default override-build: |- - [ "$(uname -m)" != "x86_64" ] && \ - [ "$(uname -m)" != "aarch64" ] && \ - [ "$(uname -m)" != "s390x" ] && \ - [ "$(uname -m)" != "ppc64le" ] && exit 0 + [ "$(uname -m)" = "armv7l" ] && exit 0 + [ "$(uname -m)" = "riscv64" ] && exit 0 craftctl default set -ex - ZFS_VER="2.2" + ZFS_VER="2.3" mv "${CRAFT_PART_INSTALL}" "${CRAFT_PART_INSTALL}.tmp" mkdir -p "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/bin" "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/lib" @@ -1214,6 +1238,9 @@ parts: mv "${CRAFT_PART_INSTALL}.tmp/lib/"*so* "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/lib/" rm -Rf "${CRAFT_PART_INSTALL}.tmp" + # unused .so + rm "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/lib/libzfsbootenv.so"* + rm "${CRAFT_PART_INSTALL}/zfs-${ZFS_VER}/lib/libzpool.so"* zstd: plugin: nil @@ -1225,39 +1252,53 @@ parts: - bin/pzstd - bin/zstd + apparmor: + plugin: nil + stage-packages: + - apparmor + organize: + sbin/: bin/ + prime: + - bin/apparmor_parser + # Core components lxc: after: - - libseccomp + - apparmor source: https://github.com/lxc/lxc + source-commit: 9e4e69ed1cb93159b0da99dad8d320b795887d07 # v6.0.5 + source-depth: 1 source-type: git - source-tag: lxc-5.0.3 build-packages: - libapparmor-dev - libcap-dev - - libdbus-1-dev - - libgnutls28-dev - - libselinux1-dev + - libseccomp-dev - pkg-config - meson - ninja-build plugin: meson meson-parameters: - - --prefix=/ + - "--buildtype=release" + - -Dapparmor=true + - -Dcapabilities=true + - -Dcommands=false + - -Ddbus=false - -Dexamples=false + - -Dinstall-init-files=false + - -Dinstall-state-dirs=false + - -Dlibdir=lib/${CRAFT_ARCH_TRIPLET_BUILD_FOR} - -Dman=false - - -Dtools=false - - -Dtests=false - -Dmemfd-rexec=false - - -Dapparmor=true - - -Dseccomp=true - - -Dselinux=true - - -Dcapabilities=true + - -Dopenssl=false + - -Dprefix=/ - -Drootfs-mount-path=/var/snap/lxd/common/lxc/ - - -Dlibexecdir=/snap/lxd/current/libexec/ + - -Dseccomp=true + - -Dselinux=false + - -Dspecfile=false + - -Dtests=false + - -Dtools=false organize: snap/lxd/current/lxc: lxc - snap/lxd/current/libexec: libexec share/lxc/hooks: lxc/hooks prime: - bin/lxc-checkconfig @@ -1273,6 +1314,10 @@ parts: git config user.email "noreply@lists.canonical.com" git config user.name "LXD snap builder" + # lxc-checkconfig.in does not need any preprocessing + mkdir -p "${CRAFT_PART_INSTALL}/bin/" + install --mode=0755 src/lxc/cmd/lxc-checkconfig.in "${CRAFT_PART_INSTALL}/bin/lxc-checkconfig" + cd ../build set +ex @@ -1284,11 +1329,11 @@ parts: lxcfs: source: https://github.com/lxc/lxcfs + source-commit: 16503df8e814d29b348e61abebc4f89b2e20f440 # v6.0.5 + source-depth: 1 source-type: git - source-tag: lxcfs-5.0.4 build-packages: - libfuse3-dev - - libpam0g-dev - pkg-config - python3-jinja2 - meson @@ -1334,29 +1379,73 @@ parts: patch -p1 "${CRAFT_PART_INSTALL}/snap/lxd/current/lxcfs/lxc.mount.hook" < "${CRAFT_PROJECT_DIR}/patches/lxcfs-0001-hook.patch" + uefivars: + after: + - spice-server + - qemu-ovmf-secureboot + - nftables + # XXX: cannot use python3-pyuefivars (1.0.0-0ubuntu2) from Noble as the Ubuntu patch breaks it + # the version in Ubuntu 24.10 onward should be OK so let's revisit with core26. + source: https://github.com/awslabs/python-uefivars + source-commit: ec1eab1717c65ea36ca7160c96fe0e10e071fb66 # v1.2 + source-depth: 1 + source-type: git + plugin: python + stage-packages: + - to amd64: + - python3-crc32c + - to arm64: + - python3-crc32c + override-stage: |- + [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && exit 0 + craftctl default + override-prime: |- + [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && exit 0 + craftctl default + override-pull: |- + [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && exit 0 + craftctl default + override-build: |- + [ "$(uname -m)" != "x86_64" ] && [ "$(uname -m)" != "aarch64" ] && exit 0 + + # Apply patches + # XXX: taken from: https://git.launchpad.net/ubuntu/+source/python-uefivars/plain/debian/patches/Revert-Use-google-crc32c-instead-of-crc32c.patch?h=ubuntu/plucky + patch -p1 < "${CRAFT_PROJECT_DIR}/patches/uefivars-Revert-Use-google-crc32c-instead-of-crc32c.patch" + + craftctl default + organize: + lib/python3.12/site-packages/: lib/python3/dist-packages/ + bin/uefivars: bin/uefivars.py + prime: + - bin/uefivars.py + - lib/python3/dist-packages/crc32c* + - lib/python3/dist-packages/pyuefivars* + lxd: source: https://github.com/canonical/lxd + # XXX: We often cherry-pick for candidate builds so don't do shallow clone + #source-depth: 1 + source-commit: 49569b65625b9c53dc5dce885ca2cb1390fd6481 # lxd-6.6 source-type: git - source-tag: lxd-5.20 after: - lxc - dqlite - - sqlite build-packages: - cmake - libacl1-dev - libudev-dev - libxml2-dev - - libxslt-dev + - libxslt1-dev - libblas-dev - libopenblas-dev - liblapack-dev - pkg-config - - pypy-dev + - pypy3-dev - python3-dev + - python3-pip - python3-venv build-snaps: - - go/1.21/stable + - go/1.25/stable stage-packages: - acl - attr @@ -1364,12 +1453,10 @@ parts: - gdisk - iw - lshw - - netbase - - pciutils + - pci.ids - pigz - rsync - - squashfs-tools - - usbutils + - usb.ids - xdelta3 plugin: nil override-pull: | @@ -1377,6 +1464,7 @@ parts: set -ex # Setup build environment + export GOTOOLCHAIN="local" export GOPATH="$(realpath ./.go)" # Setup the GOPATH @@ -1385,7 +1473,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 @@ -1394,23 +1482,12 @@ parts: git config user.email "noreply@lists.canonical.com" git config user.name "LXD snap builder" - git cherry-pick -x d4c975ad30906b96867863538f34f6e2db4e9752 # lxd/apparmor/instance_qemu: only allow QEMU system emulator - git cherry-pick -x ce24649a9164a7eecc4fcc4d9f7ec98bf29b2ec8 # lxd/apparmor/instance_qemu: remove partial duplication of unix rule - git cherry-pick -x ee8a111b2cec7724346054ee7d2d0297ec34bb3e # lxd/instance/qemu: Start using seabios as CSM firmware - git cherry-pick -x 1441e5956285d65a9d79c9d402b761e0813b40aa # lxd/instance/drivers/driver_qemu: force SeaBIOS CSM firmware instead of OVMF - git cherry-pick -x 8f8f17f91e052cefdcd51091dbc258c1aecf3721 # instance/qemu: support extended firmware search algorithm - git cherry-pick -x 7e61b93e5116c2ec3804dbe40afee308fc786320 # instance/qemu: rename ovmf mentions - git cherry-pick -x be489048500718a3a6b96f1a786d4be7568be6cc # instance/qemu: do some sanity checks around enabling security.csm - git cherry-pick -x 62ee9ff4c4baa0412b316f55e1eed9a15d9a79c4 # lxd/instance/drivers/driver_qemu: use bios-256k.bin instead of seabios.bin - git cherry-pick -x 6df2cd00c48834dab78710ccdc448f28b137d1c2 # lxc/move: Only use server-side move when dealing with a single server - git cherry-pick -x be930d736fb58dc8bcf91f1623e7521f273c5dc3 # lxd/sys: handle apparmor unconfined profile mode appropriately - git cherry-pick -x 148876f05843288a8611cf5c1183585866d4ba56 # lxd/apparmor: allow confined services to receive required signals - git cherry-pick -x e6901cde38f6d53fcaae906681582338da6fa899 # lxd/sys: add comment clarifying AppArmor unconfined profile mode - git cherry-pick -x 3681d5e54649fcc2fc9375b6820c1133f140228d # shared/simplestreams/products: Fix regression in parsing version files - git cherry-pick -x 56364f5a97373155d5e6a5a6b10d06d16a25fb3c # shared/simplestreams/simplestreams: Improve error messages - git cherry-pick -x 4ea61558b59ff2e5f14f137a95f81accfc6b98d0 # lxd/auth/tls: Return falsy permission checker when client is restricted + git cherry-pick -x 5761b33780109c4737149e445d5f673f9ac61da7 # lxd/main_callhook: Update symlink creation in applyCDIHooksToContainer + git cherry-pick -x e1b97783c9b231b1eb46382c57a68e4b6e2e3292 # lxd/apparmor: Allow all mounts in unprivileged containers + git cherry-pick -x cf3e6d2d32310094cb0bb560068a24852be5dfaf # lxd/seccomp/seccomp: mknod: continue syscall for whiteouts # Setup build environment + export GOTOOLCHAIN="local" export GOPATH="$(realpath ./.go)" export CGO_CFLAGS="-I${CRAFT_STAGE}/include/ -I${CRAFT_STAGE}/usr/local/include/" export CGO_LDFLAGS="-L${CRAFT_STAGE}/lib/ -L${CRAFT_STAGE}/usr/local/lib/" @@ -1418,31 +1495,64 @@ 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/lxc-to-lxd" github.com/canonical/lxd/lxc-to-lxd - 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-benchmark" github.com/canonical/lxd/lxd-benchmark - 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 + + # Check which Go version was used to compile each of the lxc/lxd binaries + # XXX: fail if an unexpected version (like a Go toolchain) was used + GOVER="$(snap list go | awk '{if ($1 == "go") print $2}')" + UNEXPECTED_GO_VER="$(go version -v "${CRAFT_PART_INSTALL}/bin/lxc"* "${CRAFT_PART_INSTALL}/bin/lxd"* | grep -vF ": go${GOVER}" || true)" + if [ -n "${UNEXPECTED_GO_VER:-}" ]; then + echo "Some binaries were compiled with an unexpected Go version (!= ${GOVER}):" + echo "${UNEXPECTED_GO_VER}" + exit 1 + fi - if [ "$(uname -m)" != "riscv64" ]; then + # Some python dependencies are not available for armhf/riscv64 or just require a build from source. + # Not worth the effort for now. + if [ "$(uname -m)" != "armv7l" ] && [ "$(uname -m)" != "riscv64" ]; then # Build the static website make doc + # Remove unneeded bits + rm doc/_build/objects.inv # only objects.inv.txt is used + # not needed once built + rm doc/_build/.buildinfo + rm -rf doc/_build/_sphinx_design_static/ + # Copy the static website - mkdir -p "${CRAFT_STAGE}/share/lxd-documentation" - cp -a doc/html/. "${CRAFT_STAGE}/share/lxd-documentation/" + 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/commands/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}/lxc-completer.sh" + chmod +x "${CRAFT_PART_INSTALL}/lxc-completer.sh" 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/sgdisk: bin/ prime: - bin/dnsmasq - bin/getfattr @@ -1456,58 +1566,30 @@ parts: - lib/*/libidn.so.* - - etc/bash_completion.d/snap.lxd.lxc + - lxc-completer.sh - - share/misc + - share/lxd-documentation* + - share/misc/pci.ids + - share/misc/usb.ids - bin/lxc - - bin/lxc-to-lxd - - bin/lxd - bin/lxd-agent - - bin/lxd-benchmark - bin/lxd-user - - lxd-migrate: - source: lxd-migrate/ - after: - - lxd - - sqlite - build-snaps: - - go/1.21/stable - plugin: nil - override-pull: | - craftctl default - set -ex - - # Setup build environment - export GOPATH="$(realpath ./.go)" - - # Download the dependencies - go get -d -v ./... - override-build: | - set -ex - - # Setup build environment - export GOPATH="$(realpath ./.go)" - export CGO_CFLAGS="-I${CRAFT_STAGE}/include/ -I${CRAFT_STAGE}/usr/local/include/" - export CGO_LDFLAGS="-L${CRAFT_STAGE}/lib/ -L${CRAFT_STAGE}/usr/local/lib/" - - # Build the binaries - go build -trimpath -o "${CRAFT_PART_INSTALL}/bin/lxd-migrate" -tags=libsqlite3 ./ - - mkdir -p "${CRAFT_PART_INSTALL}/bin/" - prime: - - bin/lxd-migrate + - sbin/lxd lxd-ui: source: https://github.com/canonical/lxd-ui + source-depth: 1 source-type: git - source-tag: 0.5 + source-commit: 69fa2699fe6a91754cc825bdca27d64bc6e39b2e # 0.19 plugin: nil - override-pull: | + override-prime: |- + [ "$(uname -m)" = "riscv64" ] && exit 0 + craftctl default + override-pull: |- [ "$(uname -m)" = "riscv64" ] && exit 0 - snap install node --channel=20/stable --classic || true + snap install node --channel=22/stable --classic craftctl default override-build: | [ "$(uname -m)" = "riscv64" ] && exit 0 @@ -1529,36 +1611,27 @@ parts: prime: - bin/setup-shmounts - snap-query: - source: snap-query/ - build-snaps: - - go/1.21/stable - plugin: nil - override-build: | - set -ex - - # Setup build environment - export GOPATH="$(realpath ./.go)" - - # Build the binaries - go build -trimpath -o "${CRAFT_PART_INSTALL}/bin/snap-query" snap-query.go - prime: - - bin/snap-query + gpu-2404: + after: + - lxd + - qemu + source: https://github.com/canonical/gpu-snap.git + plugin: dump + override-prime: | + ${CRAFT_PART_SRC}/bin/gpu-2404-cleanup mesa-2404 nvidia-2404 strip: after: - btrfs - ceph - dqlite - - libseccomp - logrotate - lvm - - nano - nvidia-container - openvswitch - ovn - - raft - - sqlite + - qemu-ovmf-secureboot + - spice-server - squashfs-tools-ng - swtpm - virtiofsd @@ -1566,39 +1639,47 @@ parts: - xz - wrappers - xtables - - zfs-0-8 - - zfs-2-0 - zfs-2-1 - zfs-2-2 + - zfs-2-3 - zstd - lxc - lxcfs - - criu - lxd - - lxd-migrate - shmounts - - snap-query + - nvidia-container-toolkit plugin: nil override-prime: | set -x # XXX: remove unneeded files/directories - rm -rf "${CRAFT_PRIME}/lib/python3/dist-packages/*.egg-info/" rm -rf "${CRAFT_PRIME}/lib/systemd/" rm -rf "${CRAFT_PRIME}/lib/udev/" rm -rf "${CRAFT_PRIME}/usr/local/" rm -rf "${CRAFT_PRIME}/usr/share/" - # Strip binaries (excluding shell scripts) + # 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" \ -not -path "${CRAFT_PRIME}/bin/sshfs" \ + -not -path "${CRAFT_PRIME}/bin/virt-v2v-in-place" \ -not -path "${CRAFT_PRIME}/bin/xfs_admin" \ - -exec strip -s {} + + -not -path "${CRAFT_PRIME}/bin/uefivars.py" \ + -not -path "${CRAFT_PRIME}/bin/lxcfs" \ + -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 # Strip all versions of zfs utils for v in "${CRAFT_PRIME}"/zfs-*; do @@ -1606,17 +1687,14 @@ parts: find "${v}/" -type f -exec strip -s {} + done - # Strip libraries (excluding python3 scripts) + # Strip libraries (excluding python3 scripts and liblxcfs) find "${CRAFT_PRIME}"/lib -type f \ -not -path "${CRAFT_PRIME}/lib/python3/*" \ + -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 # XXX: look for broken symlinks indicating missing/invalid prime broken_symlinks="$(find "${CRAFT_PRIME}/" -xtype l \ @@ -1627,13 +1705,26 @@ parts: exit 1 fi + # Fixup logrotate.conf permissions to not be group writable + chmod g-w "${CRAFT_PRIME}/etc/logrotate.conf" + + # XXX: do not keep the duplicated and often outdated CA certificates + # store from Python `certifi`. This file is not even used as the + # `python3-certifi` package providing it is patched to always use: + # `/etc/ssl/certs/ca-certificates.crt` + truncate --no-create --size=0 "${CRAFT_PRIME}/lib/python3/dist-packages/certifi/cacert.pem" + exit 0 wrappers: plugin: dump source: snapcraft/ organize: + commands/snap-query: bin/ hooks/: snap/hooks/ + wrappers/lxd-stophook: bin/lxd + wrappers/gpu-2404-custom-wrapper: bin/ wrappers/editor: bin/ wrappers/remote-viewer: bin/ wrappers/sshfs: bin/ + wrappers/virt-v2v-in-place: bin/ diff --git a/snapcraft/commands/buginfo b/snapcraft/commands/buginfo index 5ca78a2f3..71b706f44 100755 --- a/snapcraft/commands/buginfo +++ b/snapcraft/commands/buginfo @@ -31,12 +31,11 @@ fi echo " - Kernel version: $(uname -a)" echo " - LXC version: $(lxc --version)" echo " - LXD version: $(lxd --version)" -echo " - Snap revision: ${SNAP_REVISION}" echo "" echo "# Detailed snap information" echo '```' -nsenter -t 1 -m snap info lxd +nsenter -t 1 -m snap list --all lxd core20 core22 core24 snapd echo '```' echo "" @@ -116,5 +115,5 @@ echo "" echo "# Systemd log (last 50 lines)" echo '```' -nsenter -t 1 -m journalctl -u snap.lxd.daemon -n50 | cat +nsenter -t 1 -m journalctl --no-pager -u snap.lxd.daemon -n50 echo '```' diff --git a/snapcraft/commands/daemon.activate b/snapcraft/commands/daemon.activate index d13795fe1..a979e7742 100755 --- a/snapcraft/commands/daemon.activate +++ b/snapcraft/commands/daemon.activate @@ -18,8 +18,10 @@ fi # shellcheck disable=SC2155 export SNAP_CURRENT="$(realpath "${SNAP}/..")/current" -# shellcheck disable=SC2155 -export ARCH="$(basename "$(readlink -f "${SNAP_CURRENT}"/lib/*-linux-gnu*/)")" +# Turn `/snap/lxd/28637/lib/x86_64-linux-gnu` into `x86_64-linux-gnu` +# Similar to `basename` but using variable substitution instead of external executable +LIB_ARCH="$(readlink -f "${SNAP_CURRENT}"/lib/*-linux-gnu*/)" +export ARCH="${LIB_ARCH##*/}" 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" @@ -52,23 +54,12 @@ if ! nsenter -t 1 -m systemctl is-active -q snap."${SNAP_INSTANCE_NAME}".daemon. fi # Start LXD if running as an appliance -SNAP_MODEL="$(nsenter -t 1 -m snap model --assertion | grep "^model: " | cut -d' ' -f2)" -if echo "${SNAP_MODEL}" | grep -q "^lxd-core"; then +if nsenter -t 1 -m snap model --assertion | grep -q "^model: lxd-core"; then echo "==> LXD appliance detected, starting LXD" nsenter -t 1 -m systemctl start snap."${SNAP_INSTANCE_NAME}".daemon --no-block exit 0 fi -# Setup the "lxd" user -if ! getent passwd lxd >/dev/null 2>&1; then - echo "==> Creating \"lxd\" user" - if grep -q "^passwd.*extrausers" /var/lib/snapd/hostfs/etc/nsswitch.conf; then - nsenter -t 1 -m useradd --system -M -N --home "${SNAP_COMMON}/lxd" --shell /bin/false --extrausers lxd || true - else - nsenter -t 1 -m useradd --system -M -N --home "${SNAP_COMMON}/lxd" --shell /bin/false lxd || true - fi -fi - # Setup the "lxd" group if [ "${daemon_group}" = "lxd" ] && ! getent group lxd >/dev/null 2>&1; then echo "==> Creating \"lxd\" group" @@ -79,6 +70,16 @@ if [ "${daemon_group}" = "lxd" ] && ! getent group lxd >/dev/null 2>&1; then fi fi +# Setup the "lxd" user +if ! getent passwd lxd >/dev/null 2>&1; then + echo "==> Creating \"lxd\" user" + if grep -q "^passwd.*extrausers" /var/lib/snapd/hostfs/etc/nsswitch.conf; then + nsenter -t 1 -m useradd --system -M -N --home "${SNAP_COMMON}/lxd" --shell /bin/false --gid lxd --extrausers lxd || true + else + nsenter -t 1 -m useradd --system -M -N --home "${SNAP_COMMON}/lxd" --shell /bin/false --gid lxd lxd || true + fi +fi + # Set socket ownership if getent group "${daemon_group}" >/dev/null 2>&1; then if [ -e "${SNAP_COMMON}/lxd/unix.socket" ]; then @@ -95,7 +96,7 @@ if getent group "${daemon_user_group}" >/dev/null 2>&1; then fi # Check if LXD ever started -if [ ! -e "${SNAP_COMMON}/lxd/database" ]; then +if [ ! -d "${SNAP_COMMON}/lxd/database" ]; then echo "==> LXD never started on this system, no need to start it now" exit 0 fi diff --git a/snapcraft/commands/daemon.reload b/snapcraft/commands/daemon.reload index c06ac4cc5..eb28795df 100755 --- a/snapcraft/commands/daemon.reload +++ b/snapcraft/commands/daemon.reload @@ -10,5 +10,5 @@ if [ -d /sys/kernel/security/apparmor ]; then fi echo reload > "${SNAP_COMMON}/state" -PID=$(cat "${SNAP_COMMON}/lxd.pid") -/bin/kill "$PID" +read -r PID < "${SNAP_COMMON}/lxd.pid" +exec kill "$PID" diff --git a/snapcraft/commands/daemon.start b/snapcraft/commands/daemon.start index 44e96c853..0ba8a390c 100755 --- a/snapcraft/commands/daemon.start +++ b/snapcraft/commands/daemon.start @@ -14,25 +14,40 @@ echo "=> Preparing the system (${SNAP_REVISION})" # shellcheck disable=SC2155 export SNAP_CURRENT="$(realpath "${SNAP}/..")/current" -# shellcheck disable=SC2155 -export ARCH="$(basename "$(readlink -f "${SNAP_CURRENT}"/lib/*-linux-gnu*/)")" +# Turn `/snap/lxd/28637/lib/x86_64-linux-gnu` into `x86_64-linux-gnu` +# Similar to `basename` but using variable substitution instead of external executable +LIB_ARCH="$(readlink -f "${SNAP_CURRENT}"/lib/*-linux-gnu*/)" +export ARCH="${LIB_ARCH##*/}" 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 LD_LIBRARY_PATH="${LD_LIBRARY_PATH:-}:${SNAP_CURRENT}/lib:${SNAP_CURRENT}/lib/${ARCH}:${SNAP_CURRENT}/lib/${ARCH}/ceph" +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:${SNAP_CURRENT}/lib/${ARCH}/swtpm" export PATH="${PATH}:${SNAP_CURRENT}/bin" export LXD_CLUSTER_UPDATE="${SNAP_CURRENT}/commands/refresh" -export LXD_OVMF_PATH="${SNAP_CURRENT}/share/qemu" +export LXD_QEMU_FW_PATH="${SNAP_CURRENT}/share/qemu" export PYTHONPATH=/snap/lxd/current/lib/python3/dist-packages/ -# Detect model -SNAP_MODEL="$(nsenter -t 1 -m snap model --assertion | sed -n 's/^model: \(.\+\)/\1/p')" +# Detect LXD appliance +LXD_APPLIANCE="false" +if nsenter -t 1 -m snap model --assertion | grep -q "^model: lxd-core"; then + LXD_APPLIANCE="true" +fi + +# Detect base name +SNAP_BASE="$(sed -n '/^name:/ s/^name:\s*\(core[0-9]\{2\}\)/\1/p' /meta/snap.yaml)" + +# Temporary hack to workaround systemctl reload snap.lxd.daemon +# problem with core24-based LXD snap +_LXD_SNAP_DEVCGROUP_CONFIG="/var/lib/snapd/hostfs/var/lib/snapd/cgroup/snap.lxd.device" +if [ "${SNAP_BASE}" = "core24" ] && [ -e "${_LXD_SNAP_DEVCGROUP_CONFIG}" ]; then + grep -qxF 'self-managed=true' "${_LXD_SNAP_DEVCGROUP_CONFIG}" || echo 'self-managed=true' >> "${_LXD_SNAP_DEVCGROUP_CONFIG}" +fi # Wait for appliance configuration -if echo "${SNAP_MODEL}" | grep -q "^lxd-core"; then +if [ "${LXD_APPLIANCE}" = "true" ]; then while :; do [ "$(nsenter -t 1 -m snap managed)" = "true" ] && break sleep 5 @@ -42,6 +57,15 @@ fi # Workaround for systemd nuking our cgroups on refreshes nsenter -t 1 -m systemd-run -u snap."${SNAP_INSTANCE_NAME}".workaround -p Delegate=yes -r /bin/true >/dev/null 2>&1 || true +# Workaround to ensure LXD is stopped before MicroCeph/MicroOVN +SYSTEMD_OVERRIDE_DIR="/var/lib/snapd/hostfs/run/systemd/system/snap.lxd.daemon.service.d" +if [ ! -e "${SYSTEMD_OVERRIDE_DIR}/lxd-shutdown.conf" ]; then + mkdir -p "${SYSTEMD_OVERRIDE_DIR}" + echo "[Unit] +After=snap.microceph.daemon.service snap.microovn.daemon.service" > "${SYSTEMD_OVERRIDE_DIR}/lxd-shutdown.conf" + nsenter -t 1 -m systemctl daemon-reload +fi + # Cleanup last state true > "${SNAP_COMMON}/state" @@ -55,6 +79,8 @@ echo "==> Loading snap configuration" # shellcheck disable=SC1091 . "${SNAP_COMMON}/config" +daemon_group="${daemon_group:-"lxd"}" + # Create the main directory if [ ! -d "${SNAP_COMMON}/lxd" ]; then echo "==> Creating ${SNAP_COMMON}/lxd" @@ -81,16 +107,9 @@ if [ ! -e "${SNAP_COMMON}/mntns" ] || [ -L "${SNAP_COMMON}/mntns" ]; then ln -s /proc/$$/root "${SNAP_COMMON}/mntns" fi -# Fix /dev/pts -if [ "$(grep -F "devpts /dev/pts " /proc/self/mountinfo)" = "2" ]; then - echo "==> Setting up /dev/pts" - umount -l /dev/ptmx - umount -l /dev/pts -fi - # Setup rshared propagation on mount holding paths for path in "${SNAP_COMMON}/lxd/storage-pools" "${SNAP_COMMON}/lxd/devices"; do - if ! cut -d' ' -f5 /proc/self/mountinfo | grep -qF "${path}"; then + if ! cut -d' ' -f5 /proc/self/mountinfo | grep -qxF "${path}"; then echo "==> Setting up mount propagation on ${path}" if [ ! -e "${path}" ]; then mkdir -p "${path}" @@ -136,7 +155,8 @@ fi # Fix lsmod/modprobe echo "==> Setting up kmod wrapper" -mountpoint -q /bin/kmod || mount -o ro,bind "${SNAP}/wrappers/kmod" "/bin/kmod" +mountpoint -q /bin/kmod && umount -l /bin/kmod +mount -o ro,bind "${SNAP}/wrappers/kmod" "/bin/kmod" # Setup /boot if [ -e /var/lib/snapd/hostfs/boot ]; then @@ -150,9 +170,9 @@ echo "==> Preparing a clean copy of /run" if [ -e "/run/.lxd_generated" ]; then umount -l /run fi -mount -t tmpfs tmpfs /run -o mode=0755,nosuid,nodev +mount -t tmpfs tmpfs /run -o mode=0755,nosuid,nodev,size=4M touch /run/.lxd_generated -for entry in NetworkManager resolvconf netconfig snapd snapd.socket snapd-snap.socket systemd udev user; do +for entry in NetworkManager resolvconf netconfig snapd snapd.socket snapd-snap.socket sysctl.d systemd udev user; do [ -e "/var/lib/snapd/hostfs/run/${entry}" ] || [ -L "/var/lib/snapd/hostfs/run/${entry}" ] || continue ln -s "/var/lib/snapd/hostfs/run/${entry}" "/run/${entry}" done @@ -162,6 +182,13 @@ echo "==> Preparing /run/bin" mkdir -p "/run/bin" export PATH="/run/bin:${PATH}" +if [ -e "${SNAP_COMMON}/use-qemu-external-snap" ]; then + echo "==> Setting up external QEMU snap integration" + export SNAP_QEMU_PREFIX="external/qemu" + LD_LPATH_PIPEWIRE="$(readlink -f "${SNAP_CURRENT}"/${SNAP_QEMU_PREFIX}/lib/"${ARCH}"/pipewire-*/)" + export LD_LIBRARY_PATH="${SNAP_CURRENT}/${SNAP_QEMU_PREFIX}/lib/${ARCH}:${SNAP_CURRENT}/${SNAP_QEMU_PREFIX}/lib/${ARCH}/pulseaudio:${SNAP_CURRENT}/${SNAP_QEMU_PREFIX}/lib/${ARCH}/ceph:${LD_LPATH_PIPEWIRE:+${LD_LPATH_PIPEWIRE}:}${LD_LIBRARY_PATH}" +fi + if [ "${ceph_external:-"false"}" = "true" ]; then ln -s "${SNAP}/wrappers/run-host" "/run/bin/ceph" ln -s "${SNAP}/wrappers/run-host" "/run/bin/radosgw-admin" @@ -193,6 +220,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!" @@ -202,6 +235,18 @@ fi # Redirect getent to the host ln -s "${SNAP}/wrappers/run-host" "/run/bin/getent" +# Redirect journalctl to the host +ln -s "${SNAP}/wrappers/run-host" "/run/bin/journalctl" + +# Redirect pro to the host +ln -s "${SNAP}/wrappers/run-host" "/run/bin/pro" + +# Redirect iscsiadm to the host. +ln -s "${SNAP}/wrappers/run-host" "/run/bin/iscsiadm" + +# Redirect multipath to the host. +ln -s "${SNAP}/wrappers/run-host" "/run/bin/multipath" + # Avoid xtables talking to nft ln -s "${SNAP}/bin/arptables-legacy" "/run/bin/arptables" ln -s "${SNAP}/bin/ebtables-legacy" "/run/bin/ebtables" @@ -215,7 +260,7 @@ echo "==> Preparing a clean copy of /etc" if [ -e "/etc/.lxd_generated" ]; then umount -l /etc fi -mount -t tmpfs tmpfs /etc -o mode=0755 +mount -t tmpfs tmpfs /etc -o mode=0755,nosuid,nodev,size=4M touch /etc/.lxd_generated ## Generate a new ld.so.cache @@ -227,14 +272,9 @@ for entry in hostid hostname hosts nsswitch.conf os-release passwd group localti ln -s "/var/lib/snapd/hostfs/etc/${entry}" "/etc/${entry}" done -## And the bits we need from the core snap -for entry in alternatives apparmor apparmor.d; do - ln -s "/snap/core22/current/etc/${entry}" "/etc/${entry}" -done - -## And those we directly ship in the snap -for entry in ethertypes protocols; do - ln -s "${SNAP}/etc/${entry}" "/etc/${entry}" +## And the bits we need from the base/core snap +for entry in alternatives apparmor apparmor.d ethertypes protocols; do + ln -s "/snap/${SNAP_BASE}/current/etc/${entry}" "/etc/${entry}" done ## Setup mtab @@ -245,7 +285,7 @@ if [ -e "/var/lib/snapd/hostfs/etc/ssl" ] && [ -e "/var/lib/snapd/hostfs/usr/sha ln -s "/var/lib/snapd/hostfs/etc/ssl" "/etc/ssl" mountpoint -q "/usr/share/ca-certificates" || mount -o ro,bind "/var/lib/snapd/hostfs/usr/share/ca-certificates" "/usr/share/ca-certificates" else - ln -s "/snap/core22/current/etc/ssl" "/etc/ssl" + ln -s "/snap/${SNAP_BASE}/current/etc/ssl" "/etc/ssl" fi ## Try to handle special /etc/resolv.conf setups @@ -261,7 +301,7 @@ echo "==> Preparing a clean copy of /usr/share/misc" if [ -e "/usr/share/misc/.lxd_generated" ]; then umount -l /usr/share/misc fi -mount -t tmpfs tmpfs /usr/share/misc -o mode=0755 +mount -t tmpfs tmpfs /usr/share/misc -o mode=0755,nosuid,nodev,size=4M touch /usr/share/misc/.lxd_generated ln -s "${SNAP_CURRENT}/share/misc/pci.ids" /usr/share/misc/ ln -s "${SNAP_CURRENT}/share/misc/usb.ids" /usr/share/misc/ @@ -273,23 +313,23 @@ for entry in dev proc sys; do mount -o bind "/${entry}" "/var/lib/snapd/hostfs/${entry}" done -# FIXME: Setup the "lxd" user -if ! getent passwd lxd >/dev/null 2>&1; then - echo "==> Creating \"lxd\" user" - if grep -q "^passwd.*extrausers" /etc/nsswitch.conf; then - nsenter -t 1 -m useradd --system -M -N --home /var/snap/lxd/common/lxd --shell /bin/false --extrausers lxd || true +# Setup the "lxd" group +if [ "${daemon_group}" = "lxd" ] && ! getent group lxd >/dev/null 2>&1; then + echo "==> Creating \"lxd\" group" + if grep -q "^group.*extrausers" /var/lib/snapd/hostfs/etc/nsswitch.conf; then + nsenter -t 1 -m groupadd --system --extrausers lxd || true else - nsenter -t 1 -m useradd --system -M -N --home /var/snap/lxd/common/lxd --shell /bin/false lxd || true + nsenter -t 1 -m groupadd --system lxd || true fi fi -# FIXME: Setup the "lxd" group -if [ "${daemon_group:-"lxd"}" = "lxd" ] && ! getent group lxd >/dev/null 2>&1; then - echo "==> Creating \"lxd\" group" - if grep -q "^group.*extrausers" /etc/nsswitch.conf; then - nsenter -t 1 -m groupadd --system --extrausers lxd || true +# Setup the "lxd" user +if ! getent passwd lxd >/dev/null 2>&1; then + echo "==> Creating \"lxd\" user" + if grep -q "^passwd.*extrausers" /var/lib/snapd/hostfs/etc/nsswitch.conf; then + nsenter -t 1 -m useradd --system -M -N --home "${SNAP_COMMON}/lxd" --shell /bin/false --gid lxd --extrausers lxd || true else - nsenter -t 1 -m groupadd --system lxd || true + nsenter -t 1 -m useradd --system -M -N --home "${SNAP_COMMON}/lxd" --shell /bin/false --gid lxd lxd || true fi fi @@ -305,28 +345,50 @@ 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" if [ "${ovn_builtin:-"false"}" = "true" ]; then + echo "=> Using builtin OVN" mkdir -p "${SNAP_COMMON}/ovn" ln -s "${SNAP_COMMON}/ovn" /etc/ovn +elif [ -d "${SNAP_DATA}/microovn/certificates/pki" ]; then + echo "==> Cleaning up OVN configuration" + if [ -L /etc/ovn ]; then + echo "=> Removing /etc/ovn symlink" + rm -f /etc/ovn + elif [ -d /etc/ovn ]; then + echo "=> Removing /etc/ovn directory" + rm -rf /etc/ovn + fi + + echo "=> Detected MicroOVN Content Interface" + mkdir -p /etc/ovn + ln -s "${SNAP_DATA}/microovn/certificates/pki/client-cert.pem" /etc/ovn/cert_host + ln -s "${SNAP_DATA}/microovn/certificates/pki/client-privkey.pem" /etc/ovn/key_host + ln -s "${SNAP_DATA}/microovn/certificates/pki/cacert.pem" /etc/ovn/ovn-central.crt elif [ -d /var/snap/microovn/ ]; then + echo "==> Cleaning up OVN configuration" + if [ -L /etc/ovn ]; then + echo "=> Removing /etc/ovn symlink" + rm -f /etc/ovn + elif [ -d /etc/ovn ]; then + echo "=> Removing /etc/ovn directory" + rm -rf /etc/ovn + fi + echo "=> Detected MicroOVN" - mkdir /etc/ovn + mkdir -p /etc/ovn ln -s /var/snap/microovn/common/data/pki/client-cert.pem /etc/ovn/cert_host ln -s /var/snap/microovn/common/data/pki/client-privkey.pem /etc/ovn/key_host ln -s /var/snap/microovn/common/data/pki/cacert.pem /etc/ovn/ovn-central.crt @@ -339,28 +401,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 +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 -d. -f1-2)" + + 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 - VERSION=$(nsenter -t 1 -m modinfo -F version zfs 2>/dev/null || true) -fi - -if echo "${VERSION}" | grep -q ^2\.2; then - echo "==> Setting up ZFS (2.2)" - export LD_LIBRARY_PATH="${SNAP_CURRENT}/zfs-2.2/lib/:${LD_LIBRARY_PATH}" - export PATH="${SNAP_CURRENT}/zfs-2.2/bin:${PATH}" -elif echo "${VERSION}" | grep -q ^2\.1; then - echo "==> Setting up ZFS (2.1)" - export LD_LIBRARY_PATH="${SNAP_CURRENT}/zfs-2.1/lib/:${LD_LIBRARY_PATH}" - export PATH="${SNAP_CURRENT}/zfs-2.1/bin:${PATH}" -elif echo "${VERSION}" | grep -q ^2\.0; then - echo "==> Setting up ZFS (2.0)" - export LD_LIBRARY_PATH="${SNAP_CURRENT}/zfs-2.0/lib/:${LD_LIBRARY_PATH}" - export PATH="${SNAP_CURRENT}/zfs-2.0/bin:${PATH}" -elif echo "${VERSION}" | grep -q ^0\.8; then - echo "==> Setting up ZFS (0.8)" - export LD_LIBRARY_PATH="${SNAP_CURRENT}/zfs-0.8/lib/:${LD_LIBRARY_PATH}" - export PATH="${SNAP_CURRENT}/zfs-0.8/bin:${PATH}" + echo "==> Using ZFS tools from the host system" fi # Escape resource limits @@ -392,6 +454,58 @@ else fi fi +manage_apparmor_restrictions() { + # sysctl override snippet + SYSCTL_FILE="/var/lib/snapd/hostfs/run/sysctl.d/zz-lxd.conf" + + # Nothing to do if Apparmor is NOT active + [ -d /sys/kernel/security/apparmor ] || return 0 + + # Check if sysctl settings need to be altered and always write the override snippet + if [ "${apparmor_unprivileged_restrictions_disable:-"true"}" = "true" ]; then + KEY_USERNS="kernel.apparmor_restrict_unprivileged_userns" + KEY_UNCONFINED="kernel.apparmor_restrict_unprivileged_unconfined" + mkdir -p /var/lib/snapd/hostfs/run/sysctl.d + tmpf="$(mktemp "${SYSCTL_FILE}".XXXXXX)" + + # userns restriction + if [ "$(sysctl -n -e "${KEY_USERNS}")" = "1" ]; then + echo "==> Disabling Apparmor unprivileged userns mediation" + sysctl -w -e "${KEY_USERNS}=0" + fi + # the "-" prefix avoids any failure or warning if the key is not supported + echo "-${KEY_USERNS} = 0" >> "${tmpf}" + + # unconfined restriction + if [ "$(sysctl -n -e "${KEY_UNCONFINED}")" = "1" ]; then + echo "==> Disabling Apparmor unprivileged unconfined mediation" + sysctl -w -e "${KEY_UNCONFINED}=0" + fi + # the "-" prefix avoids any failure or warning if the key is not supported + echo "-${KEY_UNCONFINED} = 0" >> "${tmpf}" + + # Save the overrides in a snippet file if content differs or any file is missing + if ! cmp --quiet "${tmpf}" "${SYSCTL_FILE}"; then + chmod a+r "${tmpf}" + mv "${tmpf}" "${SYSCTL_FILE}" + else + rm "${tmpf}" + fi + + # Done + return 0 + fi + + # Check if an old override snippet needs to be unapplied + [ -f "${SYSCTL_FILE}" ] || return 0 + + echo "==> Restoring Apparmor unprivileged userns and unconfined mediations" + + # Remove the old override snippet before applying system rules + rm "${SYSCTL_FILE}" + nsenter -t 1 -m systemctl restart systemd-sysctl.service || true +} + # Update system limits if [ "$(stat -c '%u' /proc)" = 0 ]; then ## prlimits @@ -407,6 +521,13 @@ if [ "$(stat -c '%u' /proc)" = 0 ]; then fi fi + if [ -e /proc/sys/fs/inotify/max_user_watches ]; then + if [ "$(cat /proc/sys/fs/inotify/max_user_watches)" -lt "1048576" ]; then + echo "==> Increasing the number of inotify user watches" + echo 1048576 > /proc/sys/fs/inotify/max_user_watches || true + fi + fi + if [ -e /proc/sys/kernel/keys/maxkeys ]; then if [ "$(cat /proc/sys/kernel/keys/maxkeys)" -lt "2000" ]; then echo "==> Increasing the number of keys for a nonroot user" @@ -427,12 +548,8 @@ if [ "$(stat -c '%u' /proc)" = 0 ]; then echo 1 > /proc/sys/kernel/unprivileged_userns_clone || true fi fi -fi -# Setup CRIU -if [ "${criu_enable:-"false"}" = "true" ]; then - echo "==> Enabling CRIU" - export PATH="${SNAP_CURRENT}/criu:${PATH}" + manage_apparmor_restrictions fi # Setup UI @@ -448,7 +565,6 @@ export LXD_DOCUMENTATION="${SNAP_CURRENT}/share/lxd-documentation" # LXC ## Host specific overrides mkdir -p "${SNAP_COMMON}/lxc" -touch "${SNAP_COMMON}/lxc/local.conf" if [ -d /sys/kernel/security/apparmor ] && ! grep -qF -- "-Ubuntu" /proc/version; then echo "==> Detected kernel with partial AppArmor support" echo "lxc.apparmor.allow_incomplete = 1" > "${SNAP_COMMON}/lxc/local.conf" @@ -470,6 +586,11 @@ if [ "${openvswitch_builtin:-"false"}" = "true" ]; then export OVS_SBINDIR="${SNAP}/bin/" mkdir -p "${OVS_SYSCONFDIR}/openvswitch" + OVS_SYSTEM_ID_FILE="${OVS_SYSCONFDIR}/openvswitch/system-id.conf" + if ! [ -s "${OVS_SYSTEM_ID_FILE}" ]; then + systemd-id128 new --uuid > "${OVS_SYSTEM_ID_FILE}" + fi + ( # Close socket activation fd exec 3<&- || true @@ -477,6 +598,8 @@ if [ "${openvswitch_builtin:-"false"}" = "true" ]; then "${SNAP}/share/openvswitch/scripts/ovs-ctl" start --system-id=random ) ) +elif [ -d "${SNAP_DATA}/microovn/chassis/switch" ]; then + ln -s "${SNAP_DATA}/microovn/chassis/switch" /run/openvswitch elif [ -d /var/snap/microovn/ ]; then ln -s /var/snap/microovn/common/run/switch /run/openvswitch else @@ -492,7 +615,7 @@ if [ -e "${SNAP_COMMON}/var/lib/lxcfs/cgroup" ]; then CURRENT_FUSE="${NEW_FUSE}" ## Get the name of the base (core2X) used by the new snap - NEW_BASE="$(grep ^name /meta/snap.yaml)" + NEW_BASE="${SNAP_BASE}" CURRENT_BASE="${NEW_BASE}" ## Use the old lxcfs instance to get the libfuse soname and old base it uses @@ -500,7 +623,7 @@ if [ -e "${SNAP_COMMON}/var/lib/lxcfs/cgroup" ]; then read -r CURRENT_PID < "${SNAP_COMMON}/lxcfs.pid" if [ -e "/proc/${CURRENT_PID}" ]; then CURRENT_FUSE="$(ldd "/proc/${CURRENT_PID}/exe" | sed -n "/libfuse3\?\.so/ s/.*libfuse3\?\.so\.\([^ ]\+\) .*/\1/p")" - CURRENT_BASE="$(grep ^name "/proc/${CURRENT_PID}/root/meta/snap.yaml")" + CURRENT_BASE="$(sed -n '/^name:/ s/^name:\s*\(core[0-9]\{2\}\)/\1/p' "/proc/${CURRENT_PID}/root/meta/snap.yaml")" fi fi @@ -535,7 +658,7 @@ else export LD_LIBRARY_PATH="${SNAP_CURRENT}/lib:${SNAP_CURRENT}/lib/${ARCH}" lxcfs_args= [ "${lxcfs_loadavg:-"false"}" = "true" ] && lxcfs_args="${lxcfs_args} --enable-loadavg" - [ "${lxcfs_pidfd:-"false"}" = "true" ] && lxcfs_args="${lxcfs_args} --enable-pidfd" + [ "${lxcfs_pidfd:-"true"}" = "true" ] && lxcfs_args="${lxcfs_args} --enable-pidfd" [ "${lxcfs_cfs:-"false"}" = "true" ] && lxcfs_args="${lxcfs_args} --enable-cfs" [ "${lxcfs_debug:-"false"}" = "true" ] && lxcfs_args="${lxcfs_args} -d" @@ -574,16 +697,23 @@ fi # LXD ## Check for existing LXDs -for pid in $(pgrep -f "lxd --logfile" ; pgrep -f "lxd.debug --logfile"); do - grep -qF "SNAP_NAME=lxd" "/proc/${pid}/environ" || continue - - rm -f "/var/snap/lxd/common/lxd/.validate" - touch "/proc/${pid}/root/var/snap/lxd/common/lxd/.validate" 2>/dev/null || true - if [ -e "/var/snap/lxd/common/lxd/.validate" ]; then +for pid in $(pgrep --euid 0 --full "lxd(\.debug)? --logfile"); do + # Cheap confirmation that we likely have a LXD PID + grep -q --line-regexp --fixed-strings --max-count=1 "SNAP_NAME=lxd" "/proc/${pid}/environ" || continue + + # Confirm the PID found by pgrep is indeed ours and not one from + # a nested instance also running LXD or a recycled PID. By writing + # to a file using the `/proc` path and comparing the content seen from + # the `/var` path, we can conclude if the LXD daemon is executing + # in the same mount namespace as ours (safe to kill) or not (ignore). + # A priv nested LXD would pass the EUID=0 and SNAP_NAME=lxd tests but would + # fail the `.validate` test as it wouldn't be in the same mount namespace. + echo "$$" > "/proc/${pid}/root${SNAP_COMMON}/lxd/.validate" 2>/dev/null || true + if [ "$(cat "${SNAP_COMMON}/lxd/.validate" 2>/dev/null)" = "$$" ]; then echo "=> Killing conflicting LXD (pid=${pid})" kill -9 "${pid}" || true - rm -f "/var/snap/lxd/common/lxd/.validate" fi + rm -f "/proc/${pid}/root${SNAP_COMMON}/lxd/.validate" done ## Move the database out of the versioned path if present @@ -608,12 +738,19 @@ if [ -x "${SNAP_COMMON}/lxd.debug" ]; then echo "==> WARNING: Using a custom debug LXD binary!" fi +# Note: Snaps disallow running binaries from certain paths (for example paths under home directories). +# These will show `permission denied` when trying to run the executable. +if [ -n "${minio_path:-""}" ] ; then + minio_dir="/var/lib/snapd/hostfs${minio_path}" + export PATH="${PATH}:${minio_dir}" +fi + CMD="${LXD} --logfile ${SNAP_COMMON}/lxd/logs/lxd.log" if getent group "${daemon_group}" >/dev/null 2>&1; then CMD="${CMD} --group ${daemon_group}" - if [ -e "/var/snap/lxd/common/lxd/unix.socket" ]; then - chgrp "${daemon_group}" /var/snap/lxd/common/lxd/unix.socket + if [ -e "${SNAP_COMMON}/lxd/unix.socket" ]; then + chgrp "${daemon_group}" "${SNAP_COMMON}/lxd/unix.socket" fi else echo "==> No \"${daemon_group}\" group found, only root will be able to use LXD." @@ -631,6 +768,10 @@ if [ "${daemon_verbose:-"false"}" = "true" ]; then CMD="${CMD} --verbose" fi +if [ "${db_trace:-"false"}" = "true" ]; then + export LIBDQLITE_TRACE=1 +fi + # Check if this is the first time LXD is started. FIRSTRUN="false" if [ ! -d "${SNAP_COMMON}/lxd/database" ]; then @@ -691,7 +832,7 @@ if [ "${FIRSTRUN}" = "true" ]; then echo "==> Running LXD preseed file" ${LXD} init --preseed < "${SNAP_COMMON}/init.yaml" mv "${SNAP_COMMON}/init.yaml" "${SNAP_COMMON}/init.yaml.applied" - elif echo "${SNAP_MODEL}" | grep -q "^lxd-core"; then + elif [ "${LXD_APPLIANCE}" = "true" ]; then echo "==> Initializing LXD appliance" # Network (NIC with the default gateway) diff --git a/snapcraft/commands/daemon.stop b/snapcraft/commands/daemon.stop index b964ae0eb..1f84e953e 100755 --- a/snapcraft/commands/daemon.stop +++ b/snapcraft/commands/daemon.stop @@ -9,24 +9,23 @@ if [ -d /sys/kernel/security/apparmor ]; then fi fi -export LXD_DIR="${SNAP_COMMON}/lxd/" -PID=$(cat "${SNAP_COMMON}/lxd.pid" || true) - -# FIXME: Detect stop reason -# This should be exposed by snapd directly -STATUS=$(snap-query /run/snapd.socket lxd 2>/dev/null || true) - reason="host shutdown" if [ -s "${SNAP_COMMON}/state" ]; then - reason="$(cat "${SNAP_COMMON}/state")" -elif [ "${STATUS}" = "auto-refresh" ]; then - reason="snap refresh" -elif [ "${STATUS}" = "refresh-snap" ]; then - reason="snap refresh" -elif [ "${STATUS}" = "install-snap" ]; then - reason="snap refresh" -elif [ "${STATUS}" = "remove-snap" ]; then - reason="snap removal" + read -r reason < "${SNAP_COMMON}/state" +else + # FIXME: Detect stop reason + # This should be exposed by snapd directly + STATUS=$(snap-query 2>/dev/null || true) + + if [ "${STATUS}" = "auto-refresh" ]; then + reason="snap refresh" + elif [ "${STATUS}" = "refresh-snap" ]; then + reason="snap refresh" + elif [ "${STATUS}" = "install-snap" ]; then + reason="snap refresh" + elif [ "${STATUS}" = "remove-snap" ]; then + reason="snap removal" + fi fi echo "=> Stop reason is: ${reason}" @@ -41,6 +40,9 @@ if [ "${reason}" = "reload" ] || [ "${reason}" = "crashed" ]; then exit 0 fi +export LXD_DIR="${SNAP_COMMON}/lxd/" +read -r PID < "${SNAP_COMMON}/lxd.pid" || true + # Handle refreshes if [ "${reason}" = "snap refresh" ]; then echo "=> Stopping LXD" @@ -74,7 +76,7 @@ fi # Shutdown the daemons ## LXD -echo "=> Stopping LXD (with container shutdown)" +echo "=> Stopping LXD (with instance shutdown)" echo host-shutdown > "${SNAP_COMMON}/state" if [ -n "${PID}" ] && kill -0 "${PID}" 2>/dev/null; then @@ -104,8 +106,8 @@ fi ## OpenVswitch if [ -e "${SNAP_COMMON}/openvswitch/run/ovs-vswitchd.pid" ]; then - PID=$(cat "${SNAP_COMMON}/openvswitch/run/ovs-vswitchd.pid") - if [ -n "${PID}" ] && kill -0 "${PID}" 2>/dev/null; then + read -r OVS_PID < "${SNAP_COMMON}/openvswitch/run/ovs-vswitchd.pid" || true + if [ -n "${OVS_PID}" ] && kill -0 "${OVS_PID}" 2>/dev/null; then ( echo "=> Stopping Open vSwitch" @@ -129,17 +131,17 @@ fi ## LXCFS if [ -e "${SNAP_COMMON}/lxcfs.pid" ]; then - echo "=> Stopping LXCFS" + read -r LXCFS_PID < "${SNAP_COMMON}/lxcfs.pid" || true + if [ -n "${LXCFS_PID}" ] && kill -0 "${LXCFS_PID}" 2>/dev/null; then + echo "=> Stopping LXCFS" - PID=$(cat "${SNAP_COMMON}/lxcfs.pid") - if [ -n "${PID}" ] && kill -0 "${PID}" 2>/dev/null; then - if ! kill "$PID"; then + if ! kill "${LXCFS_PID}"; then echo "==> Failed to signal LXCFS to stop" fi DEAD=0 for _ in $(seq 30); do - if ! kill -0 "${PID}" 2>/dev/null; then + if ! kill -0 "${LXCFS_PID}" 2>/dev/null; then DEAD=1 echo "==> Stopped LXCFS" break @@ -149,7 +151,7 @@ if [ -e "${SNAP_COMMON}/lxcfs.pid" ]; then if [ "${DEAD}" = "0" ]; then echo "==> Forcefully stopping LXCFS after 30 seconds wait" - if kill -9 "${PID}" 2>/dev/null; then + if kill -9 "${LXCFS_PID}" 2>/dev/null; then echo "==> Stopped LXCFS" else echo "==> Failed to stop LXCFS" @@ -166,7 +168,7 @@ rm -f "${SNAP_COMMON}/lxcfs.pid" "${SNAP_COMMON}/lxd.pid" ## Flush our shared namespace from the host echo "=> Cleaning up namespaces" -nsenter -t 1 -m umount -l /var/snap/lxd/common/ns 2>/dev/null || true +nsenter -t 1 -m umount -l "${SNAP_COMMON}/ns" 2>/dev/null || true echo "=> All done" exit 0 diff --git a/snapcraft/commands/lxc b/snapcraft/commands/lxc index 905323943..99a274a68 100755 --- a/snapcraft/commands/lxc +++ b/snapcraft/commands/lxc @@ -1,24 +1,6 @@ #!/bin/sh set -eu -# Re-exec outside of apparmor confinement -if [ -d /sys/kernel/security/apparmor ]; then - label="$(while read -r l; do echo "$l"; done < /proc/self/attr/current)" - if [ "$label" != "unconfined" ] && [ -n "${label##*(unconfined)}" ]; then - exec /usr/bin/aa-exec -p unconfined -- "$0" "$@" - fi -fi - -# Check if native and snap installed -if [ -e "/var/lib/lxd/unix.socket" ]; then - pid=$(ss -nlpx src "/var/lib/lxd/unix.socket" 2>/dev/null | grep "/var/lib/lxd/unix.socket" | sed -e "s/.*pid=//" -e "s/,.*//g") - if [ "${pid}" -gt 0 ] 2>/dev/null; then - echo "Error: Both native and snap packages are installed on this system" - echo " Run \"lxd.migrate\" to complete your migration to the snap package" - exit 1 - fi -fi - # Fill SNAP_REAL_HOME if missing if [ -z "${SNAP_REAL_HOME:-""}" ]; then SNAP_REAL_HOME="${HOME}" @@ -29,15 +11,6 @@ if [ -z "${SNAP_REAL_HOME:-""}" ]; then fi fi -# Migrate data if needed -if [ ! -d "${SNAP_USER_COMMON}/config" ]; then - if [ -d "${SNAP_REAL_HOME}/.config/lxc" ]; then - cp -r "${SNAP_REAL_HOME}/.config/lxc" "${SNAP_USER_COMMON}/config" || true - fi - - mkdir -p "${SNAP_USER_COMMON}/config" -fi - # Set the environment if [ -z "${LXD_DIR:-""}" ]; then export LXD_DIR="${SNAP_COMMON}/lxd/" @@ -48,6 +21,7 @@ if [ -z "${LXD_DIR:-""}" ]; then fi export LXD_CONF="${SNAP_USER_COMMON}/config" +[ -d "${LXD_CONF}" ] || mkdir -p "${LXD_CONF}" export LXD_GLOBAL_CONF="${LXD_GLOBAL_CONF:-"${SNAP_COMMON}/global-conf/"}" # Use editor wrapper @@ -66,5 +40,10 @@ if [ -x "${SNAP_COMMON}/lxc.debug" ]; then LXC="${SNAP_COMMON}/lxc.debug" fi +# Run lxc itself outside of apparmor confinement +if [ -d /sys/kernel/security/apparmor ]; then + exec /usr/bin/aa-exec -p unconfined -- "${LXC}" "$@" +fi + # Run lxc itself exec "${LXC}" "$@" diff --git a/snapcraft/commands/lxc-to-lxd b/snapcraft/commands/lxc-to-lxd deleted file mode 100755 index 11af0038a..000000000 --- a/snapcraft/commands/lxc-to-lxd +++ /dev/null @@ -1,25 +0,0 @@ -#!/bin/sh -set -eu - -# Re-exec outside of apparmor confinement -if [ -d /sys/kernel/security/apparmor ]; then - label="$(cat /proc/self/attr/current 2>/dev/null)" - if [ "$label" != "unconfined" ] && [ -n "${label##*(unconfined)}" ]; then - exec aa-exec -p unconfined -- "$0" "$@" - fi -fi - -# Check that we're root -if [ "$(id -u)" != "0" ]; then - echo "error: This tool must be run as root." - exit 1 -fi - -# shellcheck disable=SC2155 -export SNAP_CURRENT="$(realpath "${SNAP}/..")/current" - -export LXD_DIR="${LXD_DIR:-"${SNAP_COMMON}/lxd/"}" -export LXD_CONF="${SNAP_USER_COMMON}/config" -export LXD_GLOBAL_CONF="${LXD_GLOBAL_CONF:-"${SNAP_COMMON}/global-conf/"}" - -exec "${SNAP_CURRENT}/bin/lxc-to-lxd" "$@" diff --git a/snapcraft/commands/lxd b/snapcraft/commands/lxd index fb383d439..dc9fc6f1e 100755 --- a/snapcraft/commands/lxd +++ b/snapcraft/commands/lxd @@ -9,27 +9,21 @@ if [ -d /sys/kernel/security/apparmor ]; then fi fi -# Check if native and snap installed -pid=$(ss -nlpx src "/var/lib/lxd/unix.socket" 2>/dev/null | grep "/var/lib/lxd/unix.socket" | sed -e "s/.*pid=//" -e "s/,.*//g") -if [ "${1:-""}" != "waitready" ] && [ "${pid}" -gt 0 ] 2>/dev/null; then - echo "Error: Both native and snap packages are installed on this system" - echo " Run \"lxd.migrate\" to complete your migration to the snap package" - exit 1 -fi - # shellcheck disable=SC2155 export SNAP_CURRENT="$(realpath "${SNAP}/..")/current" -# shellcheck disable=SC2155 -export ARCH="$(basename "$(readlink -f "${SNAP_CURRENT}"/lib/*-linux-gnu*/)")" +# Turn `/snap/lxd/28637/lib/x86_64-linux-gnu` into `x86_64-linux-gnu` +# Similar to `basename` but using variable substitution instead of external executable +LIB_ARCH="$(readlink -f "${SNAP_CURRENT}"/lib/*-linux-gnu*/)" +export ARCH="${LIB_ARCH##*/}" 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_DIR="${LXD_DIR:-"${SNAP_COMMON}/lxd/"}" # Make sure we have a ZFS binary on the path -export LD_LIBRARY_PATH="${SNAP_CURRENT}/zfs-0.8/lib/:${LD_LIBRARY_PATH}" -export PATH="${SNAP_CURRENT}/zfs-0.8/bin:${PATH}" +export LD_LIBRARY_PATH="${SNAP_CURRENT}/zfs-2.1/lib/:${LD_LIBRARY_PATH}" +export PATH="${SNAP_CURRENT}/zfs-2.1/bin:${PATH}" LXD="lxd" if [ -x "${SNAP_COMMON}/lxd.debug" ]; then diff --git a/snapcraft/commands/lxd-benchmark b/snapcraft/commands/lxd-benchmark deleted file mode 100755 index 5b196d3d3..000000000 --- a/snapcraft/commands/lxd-benchmark +++ /dev/null @@ -1,24 +0,0 @@ -#!/bin/sh -set -eu - -# Re-exec outside of apparmor confinement -if [ -d /sys/kernel/security/apparmor ]; then - label="$(cat /proc/self/attr/current 2>/dev/null)" - if [ "$label" != "unconfined" ] && [ -n "${label##*(unconfined)}" ]; then - exec aa-exec -p unconfined -- "$0" "$@" - fi -fi - -# Check if native and snap installed -pid=$(ss -nlpx src "/var/lib/lxd/unix.socket" 2>/dev/null | grep "/var/lib/lxd/unix.socket" | sed -e "s/.*pid=//" -e "s/,.*//g") -if [ "${pid}" -gt 0 ] 2>/dev/null; then - echo "Error: Both native and snap packages are installed on this system" - echo " Run \"lxd.migrate\" to complete your migration to the snap package" - exit 1 -fi - -export LXD_DIR="${LXD_DIR:-"${SNAP_COMMON}/lxd/"}" -export LXD_CONF="${SNAP_USER_COMMON}/config" -export LXD_GLOBAL_CONF="${LXD_GLOBAL_CONF:-"${SNAP_COMMON}/global-conf/"}" - -exec lxd-benchmark "$@" diff --git a/snapcraft/commands/lxd-migrate b/snapcraft/commands/lxd-migrate deleted file mode 100755 index 03a6df1a0..000000000 --- a/snapcraft/commands/lxd-migrate +++ /dev/null @@ -1,38 +0,0 @@ -#!/bin/sh -set -eu - -# Re-exec outside of apparmor confinement -if [ -d /sys/kernel/security/apparmor ]; then - label="$(cat /proc/self/attr/current 2>/dev/null)" - if [ "$label" != "unconfined" ] && [ -n "${label##*(unconfined)}" ]; then - exec aa-exec -p unconfined -- "$0" "$@" - fi -fi - -# shellcheck disable=SC2155 -export SNAP_CURRENT="$(realpath "${SNAP}/..")/current" - -export LXD_DIR="${LXD_DIR:-"${SNAP_COMMON}/lxd/"}" - -# Setup for ZFS -if [ -e /sys/module/zfs/version ]; then - VERSION=$(cat /sys/module/zfs/version) -else - VERSION=$(nsenter -t 1 -m modinfo -F version zfs 2>/dev/null || true) -fi - -if echo "${VERSION}" | grep -q ^2\.2; then - export LD_LIBRARY_PATH="${SNAP_CURRENT}/zfs-2.2/lib/:${LD_LIBRARY_PATH}" - export PATH="${SNAP_CURRENT}/zfs-2.2/bin:${PATH}" -elif echo "${VERSION}" | grep -q ^2\.1; then - export LD_LIBRARY_PATH="${SNAP_CURRENT}/zfs-2.1/lib/:${LD_LIBRARY_PATH}" - export PATH="${SNAP_CURRENT}/zfs-2.1/bin:${PATH}" -elif echo "${VERSION}" | grep -q ^2\.0; then - export LD_LIBRARY_PATH="${SNAP_CURRENT}/zfs-2.0/lib/:${LD_LIBRARY_PATH}" - export PATH="${SNAP_CURRENT}/zfs-2.0/bin:${PATH}" -elif echo "${VERSION}" | grep -q ^0\.8; then - export LD_LIBRARY_PATH="${SNAP_CURRENT}/zfs-0.8/lib/:${LD_LIBRARY_PATH}" - export PATH="${SNAP_CURRENT}/zfs-0.8/bin:${PATH}" -fi - -exec lxd-migrate "$@" diff --git a/snapcraft/commands/lxd-user b/snapcraft/commands/lxd-user index 92a7d7798..023795ea9 100755 --- a/snapcraft/commands/lxd-user +++ b/snapcraft/commands/lxd-user @@ -23,4 +23,9 @@ chmod 0711 "${SNAP_COMMON}/lxd-user/" cd "${SNAP_COMMON}/lxd-user/" # Run lxd-user -exec lxd-user +LXD_USER="lxd-user" +if [ -x "${SNAP_COMMON}/lxd-user.debug" ]; then + LXD_USER="${SNAP_COMMON}/lxd-user.debug" +fi + +exec "${LXD_USER}" "$@" diff --git a/snapcraft/commands/snap-query b/snapcraft/commands/snap-query new file mode 100755 index 000000000..369648a2e --- /dev/null +++ b/snapcraft/commands/snap-query @@ -0,0 +1,96 @@ +#!/usr/bin/python3 + +"""Query the status of the lxd snap.""" + +# Python implementation of: +# $ curl -s --unix /run/snapd.socket 'http://unix.socket/v2/changes?select=in-progress&for=lxd' | jq -r '.result[0].kind' +# auto-refresh + +# The full JSON output when querying the in-progress changes for the lxd snap: +# $ curl -s --unix /run/snapd.socket 'http://snapd/v2/changes?select=in-progress&for=lxd' | jq -r . +# { +# "type": "sync", +# "status-code": 200, +# "status": "OK", +# "result": [ +# { +# "id": "1907", +# "kind": "auto-refresh", +# "summary": "Auto-refresh snap \"lxd\"", +# "status": "Hold", +# "ready": true, +# "spawn-time": "2024-02-19T10:21:34.429396408-05:00", +# "data": { +# "snap-names": [ +# "lxd" +# ] +# } +# } +# ] +# } + +# Heavily inspired from snapd's api-client.py: +# https://github.com/snapcore/snapd/blob/master/tests/main/theme-install/api-client/bin/api-client.py + +import http.client +import json +import socket +import sys + + +# This class is a subclass of http.client.HTTPConnection that connects to a Unix socket instead of a TCP socket. +class UnixSocketHTTPConnection(http.client.HTTPConnection): + def __init__(self, socket_path): + super().__init__("snapd") + self._socket_path = socket_path + + def connect(self): + s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) + s.connect(self._socket_path) + self.sock = s + + +# This function connects to the Unix socket and requests the in-progress changes for the lxd snap. +# Returns the kind of the first result, or an empty string if an error occurs. +def main(): + # Try to connect to the Unix socket and request the in-progress changes for the lxd snap. + # If an exception occurs, print an error message and return an empty string. + try: + conn = UnixSocketHTTPConnection("/run/snapd.socket") + conn.request("GET", "/v2/changes?select=in-progress&for=lxd") + response = conn.getresponse() + body = response.read().decode() + except FileNotFoundError: + print("missing socket", file=sys.stderr) + return "" + except http.client.HTTPException as e: + print("HTTP exception:", e, file=sys.stderr) + return "" + finally: + conn.close() + + # If the response status is not 200, print an error message and return an empty string. + if response.status != 200: + print("HTTP error:", response.status, file=sys.stderr) + return "" + + # If the response body is missing or empty, print an error message and return an empty string. + if not body: + print("Missing/empty body", file=sys.stderr) + return "" + + # Try to parse the response body as JSON, and extract the "kind" field from the first result. + try: + data = json.loads(body) + except json.JSONDecodeError as e: + print("JSON decode exception:", e, file=sys.stderr) + return "" + + if "result" in data and isinstance(data["result"], list) and len(data["result"]): + return data["result"][0].get("kind", "") + + return "" + + +if __name__ == "__main__": + print(main()) diff --git a/snapcraft/hooks/configure b/snapcraft/hooks/configure index be00f2ba9..b4488f8b5 100755 --- a/snapcraft/hooks/configure +++ b/snapcraft/hooks/configure @@ -39,23 +39,26 @@ if [ ! -e /run/snapd-snap.socket ]; then fi # Get the current config +apparmor_unprivileged_restrictions_disable=$(get_bool "$(snapctl get apparmor.unprivileged-restrictions-disable)") ceph_builtin=$(get_bool "$(snapctl get ceph.builtin)") ceph_external=$(get_bool "$(snapctl get ceph.external)") -criu_enable=$(get_bool "$(snapctl get criu.enable)") daemon_debug=$(get_bool "$(snapctl get daemon.debug)") daemon_group=$(snapctl get daemon.group) daemon_user_group=$(snapctl get daemon.user.group) daemon_syslog=$(get_bool "$(snapctl get daemon.syslog)") daemon_verbose=$(get_bool "$(snapctl get daemon.verbose)") +db_trace=$(get_bool "$(snapctl get db.trace)") lvm_external=$(get_bool "$(snapctl get lvm.external)") lxcfs_loadavg=$(get_bool "$(snapctl get lxcfs.loadavg)") lxcfs_pidfd=$(get_bool "$(snapctl get lxcfs.pidfd)") lxcfs_cfs=$(get_bool "$(snapctl get lxcfs.cfs)") lxcfs_debug=$(get_bool "$(snapctl get lxcfs.debug)") +minio_path="$(snapctl get minio.path)" 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) @@ -66,26 +69,29 @@ fi # Generate the config config="${SNAP_COMMON}/config" -{ - echo "# This file is auto-generated, do NOT manually edit" - echo "ceph_builtin=${ceph_builtin:-"false"}" - echo "ceph_external=${ceph_external:-"false"}" - echo "criu_enable=${criu_enable:-"false"}" - echo "daemon_debug=${daemon_debug:-"false"}" - echo "daemon_group=${daemon_group:-"lxd"}" - echo "daemon_user_group=${daemon_user_group:-"lxd"}" - echo "daemon_syslog=${daemon_syslog:-"false"}" - echo "daemon_verbose=${daemon_verbose:-"false"}" - echo "lvm_external=${lvm_external:-"false"}" - echo "lxcfs_loadavg=${lxcfs_loadavg:-"false"}" - echo "lxcfs_pidfd=${lxcfs_pidfd:-"false"}" - echo "lxcfs_cfs=${lxcfs_cfs:-"false"}" - echo "lxcfs_debug=${lxcfs_debug:-"false"}" - echo "openvswitch_builtin=${openvswitch_builtin:-"false"}" - echo "openvswitch_external=${openvswitch_external:-"false"}" - echo "ovn_builtin=${ovn_builtin:-"false"}" - echo "ui_enable=${ui_enable:-"false"}" -} > "${config}" +cat << EOC > "${config}" +# This file is auto-generated, do NOT manually edit +apparmor_unprivileged_restrictions_disable=${apparmor_unprivileged_restrictions_disable:-"true"} +ceph_builtin=${ceph_builtin:-"false"} +ceph_external=${ceph_external:-"false"} +daemon_debug=${daemon_debug:-"false"} +daemon_group=${daemon_group:-"lxd"} +daemon_syslog=${daemon_syslog:-"false"} +daemon_user_group=${daemon_user_group:-"lxd"} +daemon_verbose=${daemon_verbose:-"false"} +db_trace=${db_trace:-"false"} +lvm_external=${lvm_external:-"false"} +lxcfs_cfs=${lxcfs_cfs:-"false"} +lxcfs_debug=${lxcfs_debug:-"false"} +lxcfs_loadavg=${lxcfs_loadavg:-"false"} +lxcfs_pidfd=${lxcfs_pidfd:-"true"} +minio_path=${minio_path:-""} +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 if getent group "${daemon_group}" >/dev/null 2>&1; then diff --git a/snapcraft/hooks/connect-plug-ovn-certificates b/snapcraft/hooks/connect-plug-ovn-certificates new file mode 100755 index 000000000..06ea22e27 --- /dev/null +++ b/snapcraft/hooks/connect-plug-ovn-certificates @@ -0,0 +1,56 @@ +#!/bin/sh +set -eu + +# Re-exec outside of apparmor confinement +if [ -d /sys/kernel/security/apparmor ]; then + label="$(cat /proc/self/attr/current 2>/dev/null)" + if [ "$label" != "unconfined" ] && [ -n "${label##*(unconfined)}" ]; then + exec aa-exec -p unconfined -- "$0" "$@" + fi +fi + +# Utility functions +get_bool() { + value=$(echo "${1:-}" | tr '[:upper:]' '[:lower:]') + + # See if it's true + for yes in "true" "1" "yes" "on"; do + if [ "${value}" = "${yes}" ]; then + echo "true" + return + fi + done + + # See if it's false + for no in "false" "0" "no" "off"; do + if [ "${value}" = "${no}" ]; then + echo "false" + return + fi + done + + # Invalid value (or not set) + return +} + +# Only create symlinks if /etc has been generated by daemon.start. +if [ -e "/etc/.lxd_generated" ]; then + ovn_builtin=$(get_bool "$(snapctl get ovn.builtin)") + + echo "==> Cleaning up OVN configuration" + if [ -L /etc/ovn ]; then + echo "=> Removing /etc/ovn symlink" + rm -f /etc/ovn + elif [ -d /etc/ovn ]; then + echo "=> Removing /etc/ovn directory" + rm -rf /etc/ovn + fi + + if ! [ "${ovn_builtin:-"false"}" = "true" ]; then + echo "=> Configuring MicroOVN Content Interface" + mkdir -p /etc/ovn + ln -snf "${SNAP_DATA}/microovn/certificates/pki/client-cert.pem" /etc/ovn/cert_host + ln -snf "${SNAP_DATA}/microovn/certificates/pki/client-privkey.pem" /etc/ovn/key_host + ln -snf "${SNAP_DATA}/microovn/certificates/pki/cacert.pem" /etc/ovn/ovn-central.crt + fi +fi diff --git a/snapcraft/hooks/connect-plug-ovn-chassis b/snapcraft/hooks/connect-plug-ovn-chassis new file mode 100755 index 000000000..16496ad09 --- /dev/null +++ b/snapcraft/hooks/connect-plug-ovn-chassis @@ -0,0 +1,42 @@ +#!/bin/sh +set -eu + +# Re-exec outside of apparmor confinement +if [ -d /sys/kernel/security/apparmor ]; then + label="$(cat /proc/self/attr/current 2>/dev/null)" + if [ "$label" != "unconfined" ] && [ -n "${label##*(unconfined)}" ]; then + exec aa-exec -p unconfined -- "$0" "$@" + fi +fi + +# Utility functions +get_bool() { + value=$(echo "${1:-}" | tr '[:upper:]' '[:lower:]') + + # See if it's true + for yes in "true" "1" "yes" "on"; do + if [ "${value}" = "${yes}" ]; then + echo "true" + return + fi + done + + # See if it's false + for no in "false" "0" "no" "off"; do + if [ "${value}" = "${no}" ]; then + echo "false" + return + fi + done + + # Invalid value (or not set) + return +} + +# Only create symlinks if /etc has been generated by daemon.start. +if [ -e "/etc/.lxd_generated" ]; then + openvswitch_builtin=$(get_bool "$(snapctl get openvswitch.builtin)") + if ! [ "${openvswitch_builtin:-"false"}" = "true" ]; then + ln -snf "${SNAP_DATA}/microovn/chassis/switch" /run/openvswitch + fi +fi diff --git a/snapcraft/hooks/connect-plug-qemu-external b/snapcraft/hooks/connect-plug-qemu-external new file mode 100755 index 000000000..fd952af0a --- /dev/null +++ b/snapcraft/hooks/connect-plug-qemu-external @@ -0,0 +1,16 @@ +#!/bin/sh +set -eu + +# Re-exec outside of apparmor confinement +if [ -d /sys/kernel/security/apparmor ]; then + label="$(cat /proc/self/attr/current 2>/dev/null)" + if [ "$label" != "unconfined" ] && [ -n "${label##*(unconfined)}" ]; then + exec aa-exec -p unconfined -- "$0" "$@" + fi +fi + +echo 1 > "${SNAP_COMMON}/use-qemu-external-snap" + +echo reload > "${SNAP_COMMON}/state" +read -r PID < "${SNAP_COMMON}/lxd.pid" +kill "$PID" diff --git a/snapcraft/hooks/disconnect-plug-ovn-certificates b/snapcraft/hooks/disconnect-plug-ovn-certificates new file mode 100755 index 000000000..323d2e1d8 --- /dev/null +++ b/snapcraft/hooks/disconnect-plug-ovn-certificates @@ -0,0 +1,45 @@ +#!/bin/sh +set -eu + +# Re-exec outside of apparmor confinement +if [ -d /sys/kernel/security/apparmor ]; then + label="$(cat /proc/self/attr/current 2>/dev/null)" + if [ "$label" != "unconfined" ] && [ -n "${label##*(unconfined)}" ]; then + exec aa-exec -p unconfined -- "$0" "$@" + fi +fi + +# Utility functions +get_bool() { + value=$(echo "${1:-}" | tr '[:upper:]' '[:lower:]') + + # See if it's true + for yes in "true" "1" "yes" "on"; do + if [ "${value}" = "${yes}" ]; then + echo "true" + return + fi + done + + # See if it's false + for no in "false" "0" "no" "off"; do + if [ "${value}" = "${no}" ]; then + echo "false" + return + fi + done + + # Invalid value (or not set) + return +} + +# Only create symlinks if /etc has been generated by daemon.start. +if [ -e "/etc/.lxd_generated" ]; then + ovn_builtin=$(get_bool "$(snapctl get ovn.builtin)") + if [ "${ovn_builtin:-"false"}" = "true" ]; then + mkdir -p "${SNAP_COMMON}/ovn" + ln -snf "${SNAP_COMMON}/ovn" /etc/ovn + else + ln -snf /var/lib/snapd/hostfs/etc/ovn /etc/ovn + fi +fi diff --git a/snapcraft/hooks/disconnect-plug-ovn-chassis b/snapcraft/hooks/disconnect-plug-ovn-chassis new file mode 100755 index 000000000..7733a9599 --- /dev/null +++ b/snapcraft/hooks/disconnect-plug-ovn-chassis @@ -0,0 +1,62 @@ +#!/bin/sh +set -eu + +# Re-exec outside of apparmor confinement +if [ -d /sys/kernel/security/apparmor ]; then + label="$(cat /proc/self/attr/current 2>/dev/null)" + if [ "$label" != "unconfined" ] && [ -n "${label##*(unconfined)}" ]; then + exec aa-exec -p unconfined -- "$0" "$@" + fi +fi + +# Utility functions +get_bool() { + value=$(echo "${1:-}" | tr '[:upper:]' '[:lower:]') + + # See if it's true + for yes in "true" "1" "yes" "on"; do + if [ "${value}" = "${yes}" ]; then + echo "true" + return + fi + done + + # See if it's false + for no in "false" "0" "no" "off"; do + if [ "${value}" = "${no}" ]; then + echo "false" + return + fi + done + + # Invalid value (or not set) + return +} + +# Only create symlinks if /etc has been generated by daemon.start. +if [ -e "/etc/.lxd_generated" ]; then + openvswitch_builtin=$(get_bool "$(snapctl get openvswitch.builtin)") + if [ "${openvswitch_builtin:-"false"}" = "true" ]; then + echo "=> Starting Open vSwitch" + export OVS_RUNDIR="${SNAP_COMMON}/openvswitch/run/" + ( + set -e + export OVS_LOGDIR="${SNAP_COMMON}/openvswitch/logs/" + export OVS_DBDIR="${SNAP_COMMON}/openvswitch/db/" + export OVS_SYSCONFDIR="${SNAP_COMMON}/openvswitch/conf/" + export OVS_PKGDATADIR="${SNAP}/share/openvswitch/" + export OVS_BINDIR="${SNAP}/bin/" + export OVS_SBINDIR="${SNAP}/bin/" + + mkdir -p "${OVS_SYSCONFDIR}/openvswitch" + ( + # Close socket activation fd + exec 3<&- || true + + "${SNAP}/share/openvswitch/scripts/ovs-ctl" start --system-id=random + ) + ) + else + ln -snf /var/lib/snapd/hostfs/run/openvswitch /run/openvswitch + fi +fi diff --git a/snapcraft/hooks/disconnect-plug-qemu-external b/snapcraft/hooks/disconnect-plug-qemu-external new file mode 100755 index 000000000..9fce6546f --- /dev/null +++ b/snapcraft/hooks/disconnect-plug-qemu-external @@ -0,0 +1,16 @@ +#!/bin/sh +set -eu + +# Re-exec outside of apparmor confinement +if [ -d /sys/kernel/security/apparmor ]; then + label="$(cat /proc/self/attr/current 2>/dev/null)" + if [ "$label" != "unconfined" ] && [ -n "${label##*(unconfined)}" ]; then + exec aa-exec -p unconfined -- "$0" "$@" + fi +fi + +rm -f "${SNAP_COMMON}/use-qemu-external-snap" + +echo reload > "${SNAP_COMMON}/state" +read -r PID < "${SNAP_COMMON}/lxd.pid" +kill "$PID" diff --git a/snapcraft/hooks/remove b/snapcraft/hooks/remove index c9e8f1ec0..be8648895 100755 --- a/snapcraft/hooks/remove +++ b/snapcraft/hooks/remove @@ -10,11 +10,27 @@ if [ -d /sys/kernel/security/apparmor ]; then fi # Unmount potential LXD paths. -for path in "${SNAP_COMMON}/ns/shmounts" "${SNAP_COMMON}/ns/mntns" "${SNAP_COMMON}/ns" "${SNAP_COMMON}/var/lib/lxcfs/"; do +for path in "${SNAP_COMMON}/ns/shmounts" "${SNAP_COMMON}/ns/mntns" "${SNAP_COMMON}/ns" "${SNAP_COMMON}/var/lib/lxcfs/" "${SNAP_COMMON}/shmounts"; do nsenter -t 1 -m umount -l "${path}" >/dev/null 2>&1 || true done # Stop workaround unit nsenter -t 1 -m systemctl stop snap.lxd.workaround >/dev/null 2>&1 || true +# Remove systemd override snippet +SYSTEMD_OVERRIDE_DIR="/var/lib/snapd/hostfs/run/systemd/system/snap.lxd.daemon.service.d" +if [ -e "${SYSTEMD_OVERRIDE_DIR}/lxd-shutdown.conf" ]; then + rm "${SYSTEMD_OVERRIDE_DIR}/lxd-shutdown.conf" || true + rmdir --ignore-fail-on-non-empty "${SYSTEMD_OVERRIDE_DIR}" + nsenter -t 1 -m systemctl daemon-reload || true +fi + +# Remove sysctl override snippet +SYSCTL_OVERRIDE_DIR="/var/lib/snapd/hostfs/run/sysctl.d" +if [ -e "${SYSCTL_OVERRIDE_DIR}/zz-lxd.conf" ]; then + rm "${SYSCTL_OVERRIDE_DIR}/zz-lxd.conf" || true + rmdir --ignore-fail-on-non-empty "${SYSCTL_OVERRIDE_DIR}" + nsenter -t 1 -m systemctl restart systemd-sysctl.service || true +fi + exit 0 diff --git a/snapcraft/wrappers/editor b/snapcraft/wrappers/editor index 825b41e7b..b66064549 100755 --- a/snapcraft/wrappers/editor +++ b/snapcraft/wrappers/editor @@ -7,14 +7,22 @@ run_cmd() { export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" export HOME="${SNAP_REAL_HOME}" export USER="${USERNAME}" - [ -z "${XDG_DATA_HOME:-}" ] && export XDG_DATA_HOME="${HOME}/.local/share/" - [ -z "${XDG_CONFIG_HOME:-}" ] && export XDG_CONFIG_HOME="${HOME}/.config/" - [ -z "${XDG_STATE_HOME:-}" ] && export XDG_STATE_HOME="${HOME}/.local/state/" + IGNORERCFILES="" + if [ "${HOME}" != "/root" ] && [ "${CMD}" = "nano" ]; then + export XDG_DATA_HOME="${HOME}/.local/share" + if [ ! -d "/var/lib/snapd/hostfs/${XDG_DATA_HOME}" ]; then + echo "Instructing nano to ignore RC files due to missing directory: \"${XDG_DATA_HOME}\"" + IGNORERCFILES="--ignorercfiles" + fi + fi # shellcheck disable=SC2145 - exec unshare --kill-child -U -m -p -r -f -R "/var/lib/snapd/hostfs/" "/bin/sh" -c "mount -t proc proc /proc 2>/dev/null || true; exec \"${CMD}\" \"$@\"" + exec unshare --kill-child -U -m -p -r -f --root="/var/lib/snapd/hostfs/" "/bin/sh" -c "mount -t proc proc /proc 2>/dev/null || true; exec \"${CMD}\" ${IGNORERCFILES} \"$@\"" } +# Detect base name +SNAP_BASE="$(sed -n '/^name:/ s/^name:\s*\(core[0-9]\{2\}\)/\1/p' /meta/snap.yaml)" + USERNS=1 [ -e /proc/sys/kernel/unprivileged_userns_clone ] && grep -qxF 0 /proc/sys/kernel/unprivileged_userns_clone && USERNS=0 @@ -35,40 +43,32 @@ if [ -z "${EDIT_PATH}" ] || [ "$#" -ge "3" ]; then done fi +# Default to trying nano if no editor is provided +if [ -z "${EDIT_CMD}" ]; then + EDIT_CMD="nano" +fi + # Try running the editor through the host. if [ -n "${EDIT_CMD}" ] && [ "${USERNS}" = 1 ]; then exec 9< /tmp/ # Replace "/tmp/" prefix by exec'ed FD 9. - EDIT_PATH_HOST="/proc/self/fd/9/$(echo "${EDIT_PATH}" | cut -d/ -f3)" + EDIT_PATH_HOST="/proc/self/fd/9/${EDIT_PATH##*/}" find_and_spawn "${EDIT_CMD}" "${EDIT_PATH_HOST}" fi -# If the editor's rcfile is not readable, ignore it. -EDIT_IGNORE_RC="" -EDIT_RESTRICT="" -# Default to built-in nano. -if [ -z "${EDIT_CMD}" ]; then - EDIT_CMD="nano" - EDIT_RESTRICT="--restricted" - [ -r "${SNAP}/etc/nanorc" ] || EDIT_IGNORE_RC="--ignorercfiles" -fi +# Fallback to using vim.tiny from base snap -# Setup for VIM. -if [ "$EDIT_CMD" != "nano" ]; then - # Find the base use by the LXD snap. - for vimrc in "${SNAP_USER_COMMON}/.vimrc" "/snap/core22/current/etc/vim/vimrc"; do - [ -r "${vimrc}" ] || continue - export VIMINIT="source ${vimrc}" - done +# Search for a vimrc +for vimrc in "${SNAP_USER_COMMON}/.vimrc" "/snap/${SNAP_BASE}/current/etc/vim/vimrc"; do + [ -r "${vimrc}" ] || continue + export VIMINIT="source ${vimrc}" +done - # Ignore vimrc if none was found to be readable. - if [ -z "${VIMINIT:-""}" ]; then - EDIT_IGNORE_RC="--clean" - fi - - EDIT_CMD="vim.tiny" - EDIT_RESTRICT="-Z" +# Ignore vimrc if none was found to be readable. +EDIT_IGNORE_RC="" +if [ -z "${VIMINIT:-""}" ]; then + EDIT_IGNORE_RC="--clean" fi # Run the editor. -exec "${EDIT_CMD}" ${EDIT_RESTRICT} ${EDIT_IGNORE_RC} "${EDIT_PATH}" +exec vim.tiny -Z ${EDIT_IGNORE_RC} "${EDIT_PATH}" diff --git a/snapcraft/wrappers/gpu-2404-custom-wrapper b/snapcraft/wrappers/gpu-2404-custom-wrapper new file mode 100755 index 000000000..4be1683cd --- /dev/null +++ b/snapcraft/wrappers/gpu-2404-custom-wrapper @@ -0,0 +1,12 @@ +#!/bin/sh + +# see also https://github.com/canonical/gpu-snap/blob/929a4228ebeb17dd1cb82c48346b192ac02ac1a3/bin/gpu-2404-wrapper#L1 + +if snapctl is-connected gpu-2404 +then + echo "INFO: the gpu-2404 interface is connected. Running with gpu-2404 wrapper." + exec "${SNAP}/gpu-2404/bin/gpu-2404-provider-wrapper" "$@" +else + echo "INFO: the gpu-2404 interface isn't connected. Skipping gpu-2404 wrapper." + exec "$@" +fi diff --git a/snapcraft/wrappers/kmod b/snapcraft/wrappers/kmod index 4b111c905..be1d3f7ef 100755 --- a/snapcraft/wrappers/kmod +++ b/snapcraft/wrappers/kmod @@ -1,9 +1,14 @@ #!/bin/sh -NAME="$(basename "${0}")" +# Turn `/usr/sbin/foo` into `foo` +# Similar to `basename` but using variable substitution instead of external executable +NAME="${0##*/}" -if [ "$(id -u)" != "0" ] && [ "${NAME}" = "modinfo" ]; then - TMPDIR=$(mktemp -d) - ln -s "/snap/core22/current/bin/kmod" "${TMPDIR}/modinfo" +# Detect base name +SNAP_BASE="$(sed -n '/^name:/ s/^name:\s*\(core[0-9]\{2\}\)/\1/p' /meta/snap.yaml)" + +if [ "${NAME}" = "modinfo" ] && [ "$(id -u)" != "0" ]; then + TMPDIR="$(mktemp -d)" + ln -s "/snap/${SNAP_BASE}/current/bin/kmod" "${TMPDIR}/modinfo" "${TMPDIR}/modinfo" "$@" RET=$? rm -Rf "${TMPDIR}" @@ -11,7 +16,7 @@ if [ "$(id -u)" != "0" ] && [ "${NAME}" = "modinfo" ]; then fi if [ "${NAME}" = "lsmod" ]; then - exec "/snap/core22/current/bin/kmod" "list" "$@" + exec "/snap/${SNAP_BASE}/current/bin/kmod" "list" "$@" fi for i in "/bin/${NAME}" "/sbin/${NAME}" "/usr/bin/${NAME}" "/usr/sbin/${NAME}"; do 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 diff --git a/snapcraft/wrappers/remote-viewer b/snapcraft/wrappers/remote-viewer index 4caf7272d..085eab3de 100755 --- a/snapcraft/wrappers/remote-viewer +++ b/snapcraft/wrappers/remote-viewer @@ -7,9 +7,6 @@ run_cmd() { export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" export HOME="${SNAP_REAL_HOME}" export USER="${USERNAME}" - [ -z "${XDG_DATA_HOME:-}" ] && export XDG_DATA_HOME="${HOME}/.local/share/" - [ -z "${XDG_CONFIG_HOME:-}" ] && export XDG_CONFIG_HOME="${HOME}/.config/" - [ -z "${XDG_STATE_HOME:-}" ] && export XDG_STATE_HOME="${HOME}/.local/state/" exec unshare -U -r chroot "/var/lib/snapd/hostfs/" "${CMD}" "$@" } diff --git a/snapcraft/wrappers/run-host b/snapcraft/wrappers/run-host index 0c2b3e5fc..26309e370 100755 --- a/snapcraft/wrappers/run-host +++ b/snapcraft/wrappers/run-host @@ -1,5 +1,7 @@ #!/bin/sh -CMD="$(basename "${0}")" +# Turn `/usr/sbin/foo` into `foo` +# Similar to `basename` but using variable substitution instead of external executable +CMD="${0##*/}" unset LD_LIBRARY_PATH unset PYTHONPATH @@ -9,4 +11,4 @@ if [ "$(id -u)" = "0" ]; then exec nsenter -t 1 -m "${CMD}" "$@" fi -exec unshare -U -r chroot "/var/lib/snapd/hostfs/" "${CMD}" "$@" +exec unshare -U -r --root="/var/lib/snapd/hostfs/" "${CMD}" "$@" diff --git a/snapcraft/wrappers/sshfs b/snapcraft/wrappers/sshfs index f7d8b45a2..0d232c630 100755 --- a/snapcraft/wrappers/sshfs +++ b/snapcraft/wrappers/sshfs @@ -7,7 +7,10 @@ if [ "$(id -u)" != "0" ]; then exit 1 fi -CMD="$(basename "${0}")" +# Turn `/usr/sbin/foo` into `foo` +# Similar to `basename` but using variable substitution instead of external executable +CMD="${0##*/}" + unset LD_LIBRARY_PATH export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" diff --git a/snapcraft/wrappers/virt-v2v-in-place b/snapcraft/wrappers/virt-v2v-in-place new file mode 100755 index 000000000..fa6f6a3f6 --- /dev/null +++ b/snapcraft/wrappers/virt-v2v-in-place @@ -0,0 +1,14 @@ +#!/bin/sh + +CMD="virt-v2v-in-place" + +unset XDG_RUNTIME_DIR +unset LD_LIBRARY_PATH + +export PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin" + +if [ "$(id -u)" = "0" ]; then + exec nsenter -t 1 -m "${CMD}" "$@" +fi + +exec unshare -U -r --root="/var/lib/snapd/hostfs/" "${CMD}" "$@"