feat(admin): module skeleton, config and two database connections
Adds the admin module: env config with fail-fast validation, two MongoDB connections (its own vantage_admin database plus a narrow path into the control plane), the boot sequence and the image. Config refuses to start without a signing key, and both Mongo URIs must name their database inline -- admin talks to two databases, so a bare MONGO_DB would be ambiguous about which. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
// Package db holds admin's two MongoDB connections.
|
||||
//
|
||||
// Admin() is its own database and it owns every collection there. Control() is
|
||||
// the control plane's database, and admin's access to it is deliberately narrow:
|
||||
// it reads `instances` and `users`, and writes exactly three licence fields on
|
||||
// `instances`. Nothing here should ever grow a write path to another collection.
|
||||
package db
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/mrhid6/vantage/admin/internal/config"
|
||||
"go.mongodb.org/mongo-driver/v2/mongo"
|
||||
"go.mongodb.org/mongo-driver/v2/mongo/options"
|
||||
)
|
||||
|
||||
var (
|
||||
adminDB *mongo.Database
|
||||
controlDB *mongo.Database
|
||||
)
|
||||
|
||||
func Connect(ctx context.Context, cfg config.Config) error {
|
||||
ac, err := mongo.Connect(options.Client().ApplyURI(cfg.AdminMongoURI))
|
||||
if err != nil {
|
||||
return fmt.Errorf("connect admin mongo: %w", err)
|
||||
}
|
||||
if err := ac.Ping(ctx, nil); err != nil {
|
||||
return fmt.Errorf("ping admin mongo: %w", err)
|
||||
}
|
||||
adminDB = ac.Database(cfg.AdminDBName)
|
||||
|
||||
cc, err := mongo.Connect(options.Client().ApplyURI(cfg.ControlMongoURI))
|
||||
if err != nil {
|
||||
return fmt.Errorf("connect control mongo: %w", err)
|
||||
}
|
||||
if err := cc.Ping(ctx, nil); err != nil {
|
||||
return fmt.Errorf("ping control mongo: %w", err)
|
||||
}
|
||||
controlDB = cc.Database(cfg.ControlDBName)
|
||||
|
||||
// The control plane must already be deployed and migrated. Without the
|
||||
// instances collection, injection would silently create it and write
|
||||
// licence fields into a collection nothing reads.
|
||||
names, err := controlDB.ListCollectionNames(ctx, map[string]any{"name": "instances"})
|
||||
if err != nil {
|
||||
return fmt.Errorf("inspect control database: %w", err)
|
||||
}
|
||||
if len(names) == 0 {
|
||||
return fmt.Errorf("control database %q has no instances collection; deploy and migrate the control plane first", cfg.ControlDBName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Admin(name string) *mongo.Collection { return adminDB.Collection(name) }
|
||||
func Control(name string) *mongo.Collection { return controlDB.Collection(name) }
|
||||
|
||||
func Ctx() (context.Context, context.CancelFunc) {
|
||||
return context.WithTimeout(context.Background(), 10*time.Second)
|
||||
}
|
||||
Reference in New Issue
Block a user