diff --git a/cmd/grounds/commands/cluster/up.go b/cmd/grounds/commands/cluster/up.go index 2ae255d..5cdbbee 100644 --- a/cmd/grounds/commands/cluster/up.go +++ b/cmd/grounds/commands/cluster/up.go @@ -10,16 +10,29 @@ import ( ) func newUp() *cobra.Command { - return &cobra.Command{ - Use: "up", - Short: "Resume the paused workspace", + var profile string + cmd := &cobra.Command{ + Use: "up [--profile=minigame|platform]", + Short: "Spawn or resume the workspace", + Long: `Create the workspace if it doesn't exist, or resume it from a paused state. + +Profiles: + minigame — namespace-scoped sandbox (default). Cheap, fast, isolated by RBAC. + platform — full per-developer vCluster with the Grounds platform chart + installed inside. Heavier (one-time ~90s spawn) but lets you + run platform plugins / agones / mc-router locally. + +Profile is locked once a workspace exists. To switch, ` + "`grounds cluster delete`" + ` and re-up.`, RunE: func(cmd *cobra.Command, _ []string) error { + if profile != "" && profile != "minigame" && profile != "platform" { + return fmt.Errorf("invalid --profile %q: must be \"minigame\" or \"platform\"", profile) + } ctx := context.Background() c, _, err := buildClient(ctx, cmd) if err != nil { return err } - s, err := c.ClusterUp(ctx) + s, err := c.ClusterUp(ctx, profile) if err != nil { return err } @@ -28,4 +41,6 @@ func newUp() *cobra.Command { return nil }, } + cmd.Flags().StringVar(&profile, "profile", "", "workspace profile: minigame (default) or platform (vCluster)") + return cmd } diff --git a/internal/api/cluster.go b/internal/api/cluster.go index d0e989b..f14960c 100644 --- a/internal/api/cluster.go +++ b/internal/api/cluster.go @@ -4,6 +4,7 @@ import ( "context" "encoding/json" "net/http" + "net/url" "time" ) @@ -32,9 +33,17 @@ func (c *Client) GetCluster(ctx context.Context) (*ClusterStatus, error) { return out, nil } -func (c *Client) ClusterUp(ctx context.Context) (*ClusterStatus, error) { +// ClusterUp spawns or resumes the workspace. `profile` may be empty +// (forge picks the default), "minigame", or "platform". Forge enforces +// the immutable-profile rule: switching profiles on an existing +// workspace requires `grounds cluster delete` first. +func (c *Client) ClusterUp(ctx context.Context, profile string) (*ClusterStatus, error) { + path := "/v1/cluster/up" + if profile != "" { + path += "?profile=" + url.QueryEscape(profile) + } out := &ClusterStatus{} - if err := c.doRequest(ctx, http.MethodPost, "/v1/cluster/up", nil, out); err != nil { + if err := c.doRequest(ctx, http.MethodPost, path, nil, out); err != nil { return nil, err } return out, nil