diff --git a/internal/servicedef/servicedef.go b/internal/servicedef/servicedef.go index 7135218..fae858d 100644 --- a/internal/servicedef/servicedef.go +++ b/internal/servicedef/servicedef.go @@ -16,8 +16,10 @@ import ( // ServiceDef is the top-level TOML structure for a service definition file. type ServiceDef struct { Name string `toml:"name"` - Node string `toml:"node"` + Node string `toml:"node,omitempty"` + Tier string `toml:"tier,omitempty"` Active *bool `toml:"active,omitempty"` + Comment string `toml:"comment,omitempty"` Path string `toml:"path,omitempty"` Build *BuildDef `toml:"build,omitempty"` Components []ComponentDef `toml:"components"` @@ -36,6 +38,7 @@ type RouteDef struct { Port int `toml:"port"` Mode string `toml:"mode,omitempty"` Hostname string `toml:"hostname,omitempty"` + Public bool `toml:"public,omitempty"` } // ComponentDef describes a single container component within a service. @@ -129,8 +132,9 @@ func validate(def *ServiceDef) error { if def.Name == "" { return fmt.Errorf("service name is required") } - if def.Node == "" { - return fmt.Errorf("service node is required") + // v2: either node or tier must be set. Tier defaults to "worker" if both empty. + if def.Node == "" && def.Tier == "" { + def.Tier = "worker" } if len(def.Components) == 0 { return fmt.Errorf("service %q must have at least one component", def.Name) @@ -191,8 +195,11 @@ func validateRoutes(compName, svcName string, routes []RouteDef) error { // ToProto converts a ServiceDef to a proto ServiceSpec. func ToProto(def *ServiceDef) *mcpv1.ServiceSpec { spec := &mcpv1.ServiceSpec{ - Name: def.Name, - Active: def.Active != nil && *def.Active, + Name: def.Name, + Active: def.Active != nil && *def.Active, + Comment: def.Comment, + Tier: def.Tier, + Node: def.Node, } for _, c := range def.Components { @@ -213,6 +220,7 @@ func ToProto(def *ServiceDef) *mcpv1.ServiceSpec { Port: int32(r.Port), //nolint:gosec // port range validated Mode: r.Mode, Hostname: r.Hostname, + Public: r.Public, }) } spec.Components = append(spec.Components, cs) @@ -227,9 +235,11 @@ func ToProto(def *ServiceDef) *mcpv1.ServiceSpec { func FromProto(spec *mcpv1.ServiceSpec, node string) *ServiceDef { active := spec.GetActive() def := &ServiceDef{ - Name: spec.GetName(), - Node: node, - Active: &active, + Name: spec.GetName(), + Node: node, + Tier: spec.GetTier(), + Active: &active, + Comment: spec.GetComment(), } for _, c := range spec.GetComponents() { @@ -250,6 +260,7 @@ func FromProto(spec *mcpv1.ServiceSpec, node string) *ServiceDef { Port: int(r.GetPort()), Mode: r.GetMode(), Hostname: r.GetHostname(), + Public: r.GetPublic(), }) } def.Components = append(def.Components, cd) diff --git a/internal/servicedef/servicedef_test.go b/internal/servicedef/servicedef_test.go index bfe3a6b..f33c25b 100644 --- a/internal/servicedef/servicedef_test.go +++ b/internal/servicedef/servicedef_test.go @@ -119,14 +119,8 @@ func TestValidation(t *testing.T) { }, wantErr: "service name is required", }, - { - name: "missing node", - def: &ServiceDef{ - Name: "svc", - Components: []ComponentDef{{Name: "api", Image: "img:v1"}}, - }, - wantErr: "service node is required", - }, + // v2: missing node no longer errors — defaults to tier=worker. + // Tested separately in TestValidationNodeTierDefault. { name: "empty components", def: &ServiceDef{