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}.
115 lines
3.1 KiB
Go
115 lines
3.1 KiB
Go
package store_test
|
|
|
|
import (
|
|
"os"
|
|
"testing"
|
|
|
|
"github.com/sdp/control-plane/internal/store"
|
|
)
|
|
|
|
// TestSandboxRoundTrip exercises the Slice-2 CRUD path against a
|
|
// throwaway data directory. The build pipeline runs this; the
|
|
// real deployment uses the control plane's HTTP layer.
|
|
func TestSandboxRoundTrip(t *testing.T) {
|
|
dir, err := os.MkdirTemp("", "sdp-store-")
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
defer os.RemoveAll(dir)
|
|
|
|
st, err := store.Open(dir)
|
|
if err != nil {
|
|
t.Fatalf("open: %v", err)
|
|
}
|
|
defer st.Close()
|
|
|
|
// env
|
|
e := store.Environment{ID: "e1", Name: "dev", Values: map[string]string{"FOO": "bar"}}
|
|
if err := st.CreateEnvironment(e); err != nil {
|
|
t.Fatalf("env create: %v", err)
|
|
}
|
|
got, err := st.GetEnvironment("e1")
|
|
if err != nil {
|
|
t.Fatalf("env get: %v", err)
|
|
}
|
|
if got.Values["FOO"] != "bar" {
|
|
t.Fatalf("env values: got %v", got.Values)
|
|
}
|
|
|
|
// sandbox
|
|
sb := store.Sandbox{ID: "s1", Name: "qa", GatewayBranch: "develop", GatewayHostPort: 8080,
|
|
Services: []store.SandboxService{
|
|
{ID: "s1-haven", SandboxID: "s1", Repo: "haven", Branch: "main", HostPort: 9001, UseOCP: false, EnvID: "e1"},
|
|
}}
|
|
if err := st.CreateSandbox(sb); err != nil {
|
|
t.Fatalf("sandbox create: %v", err)
|
|
}
|
|
gotsb, err := st.GetSandbox("s1")
|
|
if err != nil {
|
|
t.Fatalf("sandbox get: %v", err)
|
|
}
|
|
if len(gotsb.Services) != 1 || gotsb.Services[0].Repo != "haven" {
|
|
t.Fatalf("sandbox services: %+v", gotsb.Services)
|
|
}
|
|
|
|
// template + clone
|
|
t1 := store.Template{ID: "t1", Name: "acct", GatewayBranch: "develop",
|
|
Services: []store.TemplateService{
|
|
{ID: "t1-haven", TemplateID: "t1", Repo: "haven", Branch: "feature/x", HostPort: 9001, UseOCP: false},
|
|
}}
|
|
if err := st.CreateTemplate(t1); err != nil {
|
|
t.Fatalf("tpl create: %v", err)
|
|
}
|
|
if err := st.CloneTemplateIntoSandbox("t1", store.Sandbox{ID: "s2", Name: "qa2"}); err != nil {
|
|
t.Fatalf("clone: %v", err)
|
|
}
|
|
cs, err := st.GetSandbox("s2")
|
|
if err != nil {
|
|
t.Fatalf("cloned get: %v", err)
|
|
}
|
|
if cs.GatewayBranch != "develop" || len(cs.Services) != 1 {
|
|
t.Fatalf("cloned content: %+v", cs)
|
|
}
|
|
|
|
// routes
|
|
if err := st.SetRoutes("s1", []store.Route{
|
|
{ID: "r1", SandboxID: "s1", Key: "haven", Value: "http://172.18.136.92:9001"},
|
|
{ID: "r2", SandboxID: "s1", Key: "eredar", Value: "", TargetOCP: true},
|
|
}); err != nil {
|
|
t.Fatalf("routes: %v", err)
|
|
}
|
|
rs, err := st.ListRoutes("s1")
|
|
if err != nil {
|
|
t.Fatalf("routes list: %v", err)
|
|
}
|
|
if len(rs) != 2 {
|
|
t.Fatalf("routes count: %d", len(rs))
|
|
}
|
|
|
|
// deployment
|
|
if err := st.StartDeploymentInSandbox("d1", "s1", "haven", "main", "achmad", 9001); err != nil {
|
|
t.Fatalf("dep start: %v", err)
|
|
}
|
|
d, err := st.GetDeployment("d1")
|
|
if err != nil {
|
|
t.Fatalf("dep get: %v", err)
|
|
}
|
|
if d.HostPort != 9001 || d.SandboxID != "s1" {
|
|
t.Fatalf("dep content: %+v", d)
|
|
}
|
|
if err := st.SetContainerID("d1", "container-abc"); err != nil {
|
|
t.Fatalf("container id: %v", err)
|
|
}
|
|
d, _ = st.GetDeployment("d1")
|
|
if d.ContainerID != "container-abc" {
|
|
t.Fatalf("container id roundtrip: %q", d.ContainerID)
|
|
}
|
|
deps, err := st.ListDeployments("s1", 10)
|
|
if err != nil {
|
|
t.Fatalf("deps list: %v", err)
|
|
}
|
|
if len(deps) != 1 {
|
|
t.Fatalf("deps count: %d", len(deps))
|
|
}
|
|
}
|