magogi/prod/: mgf-cloud-provision-0.1.3 metadata and description

Simple index

Declarative, idempotent provisioning of the Magogi Foundation's self-hosted services (devpi, CI agents, Vault, …) on top of mgf-cloud. plan / apply / destroy over a ServiceSpec. Sibling of mgf-cloud under the mgf.* namespace.

author Bassam Alsanie, mgf-cloud-provision contributors
classifiers
  • Development Status :: 2 - Pre-Alpha
  • Intended Audience :: System Administrators
  • License :: OSI Approved :: Apache Software License
  • Operating System :: POSIX :: Linux
  • Programming Language :: Python :: 3
  • Programming Language :: Python :: 3.11
  • Programming Language :: Python :: 3.12
  • Programming Language :: Python :: 3.13
  • Topic :: System :: Systems Administration
  • Typing :: Typed
description_content_type text/markdown
keywords cloud, iac, infomaniak, infrastructure, openstack, provisioning
license Apache-2.0
license_file
  • LICENSE
  • NOTICE
project_urls
  • Homepage, https://codeberg.org/magogi-admin/mgf-cloud-provision
  • Issues, https://codeberg.org/magogi-admin/mgf-cloud-provision/issues
  • Changelog, https://codeberg.org/magogi-admin/mgf-cloud-provision/src/branch/main/CHANGELOG.md
requires_dist
  • mgf-cloud<0.2,>=0.1.1
  • mgf-common<1.0,>=0.47
  • pydantic<3,>=2.6
  • import-linter<3.0,>=2.0; extra == 'dev'
  • mgf-standard<0.2,>=0.1.6; extra == 'dev'
  • mgf-test-supervisor<0.2,>=0.1.3; extra == 'dev'
  • mypy>=1.10; extra == 'dev'
  • pytest-cov>=5.0; extra == 'dev'
  • pytest-timeout<3,>=2.3; extra == 'dev'
  • pytest>=8.0; extra == 'dev'
  • ruff<0.16,>=0.4; extra == 'dev'
  • mgf-cloud[infomaniak]<0.2,>=0.1.1; extra == 'infomaniak'
  • mgf-common[standards]<1.0,>=0.47; extra == 'standards'
requires_python >=3.11

Because this project isn't in the mirror_whitelist, no releases from root/pypi are included.

File Tox results History
mgf_cloud_provision-0.1.3-py3-none-any.whl
Size
32 KB
Type
Python Wheel
Python
3
mgf_cloud_provision-0.1.3.tar.gz
Size
217 KB
Type
Source

mgf-cloud-provision

Shape. Magogi Foundation infrastructure library. Declarative, idempotent provisioning of the federation's own self-hosted services on Infomaniak Public Cloud. Status. Pre-0.1.0 skeleton (Phase 1a). The core API + the devpi service spec exist and run end-to-end against mgf-cloud's in-memory FakeProvider; the live provider + cloud-init converge land in Phase 1b.

mgf-cloud-provision sits above mgf-cloud (the OpenStack/Infomaniak adapter). Where mgf-cloud is "talk to OpenStack," this is "declare + converge our services." A ServiceSpec describes the desired state of one service-bearing VM (devpi, a CI agent, Vault, …) as a VM + cloud-init; plan / apply / destroy converge the cloud to it.

from mgf.cloud.providers import get_provider
from mgf.cloud_provision import devpi_service_spec, plan, apply

spec = devpi_service_spec(key_name="woodpecker-key")
print(plan(spec, get_provider("fake")).action)      # Action.CREATE
apply(spec, get_provider("fake"))                    # creates the VM (fake, in-memory)

CLI:

mgf-cloud-provision plan    examples/devpi.toml --provider fake
mgf-cloud-provision apply   examples/devpi.toml --provider fake --yes
mgf-cloud-provision destroy examples/devpi.toml --provider fake --yes
mgf-cloud-provision ci-host --dry-run                # the Woodpecker CI host (built-in spec)
mgf-cloud-provision ci-host --with-agent --yes       # … + woodpecker-agent2

The whole surface runs with no cloud and no credentials (the fake provider), so it is fully testable in CI. The real provider (--provider infomaniak) loads credentials via mgf.cloud.config.load.

First customer — devpi

The reason this library exists now is the self-hosted package index rollout (replacing the Codeberg PyPI registry — closes the dependency-confusion findings of the 2026-06-18 CI audit). devpi_service_spec() / examples/devpi.toml encode the Phase-0-resolved sizing: a2-ram4-disk50-perf1 on ext-net1, reachable at <ip>.sslip.io. See the rollout plan in ~/.claude/plans/plan-self-hosted-pypi-sequencing-2026-06-18.md.

CI host — Woodpecker

Full operator runbook: docs/woodpecker-ci-runbook.md (architecture, hosts/access, secrets, self-healing, operations, failure-mode catalogue, rebuild). Backups + restore: docs/backup-restore-runbook.md (nightly recipes in backups/, heartbeats, RPO/RTO, per-store restore procedures).

mgf-cloud-provision ci-host (absorbed from the deprecated mgf-fed provision-ci-host — Wave-2 P0.4, one provisioner) provisions the server VM with the current production bundle rendered into its cloud-init, and --with-agent converges woodpecker-agent2 in the same run. The packaged bundle is byte-pinned by the unit tests to examples/, so the verb can never again render a stale topology.

The federation's self-hosted Woodpecker CI runs from examples/woodpecker-compose.yml (server + Postgres + agent + Caddy auto-TLS) — the sanitized live /opt/woodpecker compose, with every secret a ${VAR} sourced from .env (template: examples/woodpecker.env.example). The server was migrated SQLite → Postgres on 2026-06-21 to remove the single-writer "database is locked" ceiling that surfaced under fleet-wide CI bursts. The two-vhost Caddyfile (examples/woodpecker-Caddyfile) serves the web UI/API and the grpc.<domain> h2c endpoint remote agents dial.

A second agent on its own VM (examples/woodpecker-agent.toml + examples/woodpecker-agent-cloud-init.yml) removes the single-agent / single-Docker-daemon ceiling — it connects to the server's gRPC over TLS (a Caddy h2c proxy at grpc.<server-domain>:443; WOODPECKER_GRPC_SECURE=true). The shared WOODPECKER_AGENT_SECRET and the netrc are injected post-provision over SSH, never committed. Fleet capacity is now 2 agents × MAX_WORKFLOWS=2 = 4 concurrent workflows.

Two self-healing crons keep the agents honest — canonical home ops/ (co-located here in Wave-2 P0; the mgf-fed copies are deprecated): ops/self-heal.sh (every 5 min, reaps leaked wp_* Docker debris from daemon-teardown timeouts) and ops/agent-reconciler.py (every 3 min on the server host) — the reconciler recovers the "connected but not scheduling" state (an agent whose server-side worker slots were orphaned, sitting idle while work pends) by restarting that agent (local docker compose, or agent2 over SSH). It reads its API token + agent2 SSH key from root-600 files on the host (/opt/woodpecker/reconciler.token, /opt/woodpecker/agent2_id), never committed; cron: */3 * * * * python3 /opt/woodpecker/agent-reconciler.py.

Four green gates

ruff check src tests
mypy src
pytest --cov --cov-fail-under=80
lint-imports

Roadmap

License

MIT.