Initial implementation of mcdeploy deployment tool
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>
This commit is contained in:
95
config.go
Normal file
95
config.go
Normal file
@@ -0,0 +1,95 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user