Single Go binary with five commands: - build: podman build locally with registry tags + git version - push: podman push to MCR - deploy: SSH pull/stop/rm/run on target node - cert renew: issue TLS cert from Metacrypt via REST API - status: show container status on a node Config-driven via TOML service registry describing images, Dockerfiles, container configs per node. Shells out to podman for container operations and ssh for remote access. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
96 lines
2.7 KiB
Go
96 lines
2.7 KiB
Go
package main
|
|
|
|
import (
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
toml "github.com/pelletier/go-toml/v2"
|
|
)
|
|
|
|
// Config is the top-level deployment configuration.
|
|
type Config struct {
|
|
Workspace string `toml:"workspace"`
|
|
Registry string `toml:"registry"`
|
|
MCDSL MCDSLConfig `toml:"mcdsl"`
|
|
Services []ServiceConfig `toml:"services"`
|
|
Nodes map[string]*NodeConfig `toml:"nodes"`
|
|
}
|
|
|
|
// MCDSLConfig points to the shared mcdsl library.
|
|
type MCDSLConfig struct {
|
|
Path string `toml:"path"` // relative to workspace
|
|
}
|
|
|
|
// ServiceConfig describes a deployable service.
|
|
type ServiceConfig struct {
|
|
Name string `toml:"name"`
|
|
Path string `toml:"path"` // relative to workspace
|
|
Images []string `toml:"images"`
|
|
Dockerfiles map[string]string `toml:"dockerfiles"` // image name -> Dockerfile path
|
|
UsesMCDSL bool `toml:"uses_mcdsl"`
|
|
}
|
|
|
|
// NodeConfig describes a deployment target machine.
|
|
type NodeConfig struct {
|
|
Host string `toml:"host"`
|
|
User string `toml:"user"`
|
|
Containers map[string]*ContainerConfig `toml:"containers"`
|
|
}
|
|
|
|
// ContainerConfig describes a container to run on a node.
|
|
type ContainerConfig struct {
|
|
Image string `toml:"image"`
|
|
Network string `toml:"network"`
|
|
User string `toml:"user"`
|
|
Volumes []string `toml:"volumes"`
|
|
Ports []string `toml:"ports"`
|
|
Restart string `toml:"restart"`
|
|
Cmd []string `toml:"cmd"`
|
|
}
|
|
|
|
// LoadConfig reads and parses a TOML config file.
|
|
func LoadConfig(path string) (*Config, error) {
|
|
data, err := os.ReadFile(path)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("read config %s: %w", path, err)
|
|
}
|
|
|
|
var cfg Config
|
|
if err := toml.Unmarshal(data, &cfg); err != nil {
|
|
return nil, fmt.Errorf("parse config %s: %w", path, err)
|
|
}
|
|
|
|
return &cfg, nil
|
|
}
|
|
|
|
// FindService looks up a service by name.
|
|
func (c *Config) FindService(name string) (*ServiceConfig, error) {
|
|
for i := range c.Services {
|
|
if c.Services[i].Name == name {
|
|
return &c.Services[i], nil
|
|
}
|
|
}
|
|
return nil, fmt.Errorf("service %q not found in config", name)
|
|
}
|
|
|
|
// FindNode looks up a node by name.
|
|
func (c *Config) FindNode(name string) (*NodeConfig, error) {
|
|
node, ok := c.Nodes[name]
|
|
if !ok {
|
|
return nil, fmt.Errorf("node %q not found in config", name)
|
|
}
|
|
return node, nil
|
|
}
|
|
|
|
// ServicePath returns the absolute path to a service directory.
|
|
func (c *Config) ServicePath(svc *ServiceConfig) string {
|
|
return filepath.Join(c.Workspace, svc.Path)
|
|
}
|
|
|
|
// ImageRef returns the full registry reference for an image
|
|
// (e.g. "mcr.svc.mcp.metacircular.net:8443/mc-proxy").
|
|
func (c *Config) ImageRef(image string) string {
|
|
return c.Registry + "/" + image
|
|
}
|