Files
mcp/internal/runtime/runtime.go
Kyle Isom 777ba8a0e1 Add route declarations and automatic port allocation to MCP agent
Service definitions can now declare routes per component instead of
manual port mappings:

  [[components.routes]]
  name = "rest"
  port = 8443
  mode = "l4"

The agent allocates free host ports at deploy time and injects
$PORT/$PORT_<NAME> env vars into containers. Backward compatible:
components with old-style ports= work unchanged.

Changes:
- Proto: RouteSpec message, routes + env fields on ComponentSpec
- Servicedef: RouteDef parsing and validation from TOML
- Registry: component_routes table with host_port tracking
- Runtime: Env field on ContainerSpec, -e flag in BuildRunArgs
- Agent: PortAllocator (random 10000-60000, availability check),
  deploy wiring for route→port mapping and env injection

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-27 01:04:47 -07:00

66 lines
1.9 KiB
Go

package runtime
import (
"context"
"strings"
"time"
)
// ContainerSpec describes a container to create and run.
type ContainerSpec struct {
Name string // container name, format: <service>-<component>
Image string // full image reference
Network string // docker network name
User string // container user (e.g., "0:0")
Restart string // restart policy (e.g., "unless-stopped")
Ports []string // "host:container" port mappings
Volumes []string // "host:container" volume mounts
Cmd []string // command and arguments
Env []string // environment variables (KEY=VALUE)
}
// ContainerInfo describes the observed state of a running or stopped container.
type ContainerInfo struct {
Name string
Image string
State string // "running", "stopped", "exited", etc.
Network string
User string
Restart string
Ports []string
Volumes []string
Cmd []string
Version string // extracted from image tag
Started time.Time // when the container started (zero if not running)
}
// Runtime is the container runtime abstraction.
type Runtime interface {
Pull(ctx context.Context, image string) error
Run(ctx context.Context, spec ContainerSpec) error
Stop(ctx context.Context, name string) error
Remove(ctx context.Context, name string) error
Inspect(ctx context.Context, name string) (ContainerInfo, error)
List(ctx context.Context) ([]ContainerInfo, error)
}
// ExtractVersion parses the tag from an image reference.
// Examples:
//
// "registry/img:v1.2.0" -> "v1.2.0"
// "registry/img:latest" -> "latest"
// "registry/img" -> ""
// "registry:5000/img:v1" -> "v1"
func ExtractVersion(image string) string {
// Strip registry/path prefix so that a port like "registry:5000" isn't
// mistaken for a tag separator.
name := image
if i := strings.LastIndex(image, "/"); i >= 0 {
name = image[i+1:]
}
if i := strings.LastIndex(name, ":"); i >= 0 {
return name[i+1:]
}
return ""
}