55d7705c63
- protocol: add RepoInfo, RouteOverride; add HostPort, SandboxID to DeployRequest.
- ws hub: add CallAgent for sync request/response RPCs over the agent WS,
and DeliverAgentReply to route {op:reply} frames back to the caller.
UnregisterAgent now also fails any pending RPCs so callers don't hang.
- agent-micro: new op handlers list_repos, list_branches, probe.
Wire protocol.Event frames use json.RawMessage so each op decodes
its own data shape.
- agent-gateway: same op handlers (list_repos/list_branches/probe) plus
push_routes, which the gateway uses to rewrite the api-gateway
config.php. Detailed in a later commit.
- control-plane login: validateViaAgent now calls CallAgent('probe')
against the gateway agent (git ls-remote), replacing the
accept-any-creds stub.
- control-plane repos: handleListRepos and handleListBranches forward
to the agents via list_repos / list_branches RPCs, replacing the
hardcoded fixtures.
- control-plane deployments: split into its own file. handleListDeployments
reads from SQLite (was hardcoded []). handleCreateDeployment now
supports sandbox-scoped deploys with a host port + env merge.
handleStopDeployment looks up the node from the deployment row.
- store: split into store.go + deployments.go. The Deployment type
adds sandboxId, containerId, hostPort. StartDeploymentInSandbox,
SetContainerID, ListDeployments, GetDeployment, LatestDeploymentBySandboxService
are new.
- store_test.go: round-trips every Slice-2 path (env, sandbox,
template, clone, routes, deployment).
- .gitignore: track bin/ — the build runs on a separate Linux box
with the golang:1.24 toolchain, and the binaries are SCPed from
there to the company VMs (92 / 186). The VMs have no internet.
- Tracked bin/{control-plane,agent-micro,agent-gateway}.
122 lines
2.6 KiB
Go
122 lines
2.6 KiB
Go
// Package store persists deployment progress and Slice-2 metadata in
|
|
// SQLite, and log lines in append-only .log files. The hot path is
|
|
// AppendEvent — agents emit a lot of these and the dashboard wants them
|
|
// live. Slice 2 adds sandboxes, templates, environments, routes, and
|
|
// port allocations on top of the deployment rows.
|
|
package store
|
|
|
|
import (
|
|
"database/sql"
|
|
"os"
|
|
"path/filepath"
|
|
"sync"
|
|
|
|
_ "modernc.org/sqlite"
|
|
)
|
|
|
|
type Store struct {
|
|
db *sql.DB
|
|
dir string
|
|
logs map[string]*os.File // deploymentID -> file
|
|
mu sync.Mutex
|
|
}
|
|
|
|
func Open(dir string) (*Store, error) {
|
|
if err := os.MkdirAll(dir, 0o755); err != nil {
|
|
return nil, err
|
|
}
|
|
if err := os.MkdirAll(filepath.Join(dir, "logs"), 0o755); err != nil {
|
|
return nil, err
|
|
}
|
|
db, err := sql.Open("sqlite", filepath.Join(dir, "sdp.db"))
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if _, err := db.Exec(schema); err != nil {
|
|
return nil, err
|
|
}
|
|
return &Store{db: db, dir: dir, logs: make(map[string]*os.File)}, nil
|
|
}
|
|
|
|
const schema = `
|
|
CREATE TABLE IF NOT EXISTS deployments (
|
|
id TEXT PRIMARY KEY,
|
|
sandbox_id TEXT,
|
|
repository TEXT,
|
|
branch TEXT,
|
|
user TEXT,
|
|
state TEXT,
|
|
container_id TEXT,
|
|
host_port INTEGER,
|
|
started_at INTEGER,
|
|
completed_at INTEGER
|
|
);
|
|
CREATE TABLE IF NOT EXISTS progress (
|
|
deployment_id TEXT,
|
|
stage TEXT,
|
|
ok INTEGER,
|
|
at INTEGER
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS sandboxes (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT UNIQUE NOT NULL,
|
|
gateway_branch TEXT,
|
|
gateway_env_id TEXT,
|
|
gateway_host_port INTEGER,
|
|
created_at INTEGER,
|
|
updated_at INTEGER
|
|
);
|
|
CREATE TABLE IF NOT EXISTS sandbox_services (
|
|
id TEXT PRIMARY KEY,
|
|
sandbox_id TEXT NOT NULL,
|
|
repo TEXT NOT NULL,
|
|
branch TEXT,
|
|
env_id TEXT,
|
|
host_port INTEGER,
|
|
use_ocp INTEGER DEFAULT 0
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS templates (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT UNIQUE NOT NULL,
|
|
gateway_branch TEXT,
|
|
created_at INTEGER,
|
|
updated_at INTEGER
|
|
);
|
|
CREATE TABLE IF NOT EXISTS template_services (
|
|
id TEXT PRIMARY KEY,
|
|
template_id TEXT NOT NULL,
|
|
repo TEXT NOT NULL,
|
|
branch TEXT,
|
|
env_id TEXT,
|
|
host_port INTEGER,
|
|
use_ocp INTEGER DEFAULT 0
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS environments (
|
|
id TEXT PRIMARY KEY,
|
|
name TEXT UNIQUE NOT NULL,
|
|
values_json TEXT NOT NULL,
|
|
created_at INTEGER,
|
|
updated_at INTEGER
|
|
);
|
|
|
|
CREATE TABLE IF NOT EXISTS routes (
|
|
id TEXT PRIMARY KEY,
|
|
sandbox_id TEXT NOT NULL,
|
|
key TEXT NOT NULL,
|
|
value TEXT,
|
|
target_ocp INTEGER NOT NULL DEFAULT 0
|
|
);
|
|
`
|
|
|
|
func (s *Store) Close() error {
|
|
s.mu.Lock()
|
|
defer s.mu.Unlock()
|
|
for _, f := range s.logs {
|
|
_ = f.Close()
|
|
}
|
|
return s.db.Close()
|
|
}
|