From 70e32f35311f248e891c7de260b080a400cf2064 Mon Sep 17 00:00:00 2001 From: Steve Yoon Date: Tue, 7 Apr 2026 13:17:09 -0400 Subject: [PATCH] cloud-agents environment support --- cmd/lk/agent.go | 48 ++++++++++++++++++++++++++++++++++++++++++------ go.mod | 6 +++++- go.sum | 8 -------- 3 files changed, 47 insertions(+), 15 deletions(-) diff --git a/cmd/lk/agent.go b/cmd/lk/agent.go index e6745d0a..f400465e 100644 --- a/cmd/lk/agent.go +++ b/cmd/lk/agent.go @@ -97,6 +97,12 @@ var ( Required: false, } + envFlag = &cli.StringSliceFlag{ + Name: "env", + Usage: "Deployment environment(s). For create/deploy, specifies the target environment (defaults to 'production'). For update-secrets, assigns environment(s) to the secret. Can be specified multiple times (e.g. --env staging --env production).", + Required: false, + } + skipSDKCheckFlag = &cli.BoolFlag{ Name: "skip-sdk-check", Required: false, @@ -166,6 +172,7 @@ var ( ignoreEmptySecretsFlag, silentFlag, regionFlag, + envFlag, skipSDKCheckFlag, }, // NOTE: since secrets may contain commas, or indeed any special character we might want to treat as a flag separator, @@ -210,6 +217,7 @@ var ( secretsMountFlag, silentFlag, regionFlag, + envFlag, ignoreEmptySecretsFlag, skipSDKCheckFlag, }, @@ -333,6 +341,7 @@ var ( secretsFileFlag, secretsMountFlag, ignoreEmptySecretsFlag, + envFlag, idFlag(false), &cli.BoolFlag{ Name: "overwrite", @@ -605,11 +614,16 @@ func createAgent(ctx context.Context, cmd *cli.Command) error { } } + environment := "production" + if cmd.IsSet("env") { + environment = cmd.StringSlice("env")[0] + } + buildContext, cancel := context.WithTimeout(ctx, buildTimeout) defer cancel() regions := []string{region} excludeFiles := []string{fmt.Sprintf("**/%s", config.LiveKitTOMLFile)} - resp, err := agentsClient.CreateAgent(buildContext, os.DirFS(workingDir), secrets, regions, excludeFiles, os.Stderr) + resp, err := agentsClient.CreateAgent(buildContext, os.DirFS(workingDir), secrets, regions, environment, excludeFiles, os.Stderr) if err != nil { if errors.Is(err, context.DeadlineExceeded) { return fmt.Errorf("build timed out possibly due to large image size") @@ -765,10 +779,15 @@ func deployAgent(ctx context.Context, cmd *cli.Command) error { } } + environment := "production" + if cmd.IsSet("env") { + environment = cmd.StringSlice("env")[0] + } + buildContext, cancel := context.WithTimeout(ctx, buildTimeout) defer cancel() excludeFiles := []string{fmt.Sprintf("**/%s", config.LiveKitTOMLFile)} - if err := agentsClient.DeployAgent(buildContext, agentId, os.DirFS(workingDir), secrets, excludeFiles, os.Stderr); err != nil { + if err := agentsClient.DeployAgent(buildContext, agentId, os.DirFS(workingDir), secrets, environment, excludeFiles, os.Stderr); err != nil { if twerr, ok := err.(twirp.Error); ok { return fmt.Errorf("unable to deploy agent: %s", twerr.Msg()) } @@ -821,6 +840,7 @@ func getAgentStatus(ctx context.Context, cmd *cli.Command) error { agent.AgentId, agent.Version, regionalAgent.Region, + regionalAgent.Environment, regionalAgent.Status, fmt.Sprintf("%s / %s", curCPU, regionalAgent.CpuLimit), fmt.Sprintf("%s / %s", curMem, memLimit), @@ -831,7 +851,7 @@ func getAgentStatus(ctx context.Context, cmd *cli.Command) error { } t := util.CreateTable(). - Headers("ID", "Version", "Region", "Status", "CPU", "Mem", "Replicas", "Deployed At"). + Headers("ID", "Version", "Region", "Environment", "Status", "CPU", "Mem", "Replicas", "Deployed At"). Rows(rows...) fmt.Println(t) @@ -1090,19 +1110,24 @@ func listAgents(ctx context.Context, cmd *cli.Command) error { var rows [][]string for _, agent := range items { var regions []string + var environments []string for _, regionalAgent := range agent.AgentDeployments { regions = append(regions, regionalAgent.Region) + if !slices.Contains(environments, regionalAgent.Environment) { + environments = append(environments, regionalAgent.Environment) + } } rows = append(rows, []string{ agent.AgentId, strings.Join(regions, ","), + strings.Join(environments, ","), agent.Version, agent.DeployedAt.AsTime().Format(time.RFC3339), }) } t := util.CreateTable(). - Headers("ID", "Regions", "Version", "Deployed At"). + Headers("ID", "Regions", "Environment", "Version", "Deployed At"). Rows(rows...) fmt.Println(t) @@ -1129,14 +1154,18 @@ func listAgentSecrets(ctx context.Context, cmd *cli.Command) error { // TODO (steveyoon): show secret.Kind.String() once cloud-agents is released table := util.CreateTable(). - Headers("Name", "Created At", "Updated At") + Headers("Name", "Environments", "Created At", "Updated At") for _, secret := range secrets.Secrets { // NOTE: Maybe these should be omitted on the server side? if slices.Contains(ignoredSecrets, secret.Name) { continue } - table.Row(secret.Name, secret.CreatedAt.AsTime().Format(time.RFC3339), secret.UpdatedAt.AsTime().Format(time.RFC3339)) + envs := strings.Join(secret.Environments, ", ") + if envs == "" { + envs = "(all)" + } + table.Row(secret.Name, envs, secret.CreatedAt.AsTime().Format(time.RFC3339), secret.UpdatedAt.AsTime().Format(time.RFC3339)) } fmt.Println(table) @@ -1154,6 +1183,13 @@ func updateAgentSecrets(ctx context.Context, cmd *cli.Command) error { return err } + if cmd.IsSet("env") { + envs := cmd.StringSlice("env") + for _, s := range secrets { + s.Environments = envs + } + } + var confirmOverwrite bool if cmd.Bool("overwrite") { confirmOverwrite = SkipPrompts(cmd) diff --git a/go.mod b/go.mod index cfb49113..b188f551 100644 --- a/go.mod +++ b/go.mod @@ -12,7 +12,7 @@ require ( github.com/go-logr/logr v1.4.3 github.com/go-task/task/v3 v3.44.1 github.com/joho/godotenv v1.5.1 - github.com/livekit/protocol v1.45.2-0.20260403233349-218b0d450bd2 + github.com/livekit/protocol v1.45.2-0.20260403151849-8a360e8d0221 github.com/livekit/server-sdk-go/v2 v2.16.1 github.com/mattn/go-isatty v0.0.20 github.com/moby/patternmatcher v0.6.0 @@ -34,6 +34,8 @@ require ( k8s.io/apimachinery v0.34.1 ) +replace github.com/livekit/protocol => /Users/syoon/src/protocol + require ( buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.36.11-20260209202127-80ab13bee0bf.1 // indirect buf.build/go/protovalidate v1.1.3 // indirect @@ -208,3 +210,5 @@ require ( mvdan.cc/sh/v3 v3.12.0 // indirect sigs.k8s.io/json v0.0.0-20241014173422-cfa47c3a1cc8 // indirect ) + +replace github.com/livekit/server-sdk-go/v2 => /Users/syoon/src/server-sdk-go diff --git a/go.sum b/go.sum index 2ee6a50a..c9269fcc 100644 --- a/go.sum +++ b/go.sum @@ -273,16 +273,8 @@ github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731 h1:9x+U2HGLrSw5AT github.com/livekit/mageutil v0.0.0-20250511045019-0f1ff63f7731/go.mod h1:Rs3MhFwutWhGwmY1VQsygw28z5bWcnEYmS1OG9OxjOQ= github.com/livekit/mediatransportutil v0.0.0-20260309115634-0e2e24b36ee8 h1:coWig9fKxdb/nwOaIoGUUAogso12GblAJh/9SA9hcxk= github.com/livekit/mediatransportutil v0.0.0-20260309115634-0e2e24b36ee8/go.mod h1:RCd46PT+6sEztld6XpkCrG1xskb0u3SqxIjy4G897Ss= -github.com/livekit/protocol v1.45.2-0.20260403195737-756a0a7cb7b9 h1:dAOkOEzuSbsc0hb/m1z/2MfDo+OJA6hMqqjF8ehCD6I= -github.com/livekit/protocol v1.45.2-0.20260403195737-756a0a7cb7b9/go.mod h1:e6QdWDkfot+M2nRh0eitJUS0ZLuwvKCsfiz2pWWSG3s= -github.com/livekit/protocol v1.45.2-0.20260403232915-071d9549ba6f h1:/PBq2Q1V1t2K0jxQZn4R0pKupcg0mYws/SFHXDSzq2E= -github.com/livekit/protocol v1.45.2-0.20260403232915-071d9549ba6f/go.mod h1:e6QdWDkfot+M2nRh0eitJUS0ZLuwvKCsfiz2pWWSG3s= -github.com/livekit/protocol v1.45.2-0.20260403233349-218b0d450bd2 h1:tDAFmUQBiHpDEvfW+KzvWbqiMBgIHCveQ4IioocUzVg= -github.com/livekit/protocol v1.45.2-0.20260403233349-218b0d450bd2/go.mod h1:e6QdWDkfot+M2nRh0eitJUS0ZLuwvKCsfiz2pWWSG3s= github.com/livekit/psrpc v0.7.1 h1:ms37az0QTD3UXIWuUC5D/SkmKOlRMVRsI261eBWu/Vw= github.com/livekit/psrpc v0.7.1/go.mod h1:bZ4iHFQptTkbPnB0LasvRNu/OBYXEu1NA6O5BMFo9kk= -github.com/livekit/server-sdk-go/v2 v2.16.1 h1:ZkIA9OdVvQ6Up1uW/RtQ0YJUgYMJ6+ywOmDg0jX7bTg= -github.com/livekit/server-sdk-go/v2 v2.16.1/go.mod h1:oQbYijcbPzfjBAOzoq7tz9Ktqur8JNRCd923VP8xOQQ= github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= github.com/magefile/mage v1.16.1 h1:j5UwkdA48xTlGs0Hcm1Q3sSAcxBorntQjiewDNMsqlo=