Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e88dad8
github: ask CodeQL to also look after GH actions
simondeziel May 6, 2026
6048a63
github: add `concurrency` and top level `permissions` to CodeQL workflow
simondeziel May 6, 2026
38678f7
github: add needed variables and deps to CodeQL job
simondeziel May 6, 2026
629d5eb
github: split the dqlite libs/deps handling from the build
simondeziel May 6, 2026
d77b1e3
doc/conf: Add charmub.io to link ignore list
roosterfish Jun 8, 2026
bd6f304
cmd/microcloud/ask: Add concrete warning if MicroOVN cannot be config…
roosterfish Jun 9, 2026
1507b38
cmd/microcloud/ask: Change default answer to no if MicroOVN setup failed
roosterfish Jun 9, 2026
d94a98f
AGENTS: Add instructions
roosterfish Jun 9, 2026
3d583a5
doc/conf.py: add to linkcheck_ignore
elijahgreenstein Jun 10, 2026
c71c8b2
doc/how-to/initialize: Clarify how to configure CephFS vols as image/…
roosterfish Jun 18, 2026
e900aee
demos/terraform: Remove incompatible secure boot option
mseralessandri Jun 24, 2026
db8c61c
doc/reference/release-snaps: Remove outdated statement about 3 track
roosterfish Jun 25, 2026
9beedd5
doc/reference/releases-snaps: Don't use backticks on parts of the cha…
roosterfish Jun 25, 2026
e0f2271
Revert "github/workflows/test: Use Canonical runners"
roosterfish Mar 18, 2026
75ed600
test/e2e: Pin version of LXD provider
roosterfish Jul 1, 2026
9631178
service/microceph: Use constant for long running job timeout
roosterfish Jul 1, 2026
761ce69
service/microceph: Allow longer runtime for setting pool replication …
roosterfish Jul 1, 2026
d659b58
github/workflows/security: Drop 1 due to EOL
roosterfish Jul 2, 2026
3beb43e
github/workflows/security: Align trivy job with LXD
roosterfish Jul 2, 2026
73abc62
Revert "test/e2e/reboot: Add temporary fix for MicroOVN northd issue"
roosterfish Jul 2, 2026
949aa1f
demos/terraform: Rename network resource from microbr0 to microbr
mseralessandri Jun 24, 2026
f841adc
demos/terraform: Simplify disk numbering in main.tf
mseralessandri Jun 24, 2026
4a3eb12
demos/terraform: Add disk_number_start variable in variables.tf
mseralessandri Jun 24, 2026
b1ee357
demos/terraform: Add disk_number_start in terraform.tfvars.example
mseralessandri Jun 24, 2026
5a18f32
github/workflows/security: Account for non existing latest/ track
roosterfish Jul 3, 2026
aa77953
doc: detail number of nodes in about page
elijahgreenstein Jun 25, 2026
23ba956
doc/conf.py: temporarily remove "edit page" button
elijahgreenstein Jun 5, 2026
2beea96
doc/conf.py: restore "edit page" button
elijahgreenstein Jul 15, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 28 additions & 11 deletions .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,18 @@ 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:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true

jobs:
analyze:
if: ${{ github.repository_owner == 'canonical' }}
Expand All @@ -41,7 +53,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
Expand All @@ -53,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
Expand All @@ -65,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
Expand Down
23 changes: 9 additions & 14 deletions .github/workflows/security.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,15 +77,10 @@ jobs:
strategy:
matrix:
include:
- channel: "3/edge"
branch: "main"
version: "3"
- channel: "2/stable"
branch: "v2-edge"
version: "2"
- channel: "1/stable"
branch: "v1-edge"
version: "1"
- track: 3
branch: main
- track: 2
branch: v2-edge
steps:
- name: Checkout
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
Expand All @@ -101,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
Expand All @@ -112,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: |
Expand All @@ -132,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.branch }}
16 changes: 9 additions & 7 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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:
Expand All @@ -141,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
Expand Down Expand Up @@ -196,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
Expand Down
115 changes: 115 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -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

```
<component/subcomponent>: <concise change description>
```

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 |
6 changes: 5 additions & 1 deletion cmd/microcloud/ask.go
Original file line number Diff line number Diff line change
Expand Up @@ -1106,8 +1106,12 @@ 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)
wantsContinue, err := c.asker.AskBoolWarn(warningMessage, question, false)
if err != nil {
return err
}
Expand Down
32 changes: 14 additions & 18 deletions demos/terraform/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -32,20 +32,17 @@ 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" "microbr0" {
resource "lxd_network" "microbr" {
name = var.network_name

config = {
Expand All @@ -57,8 +54,8 @@ resource "lxd_network" "microbr0" {
}

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"
Expand All @@ -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"
Expand All @@ -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"
Expand All @@ -90,7 +87,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
Expand Down Expand Up @@ -123,7 +119,7 @@ resource "lxd_instance" "microcloud" {
type = "nic"
properties = {
nictype = "bridged"
parent = lxd_network.microbr0.name
parent = lxd_network.microbr.name
}
}

Expand All @@ -143,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
}
}
}
Expand Down Expand Up @@ -204,7 +200,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
]
Expand Down
Loading
Loading