a7df9ffc6c
- store: add tables and CRUD for sandboxes (with services), templates (with services, clone-into-sandbox), environments (named key/value sets), and routes (per-sandbox <service>_url overrides). - api: split into one file per resource. handleSandboxes/handleSandboxByID covers CRUD + 'clone from template' + 'deploy one service in a sandbox' (which merges the sandbox's env into the request, picks the port, and dispatches the deploy frame to the right node). handleTemplates/handleTemplateByID, handleEnvironments/handleEnvironmentByID, handlePushRoutes cover the rest. The control plane's repo->node resolution still lives in resolveNode (api-gateway -> gateway, everything else -> micro).
83 lines
2.2 KiB
Go
83 lines
2.2 KiB
Go
package store
|
|
|
|
import (
|
|
"database/sql"
|
|
)
|
|
|
|
// Route is one "<service>_url" line attached to a sandbox. The agent
|
|
// pushes the whole set to the gateway by replacing any matching lines
|
|
// in the gateway's config.php.
|
|
type Route struct {
|
|
ID string `json:"id"`
|
|
SandboxID string `json:"sandboxId"`
|
|
Key string `json:"key"`
|
|
Value string `json:"value"`
|
|
TargetOCP bool `json:"targetOcp"`
|
|
}
|
|
|
|
// SetRoutes atomically replaces the routing table for a sandbox. The
|
|
// gateway agent's "push" frame is the whole set.
|
|
func (s *Store) SetRoutes(sandboxID string, routes []Route) error {
|
|
tx, err := s.db.Begin()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
defer tx.Rollback()
|
|
if _, err := tx.Exec(`DELETE FROM routes WHERE sandbox_id=?`, sandboxID); err != nil {
|
|
return err
|
|
}
|
|
for i := range routes {
|
|
r := routes[i]
|
|
r.SandboxID = sandboxID
|
|
if r.ID == "" {
|
|
r.ID = sandboxID + "-" + r.Key
|
|
}
|
|
if _, err := tx.Exec(
|
|
`INSERT INTO routes(id, sandbox_id, key, value, target_ocp) VALUES(?,?,?,?,?)`,
|
|
r.ID, r.SandboxID, r.Key, r.Value, boolInt(r.TargetOCP)); err != nil {
|
|
return err
|
|
}
|
|
}
|
|
return tx.Commit()
|
|
}
|
|
|
|
// ListRoutes returns the routes for one sandbox.
|
|
func (s *Store) ListRoutes(sandboxID string) ([]Route, error) {
|
|
rows, err := s.db.Query(
|
|
`SELECT id, sandbox_id, key, COALESCE(value,''), target_ocp
|
|
FROM routes WHERE sandbox_id=? ORDER BY key`, sandboxID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
defer rows.Close()
|
|
var out []Route
|
|
for rows.Next() {
|
|
var r Route
|
|
var targetOCP int
|
|
if err := rows.Scan(&r.ID, &r.SandboxID, &r.Key, &r.Value, &targetOCP); err != nil {
|
|
return nil, err
|
|
}
|
|
r.TargetOCP = targetOCP == 1
|
|
out = append(out, r)
|
|
}
|
|
return out, rows.Err()
|
|
}
|
|
|
|
// GetRoute returns one route by sandbox+key, or ErrNotFound.
|
|
func (s *Store) GetRoute(sandboxID, key string) (*Route, error) {
|
|
row := s.db.QueryRow(
|
|
`SELECT id, sandbox_id, key, COALESCE(value,''), target_ocp
|
|
FROM routes WHERE sandbox_id=? AND key=?`, sandboxID, key)
|
|
var r Route
|
|
var targetOCP int
|
|
err := row.Scan(&r.ID, &r.SandboxID, &r.Key, &r.Value, &targetOCP)
|
|
if err == sql.ErrNoRows {
|
|
return nil, ErrNotFound
|
|
}
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
r.TargetOCP = targetOCP == 1
|
|
return &r, nil
|
|
}
|