From e88dad84fbc59481975649745f2f6c399fa6213b Mon Sep 17 00:00:00 2001 From: Simon Deziel Date: Wed, 6 May 2026 14:44:34 -0400 Subject: [PATCH 01/28] github: ask CodeQL to also look after GH actions Signed-off-by: Simon Deziel (cherry picked from commit c96771d8ebb91715b61d775308f60105e8563eb4) --- .github/workflows/codeql.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 0ee6d261e..fbfbda356 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -41,7 +41,7 @@ jobs: strategy: fail-fast: false matrix: - language: [ 'go' ] + language: ['actions', 'go'] # CodeQL supports [ 'c-cpp', 'csharp', 'go', 'java-kotlin', 'javascript-typescript', 'python', 'ruby', 'swift' ] # Use only 'java-kotlin' to analyze code written in Java, Kotlin or both # Use only 'javascript-typescript' to analyze code written in JavaScript, TypeScript or both From 6048a6307c5fa192a2c20445a806d8aa64b06a35 Mon Sep 17 00:00:00 2001 From: Simon Deziel Date: Wed, 6 May 2026 15:21:15 -0400 Subject: [PATCH 02/28] github: add `concurrency` and top level `permissions` to CodeQL workflow Signed-off-by: Simon Deziel (cherry picked from commit 73e483c66f8663bcaaa550d88556c669971cf6e4) --- .github/workflows/codeql.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index fbfbda356..1527b22f3 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -19,6 +19,12 @@ on: schedule: - cron: '19 20 * * 5' +permissions: {} + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + jobs: analyze: if: ${{ github.repository_owner == 'canonical' }} From 38678f7c552fc862f73c5f33a2bb11dd0371dace Mon Sep 17 00:00:00 2001 From: Simon Deziel Date: Wed, 6 May 2026 15:21:23 -0400 Subject: [PATCH 03/28] github: add needed variables and deps to CodeQL job Signed-off-by: Simon Deziel (cherry picked from commit 779e3b2f5591479f750e20cac7ab425bd2e0db28) --- .github/workflows/codeql.yml | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 1527b22f3..f4d85660d 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -19,6 +19,12 @@ on: schedule: - cron: '19 20 * * 5' +env: + CGO_CFLAGS: -I/home/runner/go/deps/dqlite/include/ + CGO_LDFLAGS: -L/home/runner/go/deps/dqlite/.libs/ + LD_LIBRARY_PATH: /home/runner/go/deps/dqlite/.libs/ + CGO_LDFLAGS_ALLOW: (-Wl,-wrap,pthread_create)|(-Wl,-z,now) + permissions: {} concurrency: @@ -59,6 +65,12 @@ jobs: with: persist-credentials: false + - name: Install Go + if: matrix.language == 'go' + uses: actions/setup-go@4a3601121dd01d1626a1e23e37211e3254c1c06c # v6.4.0 + with: + go-version-file: 'go.mod' + # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 @@ -71,21 +83,20 @@ jobs: # For more details on CodeQL's query packs, refer to: https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs # queries: security-extended,security-and-quality - # Autobuild attempts to build any compiled languages (C/C++, C#, Go, Java, or Swift). - # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild + if: matrix.language != 'go' uses: github/codeql-action/autobuild@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 - # ℹ️ Command-line programs to run using the OS shell. - # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun - - # If the Autobuild fails above, remove it and uncomment the following three lines. - # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. + - name: Install MicroCloud build dependencies + if: matrix.language == 'go' + uses: ./.github/actions/install-builddeps - # - run: | - # echo "Run, Build Application using script" - # ./location_of_script_within_repo/buildscript.sh + - name: Build + if: matrix.language == 'go' + run: | + make deps + make build - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 From 629d5eb47ec14510f19a5ac82b94c8e7bd908f20 Mon Sep 17 00:00:00 2001 From: Simon Deziel Date: Wed, 6 May 2026 16:01:59 -0400 Subject: [PATCH 04/28] github: split the dqlite libs/deps handling from the build Also, move them into place instead of copying them. Signed-off-by: Simon Deziel (cherry picked from commit 4f565c80dbfcd3d6b2e92838ca73ca216cbac824) --- .github/workflows/tests.yml | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 00aadb5d3..bc177d7a3 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -100,11 +100,6 @@ jobs: make deps make build-test - # Include dqlite libs in dependencies for system tests. - mkdir /home/runner/go/bin/dqlite - cp -r ~/go/deps/dqlite/include /home/runner/go/bin/dqlite/include - cp -r ~/go/deps/dqlite/.libs /home/runner/go/bin/dqlite/libs - - name: Run static analysis run: make check-static @@ -124,6 +119,13 @@ jobs: path: ${{env.GOCOVERDIR}} if: env.GOCOVERDIR != '' + - name: Prepare dqlite dependencies for system tests + run: | + # Include dqlite libs in dependencies for system tests. + mkdir /home/runner/go/bin/dqlite + mv ~/go/deps/dqlite/include /home/runner/go/bin/dqlite/include + mv ~/go/deps/dqlite/.libs /home/runner/go/bin/dqlite/libs + - name: Upload system test dependencies uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: From d77b1e33a8cf29f7db13b3e5ce1de894bec6f0f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20Peliz=C3=A4us?= Date: Mon, 8 Jun 2026 13:25:01 +0200 Subject: [PATCH 05/28] doc/conf: Add charmub.io to link ignore list MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julian Pelizäus (cherry picked from commit 58aef34f0456b6d61410198bcb5e84b00d1df55a) --- doc/conf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/conf.py b/doc/conf.py index d43895e78..7083cef84 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -132,6 +132,8 @@ 'http://localhost:8000', # These links may fail from time to time 'https://ceph.io', + # Rejects us always with a "Connection aborted" + r'https://charmhub\.io/.*', # Cloudflare protection on SourceForge domains often block linkcheck r'https://.*\.sourceforge\.(net|io)/.*', # These links often fail due to infra issues or protection measures From bd6f304588432d119ab8ba6b2b2d091009a69c6e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20Peliz=C3=A4us?= Date: Tue, 9 Jun 2026 10:52:35 +0200 Subject: [PATCH 06/28] cmd/microcloud/ask: Add concrete warning if MicroOVN cannot be configured MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should help in giving users a pointer that MicroOVN cannot be setup. Signed-off-by: Julian Pelizäus (cherry picked from commit ebbb6d14f2e2e031a6323e7efca21068d128839c) --- cmd/microcloud/ask.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd/microcloud/ask.go b/cmd/microcloud/ask.go index f2aba5766..33345656d 100644 --- a/cmd/microcloud/ask.go +++ b/cmd/microcloud/ask.go @@ -1106,6 +1106,10 @@ func (c *initConfig) askOVNNetwork(sh *service.Handler) error { } if warningMessage != "" { + // Be concrete and notify the user that we cannot configure MicroOVN at this stage. + tui.PrintWarning("Cannot configure MicroOVN") + + // Ask to continue and print a second warning here (the actual warning message) which contains some more reasoning. question := "Continue anyway?" wantsContinue, err := c.asker.AskBoolWarn(warningMessage, question, true) if err != nil { From 1507b38a19fe95f06f1e05341ab87c4a7a6f7a83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20Peliz=C3=A4us?= Date: Tue, 9 Jun 2026 10:54:16 +0200 Subject: [PATCH 07/28] cmd/microcloud/ask: Change default answer to no if MicroOVN setup failed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This should lead the user to stop the setup and fix what is written in the warning message. Or it can be answered with yes in which case we fall back to FAN networking. Signed-off-by: Julian Pelizäus (cherry picked from commit 88e72150e1118845bf84dbd0f793e44e2034af22) --- cmd/microcloud/ask.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/microcloud/ask.go b/cmd/microcloud/ask.go index 33345656d..a97ea1c8a 100644 --- a/cmd/microcloud/ask.go +++ b/cmd/microcloud/ask.go @@ -1111,7 +1111,7 @@ func (c *initConfig) askOVNNetwork(sh *service.Handler) error { // Ask to continue and print a second warning here (the actual warning message) which contains some more reasoning. question := "Continue anyway?" - wantsContinue, err := c.asker.AskBoolWarn(warningMessage, question, true) + wantsContinue, err := c.asker.AskBoolWarn(warningMessage, question, false) if err != nil { return err } From d94a98f8655d5261006f043a7fd7075c405f0239 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20Peliz=C3=A4us?= Date: Tue, 9 Jun 2026 15:39:59 +0200 Subject: [PATCH 08/28] AGENTS: Add instructions MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julian Pelizäus (cherry picked from commit f25eb35803c12166c5035b3d31abeadb87e4b7d8) --- AGENTS.md | 115 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 AGENTS.md diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 000000000..9c008f2a8 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,115 @@ +# AGENTS.md — MicroCloud Agent Instructions + +MicroCloud is an open source cloud platform written in Go. It orchestrates a cluster of machines by auto-configuring LXD, MicroCeph, and MicroOVN. Module: `github.com/canonical/microcloud/microcloud`. + +## Prerequisites + +MicroCloud requires Go 1.26.2 or higher. + +- CGO native dependency: `dqlite`. Fetch and build it once with: + + ``` + make deps + ``` + + This clones and builds the `dqlite` C library under `$GOPATH/deps/dqlite`. Set `CGO_CFLAGS`, `CGO_LDFLAGS`, and `LD_LIBRARY_PATH` accordingly if building outside of `make`. + +## Repository layout + +``` +api/ HTTP API handlers and request/response types + types/ Shared API type definitions +client/ Go client library for the MicroCloud API +cmd/ + microcloud/ CLI binary + microcloudd/ Daemon binary + tui/ Terminal UI library (tables, prompts, autocomplete) +database/ dqlite schema and CRUD helpers +multicast/ UDP multicast peer discovery +service/ Service interface and wrappers for LXD, MicroCeph, MicroOVN +test/ + suites/ System test suites (bash) + includes/ Shared shell helper functions + lint/ Shell lint scripts + e2e/ Post-deployment end-to-end tests (Terraform) +version/ Single source of truth for the version string +doc/ Sphinx documentation +``` + +### Auto-generated files — do not edit manually + +Update these via the listed `make` target instead of editing by hand: + +| File | Command | +| --- | --- | +| `go.mod`, `go.sum` | `make update-gomod` | + +## Build + +```sh +# Production build +make build + +# Test build (scripted TUI input, simplified wordlist) +make build-test +``` + +## Validate before committing + +Run these in order. Each must pass before moving to the next. + +```sh +# 1. Static analysis (golangci-lint, revive, shell lint scripts) +make check-static + +# 2. Unit tests +make check-unit + +# 3. Full build +make build +``` + +`make check-static` runs `golangci-lint`, `revive`, and the shell scripts under `test/lint/`. Review any reformatted files and stage only changes relevant to your work. + +## Key conventions + +### Commit format + +``` +: +``` + +Examples: +- `api/services: Use the authHandlerMTLS func` +- `cmd/microcloud: Remove token add command` +- `service/lxd: Fix storage pool bootstrap error handling` + +Use separate commits for each logical change and for changes to different components. See `CONTRIBUTING.md` for DCO sign-off (`git commit -s`) and GPG signature requirements. + +### Error messages + +- Use `"Cannot"` not `"Unable to"`. +- Capitalize the first letter of error strings: `fmt.Errorf("Cannot connect to ...")`. +- No contractions: `"does not"` not `"doesn't"`. +- US English spelling throughout (`behavior`, `color`, `initialize`, `organization`). + +### Go code style + +- No inline variable declarations inside `if` conditions — assign on a separate line first. +- Prefer early returns to reduce nesting. +- Import grouping (enforced by `gci`): stdlib → external → `github.com/canonical/microcloud/microcloud`. +- Check `service/` for existing helpers before implementing utilities from scratch. +- Both the `microcloud` CLI and `microcloudd` daemon enforce `os.Geteuid() == 0`; keep this behavior. + +### Shell test style + +- Use `jq --exit-status` (`jq -e`) when asserting field presence or values. +- For expected command failure: `if cmd_should_fail; then echo "ERROR: ..."; exit 1; fi` +- Use helper functions from `test/includes/microcloud.sh` (`validate_system_*`, `reset_systems`, etc.) rather than reimplementing validation logic. + +### Build tags + +| Tag | Purpose | +| --- | --- | +| `agent` | Production build | +| `test` | Enables `TEST_CONSOLE=1` scripted input and replaces the EFF wordlist with a small test wordlist | From 3d583a5ebbed38e98b51d9088bb3624967fd0b54 Mon Sep 17 00:00:00 2001 From: Elijah Greenstein Date: Tue, 9 Jun 2026 20:05:25 -0700 Subject: [PATCH 09/28] doc/conf.py: add to linkcheck_ignore Signed-off-by: Elijah Greenstein (cherry picked from commit 2245b1aea30232b8b628f3ac2bb5882fec8fe50d) --- doc/conf.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/doc/conf.py b/doc/conf.py index 7083cef84..41d02719c 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -138,6 +138,8 @@ r'https://.*\.sourceforge\.(net|io)/.*', # These links often fail due to infra issues or protection measures r'https://ubuntu\.com.*', + r'https://canonical\.com.*', + r'https://snapcraft\.io.*', # Ignore so that we can link change log in release notes before a release is ready r'https://github\.com/canonical/microcloud/compare.*', ] From c71c8b2d7c727c54dc3e770062257ed20d06365a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20Peliz=C3=A4us?= Date: Thu, 18 Jun 2026 09:38:09 +0200 Subject: [PATCH 10/28] doc/how-to/initialize: Clarify how to configure CephFS vols as image/backup store MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit A user might not be aware that it's crucial to set the config per cluster member. So instead of mentioning it at the bottom, use the --target key specifically. Otherwise a user would need to know that he needs to go to each cluster member to set the config key. Signed-off-by: Julian Pelizäus (cherry picked from commit 51a6f5de2ebe1b681fff49396cc577de6ca0c95e) --- doc/how-to/initialize.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/doc/how-to/initialize.md b/doc/how-to/initialize.md index 8d082a880..9c9076ef7 100644 --- a/doc/how-to/initialize.md +++ b/doc/how-to/initialize.md @@ -276,18 +276,18 @@ lxc storage volume create remote-fs backups # for instances operations lxc storage volume create remote-fs images # for images operations ``` -Once the storage volumes are created, set them as the values for the {ref}`configuration options ` of `storage.images_volume` and `storage.backups_volume`. This example syntax uses `remote-fs` as the storage pool, along with volumes named `images` and `backup`: +Once the storage volumes are created, set them as the values for the `storage.images_volume` and `storage.backups_volume` {ref}`configuration options `. +This example syntax uses `remote-fs` as the storage pool, along with volumes named `images` and `backups`. +Repeat these steps for each cluster member: ```bash -lxc config set storage.images_volume=remote-fs/images -lxc config set storage.backups_volume=remote-fs/backups +lxc config set storage.images_volume=remote-fs/images --target +lxc config set storage.backups_volume=remote-fs/backups --target ``` To view the set values, run: ```bash -lxc config get storage.backups_volume -lxc config get storage.images_volume +lxc config get storage.backups_volume --target +lxc config get storage.images_volume --target ``` - -Repeat these steps on each cluster member. From e900aee6895994785e286b1a242f09d90b3fa3f0 Mon Sep 17 00:00:00 2001 From: Maria Seralessandri Date: Wed, 24 Jun 2026 16:34:26 +0200 Subject: [PATCH 11/28] demos/terraform: Remove incompatible secure boot option Signed-off-by: Maria Seralessandri (cherry picked from commit 61dbc1a2b708ac66af8366cc48250c63157dfdf2) --- demos/terraform/main.tf | 1 - 1 file changed, 1 deletion(-) diff --git a/demos/terraform/main.tf b/demos/terraform/main.tf index 503169cee..7fcc56ac6 100644 --- a/demos/terraform/main.tf +++ b/demos/terraform/main.tf @@ -90,7 +90,6 @@ resource "lxd_instance" "microcloud" { } config = { - "security.secureboot" = "false" "cloud-init.user-data" = templatefile("${path.module}/cloud-init.yaml.tpl", { hostname = var.vm_names[count.index] lookup_interface = var.lookup_interface From db8c61cf563dcd1308cf069ad679a3c8fe015a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20Peliz=C3=A4us?= Date: Thu, 25 Jun 2026 15:49:13 +0200 Subject: [PATCH 12/28] doc/reference/release-snaps: Remove outdated statement about 3 track MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There are feature releases on the 3 track. Signed-off-by: Julian Pelizäus (cherry picked from commit 322f524298d3dfa6eb7256095759ec1569e8f7bb) --- doc/reference/releases-snaps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/reference/releases-snaps.md b/doc/reference/releases-snaps.md index 72406b500..a5775f64e 100644 --- a/doc/reference/releases-snaps.md +++ b/doc/reference/releases-snaps.md @@ -94,7 +94,7 @@ MicroCloud LTS tracks use the format _x.y_, corresponding to the major and minor The MicroCloud feature track uses the major number of the current {ref}`feature release ` series. Feature releases within the same major version are published to the same track, replacing the previous release. This simplifies updates, as you don't need to switch channels to access new feature releases within the same major version. -The current feature track is {{current_feature_track}}. No feature release has yet been published to this track. The most recent development updates can be found in the {{current_feature_track}}/`edge` channel, for testing purposes only. +The current feature track is {{current_feature_track}}. The most recent development updates can be found in the {{current_feature_track}}/`edge` channel, for testing purposes only. (ref-snaps-microcloud-track-default)= #### The default track From 9beedd5997af1e1db0cb6aa019e4d2bb22a709ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20Peliz=C3=A4us?= Date: Thu, 25 Jun 2026 16:19:01 +0200 Subject: [PATCH 13/28] doc/reference/releases-snaps: Don't use backticks on parts of the channel name MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julian Pelizäus (cherry picked from commit fabd97742a91921295662625d11e16a9e6b56e48) --- doc/reference/releases-snaps.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/reference/releases-snaps.md b/doc/reference/releases-snaps.md index a5775f64e..1610c8f9c 100644 --- a/doc/reference/releases-snaps.md +++ b/doc/reference/releases-snaps.md @@ -94,7 +94,7 @@ MicroCloud LTS tracks use the format _x.y_, corresponding to the major and minor The MicroCloud feature track uses the major number of the current {ref}`feature release ` series. Feature releases within the same major version are published to the same track, replacing the previous release. This simplifies updates, as you don't need to switch channels to access new feature releases within the same major version. -The current feature track is {{current_feature_track}}. The most recent development updates can be found in the {{current_feature_track}}/`edge` channel, for testing purposes only. +The current feature track is {{current_feature_track}}. The most recent development updates can be found in the {{current_feature_track}}/edge channel, for testing purposes only. (ref-snaps-microcloud-track-default)= #### The default track From e0f2271783b99ea1abed382cb1897dd11d539c81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20Peliz=C3=A4us?= Date: Wed, 18 Mar 2026 11:17:52 +0100 Subject: [PATCH 14/28] Revert "github/workflows/test: Use Canonical runners" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 6142647cacb9a05f823a7b8181e71cf1e8626f08. Also instead of 22.04 use 24.04. Signed-off-by: Julian Pelizäus (cherry picked from commit 6f7c9b99c310b031df9f38fb6cf51ba9b7f86b5f) --- .github/workflows/tests.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index bc177d7a3..1016a4191 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -143,7 +143,7 @@ jobs: SNAPSHOT_RESTORE: "1" if: ${{ github.repository_owner == 'canonical' }} name: System (core) - runs-on: self-hosted-linux-amd64-noble-large + runs-on: ubuntu-24.04 needs: code-tests strategy: fail-fast: false @@ -198,7 +198,7 @@ jobs: SNAPSHOT_RESTORE: "1" if: ${{ github.repository_owner == 'canonical' }} name: System (upgrade) - runs-on: self-hosted-linux-amd64-noble-large + runs-on: ubuntu-24.04 needs: code-tests strategy: fail-fast: false From 75ed6009db38bcb76bc2f98f877f85462404e6a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20Peliz=C3=A4us?= Date: Wed, 1 Jul 2026 11:42:17 +0200 Subject: [PATCH 15/28] test/e2e: Pin version of LXD provider MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julian Pelizäus (cherry picked from commit bb80a2b7305640c06416580b4e903def5c575789) --- test/e2e/versions.tf | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/e2e/versions.tf b/test/e2e/versions.tf index ddcbeb012..ccec0f917 100644 --- a/test/e2e/versions.tf +++ b/test/e2e/versions.tf @@ -3,7 +3,7 @@ terraform { required_providers { lxd = { source = "terraform-lxd/lxd" - version = ">= 2.5.0" + version = "2.7.1" } } } From 9631178f3288c4788e8f5f0e31cb93ec835c9bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20Peliz=C3=A4us?= Date: Wed, 1 Jul 2026 13:41:13 +0200 Subject: [PATCH 16/28] service/microceph: Use constant for long running job timeout MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julian Pelizäus (cherry picked from commit eced3d3bed7b56def085fd108a2e00ef7d6ff777) --- service/microceph.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/service/microceph.go b/service/microceph.go index 9b827c3ad..dc4adee18 100644 --- a/service/microceph.go +++ b/service/microceph.go @@ -22,6 +22,9 @@ import ( cloudClient "github.com/canonical/microcloud/microcloud/client" ) +// cephJobTimeout is the maximum time we allow for a Ceph job to complete before the context gets canceled. +const cephJobTimeout = 5 * time.Minute + // CephService is a MicroCeph service. type CephService struct { m *microcluster.MicroCluster @@ -148,7 +151,7 @@ func (s CephService) AddDisk(ctx context.Context, data cephTypes.DisksPost, targ // In the pipeline runners we often see runtimes > 1 minute. // To prevent any issues with slow environments set a more forgiving upper limit. // As long as the MicroCeph API doesn't return an error, the process is still running and we have to wait for it. - ctx, cancel = context.WithTimeout(ctx, 5*time.Minute) + ctx, cancel = context.WithTimeout(ctx, cephJobTimeout) defer cancel() err = c.Query(ctx, "POST", types.APIVersion, api.NewURL().Path("disks"), data, &response) From 761ce69657a86d0cd41aee7ea38bde189a160498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20Peliz=C3=A4us?= Date: Wed, 1 Jul 2026 13:41:33 +0200 Subject: [PATCH 17/28] service/microceph: Allow longer runtime for setting pool replication factor MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julian Pelizäus (cherry picked from commit a2606dc54c640423f186d26f686bb2ec2e8df1aa) --- service/microceph.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/service/microceph.go b/service/microceph.go index dc4adee18..ed1c4e143 100644 --- a/service/microceph.go +++ b/service/microceph.go @@ -235,6 +235,11 @@ func (s CephService) PoolSetReplicationFactor(ctx context.Context, data cephType return err } + // On the GH runners it was observed that setting the pool replication factor can take + // longer than the default of 30s if no deadline is set on the context. + ctx, cancel := context.WithTimeout(ctx, cephJobTimeout) + defer cancel() + err = c.Query(ctx, "PUT", types.APIVersion, api.NewURL().Path("pools-op"), data, nil) if err != nil { return fmt.Errorf("Failed setting replication factor: %w", err) From d659b5849049723db347683592d56d9f33ab7472 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20Peliz=C3=A4us?= Date: Thu, 2 Jul 2026 14:44:17 +0200 Subject: [PATCH 18/28] github/workflows/security: Drop 1 due to EOL MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julian Pelizäus (cherry picked from commit a8104149a395b891b903e43cb22b53f917b757d1) --- .github/workflows/security.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 9987595a6..0474105d4 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -83,9 +83,6 @@ jobs: - channel: "2/stable" branch: "v2-edge" version: "2" - - channel: "1/stable" - branch: "v1-edge" - version: "1" steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 From 3beb43e6847622327314ce21b2c6eab9ff213edd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20Peliz=C3=A4us?= Date: Thu, 2 Jul 2026 14:50:02 +0200 Subject: [PATCH 19/28] github/workflows/security: Align trivy job with LXD MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Julian Pelizäus (cherry picked from commit df4823823f810871f0f7927c121a0f6024cb3d4f) --- .github/workflows/security.yml | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 0474105d4..6f242c0be 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -76,18 +76,14 @@ jobs: if: ${{ ( github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' ) && github.ref_name == 'main' && github.repository_owner == 'canonical' }} strategy: matrix: - include: - - channel: "3/edge" - branch: "main" - version: "3" - - channel: "2/stable" - branch: "v2-edge" - version: "2" + version: + - "latest" + - "2" steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - ref: ${{ matrix.branch }} + ref: ${{ (matrix.version == 'latest' && 'main') || format('v{0}-edge', matrix.version) }} persist-credentials: false - name: Resolve branch HEAD SHA @@ -137,4 +133,4 @@ jobs: with: sarif_file: ${{ matrix.version }}-stable.sarif sha: ${{ steps.branch-sha.outputs.sha }} - ref: refs/heads/${{ matrix.branch }} + ref: refs/heads/${{ (matrix.version == 'latest' && 'main') || format('v{0}-edge', matrix.version) }} From 73abc6292fde1d215c29e5b2048f47293623bb2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20Peliz=C3=A4us?= Date: Thu, 2 Jul 2026 17:02:21 +0200 Subject: [PATCH 20/28] Revert "test/e2e/reboot: Add temporary fix for MicroOVN northd issue" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit 5f5c8a82fb9af088dd03cf40db392422ebd4057f. Signed-off-by: Julian Pelizäus (cherry picked from commit 7e0a1bf672d862e952421a59b277f4a98115e391) --- test/e2e/reboot.local-lxd-vm | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/test/e2e/reboot.local-lxd-vm b/test/e2e/reboot.local-lxd-vm index addbf9e85..b914ad2ed 100755 --- a/test/e2e/reboot.local-lxd-vm +++ b/test/e2e/reboot.local-lxd-vm @@ -33,14 +33,3 @@ lxc exec "${MEMBER}" -- timeout 90 systemctl is-system-running --wait --quiet || sleep 5 lxc exec "${MEMBER}" --env TEST_CONSOLE=0 -- microcloud waitready --timeout=90 || true echo " DONE" - -# Temporary fix to deal with https://github.com/canonical/microovn/pull/249. -# -# First try to find the cluster member which joined last and restart its ovn-northd service. -# We can identify it based on its appearance in Microcluster's `core_cluster_members` table. -# The CLI's `microovn cluster list` cannot be used as the result is sorted. -# MicroCloud doesn't guarantee any order in which members are joined and doesn't sort them by name (as they are internally stored inside a map). -last_member="$(lxc exec "${MEMBER}" -- microovn cluster sql 'SELECT name FROM core_cluster_members ORDER BY ID DESC LIMIT 1' | awk -F" " '/micro/ { print $2 }')" - -# Second restart ovn-northd on this member. -lxc exec "${last_member}" -- systemctl restart snap.microovn.ovn-northd.service From 949aa1fd99473cfe5cafc9aaaee0b76de3167803 Mon Sep 17 00:00:00 2001 From: Maria Seralessandri Date: Wed, 24 Jun 2026 16:07:04 +0200 Subject: [PATCH 21/28] demos/terraform: Rename network resource from microbr0 to microbr Signed-off-by: Maria Seralessandri (cherry picked from commit 91f0fbe3f1219162fc57976ad6228f0f1c0138e5) --- demos/terraform/main.tf | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/demos/terraform/main.tf b/demos/terraform/main.tf index 7fcc56ac6..6325fa03c 100644 --- a/demos/terraform/main.tf +++ b/demos/terraform/main.tf @@ -45,7 +45,7 @@ locals { } } -resource "lxd_network" "microbr0" { +resource "lxd_network" "microbr" { name = var.network_name config = { @@ -122,7 +122,7 @@ resource "lxd_instance" "microcloud" { type = "nic" properties = { nictype = "bridged" - parent = lxd_network.microbr0.name + parent = lxd_network.microbr.name } } @@ -203,7 +203,7 @@ resource "lxd_instance" "microcloud" { depends_on = [ data.lxd_network.lookup_bridge, - lxd_network.microbr0, + lxd_network.microbr, lxd_volume.local_disk, lxd_volume.ceph_disk ] From f841adc35d062b9c526a9d846b29287c3242f112 Mon Sep 17 00:00:00 2001 From: Maria Seralessandri Date: Wed, 24 Jun 2026 16:07:33 +0200 Subject: [PATCH 22/28] demos/terraform: Simplify disk numbering in main.tf Signed-off-by: Maria Seralessandri (cherry picked from commit 92a02f282093c4ed02190b65fab8685f2f34a021) --- demos/terraform/main.tf | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/demos/terraform/main.tf b/demos/terraform/main.tf index 6325fa03c..25dc7a43a 100644 --- a/demos/terraform/main.tf +++ b/demos/terraform/main.tf @@ -32,17 +32,14 @@ locals { systems = [ for i, name in var.vm_names : { - name = name - ip = cidrhost(local.lookup_subnet, var.ip_base_offset + (i * var.ip_increment)) - has_ceph = contains(var.ceph_nodes, name) + name = name + ip = cidrhost(local.lookup_subnet, var.ip_base_offset + (i * var.ip_increment)) + has_ceph = contains(var.ceph_nodes, name) + disk_number = var.disk_number_start + i } ] - ceph_disk_mapping = { - for i, system in local.systems : i => length([ - for j, s in local.systems : j if j < i && s.has_ceph - ]) if system.has_ceph - } + ceph_systems = [for s in local.systems : s if s.has_ceph] } resource "lxd_network" "microbr" { @@ -57,8 +54,8 @@ resource "lxd_network" "microbr" { } resource "lxd_volume" "local_disk" { - count = var.vm_count - name = "${var.local_disk_name_prefix}${count.index + 1}" + count = length(local.systems) + name = "${var.local_disk_name_prefix}${local.systems[count.index].disk_number}" pool = var.storage_pool type = "custom" content_type = "block" @@ -68,8 +65,8 @@ resource "lxd_volume" "local_disk" { } resource "lxd_volume" "ceph_disk" { - count = length([for system in local.systems : system if system.has_ceph]) - name = "${var.ceph_disk_name_prefix}${count.index + 1}" + count = length(local.ceph_systems) + name = "${var.ceph_disk_name_prefix}${local.ceph_systems[count.index].disk_number}" pool = var.storage_pool type = "custom" content_type = "block" @@ -79,7 +76,7 @@ resource "lxd_volume" "ceph_disk" { } resource "lxd_instance" "microcloud" { - count = var.vm_count + count = length(local.systems) name = var.vm_names[count.index] image = var.ubuntu_image type = "virtual-machine" @@ -142,7 +139,7 @@ resource "lxd_instance" "microcloud" { type = "disk" properties = { pool = var.storage_pool - source = lxd_volume.ceph_disk[local.ceph_disk_mapping[count.index]].name + source = lxd_volume.ceph_disk[index(local.ceph_systems[*].name, local.systems[count.index].name)].name } } } From 4a3eb12738e040213356cbaf60b6aead8580ae68 Mon Sep 17 00:00:00 2001 From: Maria Seralessandri Date: Wed, 24 Jun 2026 16:08:13 +0200 Subject: [PATCH 23/28] demos/terraform: Add disk_number_start variable in variables.tf Signed-off-by: Maria Seralessandri (cherry picked from commit 2498120c6125555b28ab9d4479b61d8898eb3ae3) --- demos/terraform/variables.tf | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/demos/terraform/variables.tf b/demos/terraform/variables.tf index 9525e96c0..662ae46ec 100644 --- a/demos/terraform/variables.tf +++ b/demos/terraform/variables.tf @@ -148,13 +148,6 @@ variable "lookup_bridge" { default = "lxdbr0" } - -variable "vm_count" { - description = "Number of VMs to create" - type = number - default = 4 -} - variable "ip_base_offset" { description = "Base IP address offset for the first VM" type = number @@ -179,6 +172,12 @@ variable "ceph_disk_name_prefix" { default = "remote" } +variable "disk_number_start" { + description = "Starting number for disk names (e.g., 1 for local1/remote1, 5 for local5/remote5)" + type = number + default = 1 +} + variable "initiator" { description = "Name of the initiator node for MicroCloud cluster (matches preseed initiator)" type = string From b1ee357bfc2fdf366675c94ce537b7f1eba9fcbb Mon Sep 17 00:00:00 2001 From: Maria Seralessandri Date: Wed, 24 Jun 2026 16:08:28 +0200 Subject: [PATCH 24/28] demos/terraform: Add disk_number_start in terraform.tfvars.example Signed-off-by: Maria Seralessandri (cherry picked from commit 7eca35423721f5eb57337bada95005aea7e7c125) --- demos/terraform/terraform.tfvars.example | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/demos/terraform/terraform.tfvars.example b/demos/terraform/terraform.tfvars.example index a82a4bd6a..f8f58427d 100644 --- a/demos/terraform/terraform.tfvars.example +++ b/demos/terraform/terraform.tfvars.example @@ -22,7 +22,6 @@ lookup_timeout = 300 instance_create_timeout = "25m" # VM Configuration -vm_count = 4 vm_names = ["micro1", "micro2", "micro3", "micro4"] ceph_nodes = ["micro1", "micro2", "micro3"] @@ -46,6 +45,7 @@ ip_increment = 10 # Disk Name Configuration local_disk_name_prefix = "local" ceph_disk_name_prefix = "remote" +disk_number_start = 1 # MicroCloud Configuration initiator = "micro1" From 5a18f322d3c5af401293248bfef8f02d80c5980f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Julian=20Peliz=C3=A4us?= Date: Fri, 3 Jul 2026 09:57:55 +0200 Subject: [PATCH 25/28] github/workflows/security: Account for non existing latest/ track MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In MicroCloud we don't use latest/ track but instead only track numbers. Only latest/edge get populated. Signed-off-by: Julian Pelizäus (cherry picked from commit 0e23a209e35e18d7663f5f5c7563dba49b4be880) --- .github/workflows/security.yml | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 6f242c0be..ee3fefe09 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -76,14 +76,16 @@ jobs: if: ${{ ( github.event_name == 'workflow_dispatch' || github.event_name == 'schedule' ) && github.ref_name == 'main' && github.repository_owner == 'canonical' }} strategy: matrix: - version: - - "latest" - - "2" + include: + - track: 3 + branch: main + - track: 2 + branch: v2-edge steps: - name: Checkout uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: - ref: ${{ (matrix.version == 'latest' && 'main') || format('v{0}-edge', matrix.version) }} + ref: ${{ matrix.branch }} persist-credentials: false - name: Resolve branch HEAD SHA @@ -94,7 +96,7 @@ jobs: env: SNAP_NAME: ${{ github.event.repository.name }} run: | - snap download "${SNAP_NAME}" --channel=${{ matrix.version }}/stable --cohort="+" + snap download "${SNAP_NAME}" --channel=${{ matrix.track }}/stable --cohort="+" unsquashfs ./${SNAP_NAME}*.snap - name: Run Trivy vulnerability scanner @@ -105,7 +107,7 @@ jobs: scanners: vuln,secret,misconfig format: sarif severity: LOW,MEDIUM,HIGH,CRITICAL - output: ${{ matrix.version }}-stable.sarif + output: ${{ matrix.branch }}.sarif - name: Flag snap scanning alerts and tag KEV alerts run: | @@ -125,12 +127,12 @@ jobs: else . end - )' ${{ matrix.version }}-stable.sarif > ${{ matrix.version }}-modified.sarif - mv ${{ matrix.version }}-modified.sarif ${{ matrix.version }}-stable.sarif + )' ${{ matrix.branch }}.sarif > ${{ matrix.branch }}-modified.sarif + mv ${{ matrix.branch }}-modified.sarif ${{ matrix.branch }}.sarif - name: Upload Trivy scan results to GitHub Security tab uses: github/codeql-action/upload-sarif@f205ea1c3313d32999d8d6a48b4f6530d4437b38 # v4.37.4 with: - sarif_file: ${{ matrix.version }}-stable.sarif + sarif_file: ${{ matrix.branch }}.sarif sha: ${{ steps.branch-sha.outputs.sha }} - ref: refs/heads/${{ (matrix.version == 'latest' && 'main') || format('v{0}-edge', matrix.version) }} + ref: refs/heads/${{ matrix.branch }} From aa77953424a3b50842ea12e1c5a3f30298a5cf7d Mon Sep 17 00:00:00 2001 From: Elijah Greenstein Date: Thu, 25 Jun 2026 10:39:29 -0700 Subject: [PATCH 26/28] doc: detail number of nodes in about page Signed-off-by: Elijah Greenstein (cherry picked from commit 56456039e9b299cc1739b4b67597de75be2661fe) --- doc/explanation/microcloud.md | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/doc/explanation/microcloud.md b/doc/explanation/microcloud.md index b9c3371bf..3f370c0a0 100644 --- a/doc/explanation/microcloud.md +++ b/doc/explanation/microcloud.md @@ -10,9 +10,7 @@ myst: The MicroCloud snap drives three other snaps ({doc}`lxd:index`, {doc}`microceph:index`, and {doc}`microovn:index`), enabling automated deployment of a highly available LXD cluster for compute, with Ceph as the storage driver and OVN as the managed network. -During initialization, MicroCloud scrapes the other servers for details and then prompts you to add disks to Ceph and configure the networking setup. - -At the end of this, you’ll have an OVN cluster, a Ceph cluster, and a LXD cluster. LXD itself will have been configured with both networking and storage suitable for use in a cluster. +MicroCloud starts with a single cluster member, requires 3 members for {ref}`high availability `, and can scale to 50-member clusters. During initialization, MicroCloud scrapes the other servers for details and then prompts you to add disks to Ceph and configure the networking setup. At the end of this, you’ll have an OVN cluster, a Ceph cluster, and a LXD cluster. LXD itself will have been configured with both networking and storage suitable for use in a cluster. (exp-microcloud-lxd)= ## LXD cluster From 23ba9567a5a2eede6dddcede45f32afe495cd2f3 Mon Sep 17 00:00:00 2001 From: Elijah Greenstein Date: Thu, 4 Jun 2026 20:51:15 -0700 Subject: [PATCH 27/28] doc/conf.py: temporarily remove "edit page" button This commit removes the "Contribute to this page" button. This change is temporary, and the button will be restored after the docs have moved to canonical.com. Signed-off-by: Elijah Greenstein (cherry picked from commit bcb0d2d2dd57111ad7fb33a86f6d30500a1a1550) --- doc/conf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 41d02719c..29fd50e23 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -75,9 +75,9 @@ } # Enables the pencil icon to edit pages on GitHub, shown at the top of each page -html_theme_options = { - 'source_edit_link': html_context['github_url'] -} +# html_theme_options = { +# 'source_edit_link': html_context['github_url'] +# } ####################### # Sitemap configuration: https://sphinx-sitemap.readthedocs.io/ From 2beea96672bca90e7f2a8d1dfe43823f0fcf2aea Mon Sep 17 00:00:00 2001 From: Elijah Greenstein Date: Tue, 14 Jul 2026 21:15:41 -0700 Subject: [PATCH 28/28] doc/conf.py: restore "edit page" button Signed-off-by: Elijah Greenstein (cherry picked from commit 73189dee63b89120aa8c7c6264f1e5c3e78db64c) --- doc/conf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/conf.py b/doc/conf.py index 29fd50e23..41d02719c 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -75,9 +75,9 @@ } # Enables the pencil icon to edit pages on GitHub, shown at the top of each page -# html_theme_options = { -# 'source_edit_link': html_context['github_url'] -# } +html_theme_options = { + 'source_edit_link': html_context['github_url'] +} ####################### # Sitemap configuration: https://sphinx-sitemap.readthedocs.io/