Run the Manager locally (make dev) via a NodeApi abstraction + DummyApi#353
Merged
Conversation
e27a110 to
9f7346a
Compare
Contributor
There was a problem hiding this comment.
Pull request overview
This PR makes the Manager runnable standalone on localhost via make dev, adding a provider abstraction (Node.api() dispatching by nodeType) and a DummyApi so container creation can exercise the real job-runner path without needing Proxmox.
Changes:
- Add
nodeTypewithNode.api()dispatch (proxmoxvsdummy) and implementDummyApito simulate hypervisor calls. - Introduce
make dev+bin/dev-bootstrap.jsto bootstrap a local SQLite dev environment and run server + job-runner together. - Add a
patch-packagebackport patch for Sequelize SQLite composite-index uniqueness behavior and gate Sequelize SQL logging behindLOG_LEVEL=trace.
Reviewed changes
Copilot reviewed 14 out of 16 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
| README.md | Updates docs pointer to highlight make dev workflow. |
| mie-opensource-landing/docs/developers/development-workflow.md | Adds a dedicated make dev section and reorganizes Docker-stack guidance. |
| Makefile | Adds dev target to install, migrate, bootstrap, build, and run server + job-runner. |
| create-a-container/utils/dummy-api.js | Introduces DummyApi implementing the NodeApi/ProxmoxApi method surface for local runs. |
| create-a-container/routers/api/v1/containers.js | Makes node selection provider-agnostic and routes delete teardown through node.api(). |
| create-a-container/patches/sequelize+6.37.8.patch | Adds a patch-package patch for Sequelize v6 SQLite query-interface uniqueness handling. |
| create-a-container/package.json | Adds postinstall patch-package hook and updates db migration script to sequelize-cli. |
| create-a-container/package-lock.json | Locks patch-package and its transitive dependencies. |
| create-a-container/models/node.js | Adds nodeType field and Node.api() dispatch to DummyApi vs ProxmoxApi. |
| create-a-container/migrations/20260605000000-add-node-type-to-nodes.js | Adds nodeType column with default proxmox. |
| create-a-container/example.env | Documents LOG_LEVEL behavior for SQL query logging. |
| create-a-container/config/config.js | Gates Sequelize SQL logging behind LOG_LEVEL=trace (including production). |
| create-a-container/bin/dev-bootstrap.js | Seeds an empty DB with a localhost site, dummy node, and localhost external domain. |
Files not reviewed (1)
- create-a-container/package-lock.json: Generated file
… + DummyApi
Run the Manager standalone on localhost (SQLite, `make dev`) and create
containers without Proxmox, keeping the real provisioning code path.
- NodeApi abstraction: Node.api() dispatches on a new `nodeType` column.
`proxmox` (default) returns ProxmoxApi; `dummy` returns a new DummyApi that
implements the same surface and simulates Proxmox calls. Creation still runs
POST /containers -> Job -> job-runner -> bin/create-container.js -> node.api().
- DummyApi.clusterResources('lxc') derives the running set from the DB so the
live container-status resolver (#352) reports dummy containers correctly;
dev-bootstrap gives the dummy node placeholder creds so nodeHasCreds() passes.
- Provider-agnostic node selection that only excludes unprovisionable nodes
(dummy, or proxmox with apiUrl/tokenId/secret); DELETE routes teardown through
node.api(). Node.api() validates apiUrl alongside credentials.
- Postgres-safe migration adding `nodeType` (existing rows default to proxmox).
- Fix the erroneous UNIQUE on Containers.nodeId via patch-package (v6 backport of
sequelize/sequelize#17583); replaces the SQLite-specific migration.
- bin/dev-bootstrap.js seeds a localhost site + dummy node + external domain,
no-op if any Site exists, so it never clobbers the docker-compose bootstrap.
- Make idempotent seeders (groups, push-notification) so re-running them in
`make dev` doesn't violate unique constraints.
- Gate Sequelize SQL query logging behind LOG_LEVEL=trace; off otherwise.
- Replace the unmaintained sqlite3 with @vscode/sqlite3 (dev-only, builds from
source via dialectModule) so there is no prebuilt-binary glibc mismatch; prod
(Postgres) never installs or loads it.
- `make dev` lives in create-a-container/Makefile (root delegates): self-contained
install (--no-package-lock, so it never rewrites the lockfile), migrate, seed,
then run server (nodemon) + job-runner + client watch together.
- Docs: "Run the Manager Locally (make dev)" section; README + release-pipeline
pointers; LOG_LEVEL documented in example.env.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Rebased onto current
main(which now includes #347, #351, and #352). This PR is a single commit with no upstream-PR duplication.Why
Supersedes #329. That PR made the Manager runnable on
localhostbut did so in ways flagged in review: a mock that bypassed the job-runner, in-band signaling (apiUrl === 'local'), a SQLite-specific migration, and dev-login provisioning that clobbered the Docker Compose bootstrap.This reworks the same goal — run the Manager standalone and create containers without Proxmox — but addresses the root causes and keeps the real provisioning code path intact. It also lays the groundwork for additional production-capable node providers behind a single
NodeApiabstraction (starting with the dummy provider).What changed
1.
NodeApiabstraction (ProxmoxApi+ newDummyApi)Node.api()now dispatches on a newnodeTypecolumn:proxmox(default) → authenticatedProxmoxApi(unchanged behavior).dummy→ newDummyApi(utils/dummy-api.js) implementing the same method surface, simulating the Proxmox calls.POST /containers→Job→job-runner.js→bin/create-container.js→node.api(). The full creation path is exercised; only the hypervisor calls are faked. Running the job-runner is required (andmake devdoes so).DummyApi.clusterResources('lxc')derives the running set from the DB so the live container-status resolver (Container status API: compute live status instead of static DB column #352) reports dummy containers asrunning; the dev bootstrap gives the dummy node placeholder credentials so the resolver routes throughnode.api().2. Provider-agnostic-ish node selection
Node selection only excludes nodes that can't provision (it picks a dummy node, or a node with full
apiUrl/tokenId/secret), so a half-configured node is never selected and then failed innode.api(). The DELETE path likewise routes VM teardown throughnode.api().Node.api()validatesapiUrlalongside the credentials.3.
nodeTypecolumn (Postgres-safe)New migration
20260605000000-add-node-type-to-nodesaddsnodeType(STRING(50), default'proxmox'). Existing rows backfill toproxmoxvia the column default;Node.bulkCreate(node import) also applies it, so production node selection is unchanged.4. Root-cause fix for the erroneous
UNIQUEonContainers.nodeId(via patch-package)A v6 backport of sequelize/sequelize#17583 (
patches/sequelize+6.37.8.patch) so SQLite'schangeColumn/describeTableno longer marks members of a composite index asunique. Wired viapatch-package(postinstall). Replaces the SQLite-specific migration.5. Local dev environment out of
/auth/devNew
bin/dev-bootstrap.jsseeds alocalhostsite, adummynode, and alocalhostexternal domain. It no-ops if any Site already exists, so it never collides with the Docker Compose bootstrap. The/auth/devlogin route is left clean. The groups + push-notification seeders are made idempotent so re-running them undermake devdoesn't violate unique constraints.6. SQL query logging gated by
LOG_LEVEL=traceSequelize query logging (noisy — the job-runner polls the
Jobstable every tick) is gated behindLOG_LEVEL=trace, in both dev and production; off otherwise. Pass it through:make dev LOG_LEVEL=trace.7.
@vscode/sqlite3instead of the unmaintainedsqlite3The dev SQLite driver is the actively-maintained
@vscode/sqlite3fork, wired in via Sequelize v6dialectModule. It builds from source (no prebuilt-binary glibc mismatches that brokemake devon LTS distros) and is a devDependency required lazily only when the sqlite dialect is selected — so production (Postgres) never installs or loads it (npm ci --omit=devskips the native build entirely).8.
make devLives in
create-a-container/Makefile(the rootMakefiledelegates). Self-contained: installs server + client deps withnpm install --no-package-lock(so it never rewrites the lockfile), runs migrations, seeds the localhost site + dummy node, builds the client, then runs server (nodemon) + job-runner + client watch together. No.envis needed — the server's defaults (SQLite atdata/database.sqlite, an auto-generated session secret, dev login when not in production) are sufficient.db:migrateis fixed to callsequelize-cli.9. Docs
New "Run the Manager Locally (
make dev)" section in the development-workflow doc; README + release-pipeline pointers updated;LOG_LEVELdocumented inexample.env.How this addresses the #329 review comments
NodeApiinterface +DummyApi, with the job-runner still in the loopDummyApiimplements theProxmoxApisurface; creation runs through the job-runner andbin/create-container.jsunchangedapiUrl === 'local'); want a dedicated fieldnodeTypecolumn drivesNode.api()/auth/devintobin/dev-bootstrap.js, which no-ops if any Site exists.gitignoreentrymake devuses the defaultdata/database.sqlite(already ignored bycreate-a-container/data/.gitignore)Also addressed the Copilot review on this PR (provisionable-node filter + clearer error,
Node.api()apiUrl validation, conditionalLOG_LEVELforwarding in the Makefile, larger non-reused DummyApi VMID space, real locally-administered MAC prefix, patch-package moved so--omit=devinstalls don't fail).Testing
remove-container-status);Containershas no column-levelUNIQUEonnodeId.bin/create-container.jsagainstDummyApilands the container, and the live status resolver reports itrunning(andcreating/failedfor the other states); DELETE routes throughnode.api()and removes the row.npm ci(dev) andnpm ci --omit=dev(production, no@vscode/sqlite3, no native build) both succeed.make devruns server + job-runner + client watch and does not modify the lockfile.Closes #329