From 348a736f6dc90a4b722a22a576e440202dab468a Mon Sep 17 00:00:00 2001 From: Tobias Fried Date: Sat, 14 Sep 2024 00:02:23 -0600 Subject: [PATCH] feat(sbx): use sandbox name rather than template name when cloning (#413) * feat(sbx): use sandbox name rather than template name when cloning * chore(cmd): bump version --- cmd/lk/app.go | 36 +++++------------------------ cmd/lk/cloud.go | 5 ++-- cmd/lk/replay.go | 9 ++------ go.mod | 16 ++++++------- go.sum | 28 +++++++++++------------ pkg/auth/auth.go | 11 +++++++++ pkg/bootstrap/bootstrap.go | 47 ++++++++++++++++++++++++++++++++++---- version.go | 2 +- 8 files changed, 87 insertions(+), 67 deletions(-) create mode 100644 pkg/auth/auth.go diff --git a/cmd/lk/app.go b/cmd/lk/app.go index 662e8fbd..96ba0f71 100644 --- a/cmd/lk/app.go +++ b/cmd/lk/app.go @@ -16,10 +16,8 @@ package main import ( "context" - "encoding/json" "errors" "fmt" - "net/http" "os" "os/exec" "path" @@ -33,12 +31,6 @@ import ( "github.com/urfave/cli/v3" ) -const ( - templateBaseURL = "https://github.com/livekit-examples" - sandboxDashboardURL = "https://cloud.livekit.io/projects/p_/v2/sandbox" - sandboxTemplateEndpoint = "/api/sandbox/template" -) - var ( template *bootstrap.Template templateName string @@ -62,7 +54,7 @@ var ( Flags: []cli.Flag{ &cli.StringFlag{ Name: "template", - Usage: "`TEMPLATE` to instantiate, see " + templateBaseURL, + Usage: "`TEMPLATE` to instantiate, see " + bootstrap.TemplateBaseURL, Destination: &templateName, }, &cli.StringFlag{ @@ -266,40 +258,24 @@ func setupSandboxTemplate(ctx context.Context, cmd *cli.Command) error { return err } - req, err := http.NewRequestWithContext(ctx, "GET", serverURL+sandboxTemplateEndpoint, nil) - req.Header = newHeaderWithToken(token) - query := req.URL.Query() - query.Add("id", sandboxID) - req.URL.RawQuery = query.Encode() - if err != nil { - return err - } - - resp, err := http.DefaultClient.Do(req) + details, err := bootstrap.FetchSandboxDetails(ctx, sandboxID, token, serverURL) if err != nil { return err } - if resp.StatusCode != 200 { - return errors.New("access denied") - } - - var template bootstrap.Template - if err := json.NewDecoder(resp.Body).Decode(&template); err != nil { - return err - } + template = &details.Template fmt.Println("Cloning template...") - if err := cloneTemplate(ctx, cmd, template.URL, template.Name); err != nil { + if err := cloneTemplate(ctx, cmd, template.URL, details.Name); err != nil { return err } fmt.Println("Instantiating environment...") - if err := instantiateEnv(ctx, cmd, template.Name); err != nil { + if err := instantiateEnv(ctx, cmd, details.Name); err != nil { return err } fmt.Println("Installing template...") - if err := doInstall(ctx, bootstrap.TaskInstallSandbox, template.Name, cmd.Bool("verbose")); err != nil { + if err := doInstall(ctx, bootstrap.TaskInstallSandbox, details.Name, cmd.Bool("verbose")); err != nil { return err } diff --git a/cmd/lk/cloud.go b/cmd/lk/cloud.go index 5802bff0..80fe59d8 100644 --- a/cmd/lk/cloud.go +++ b/cmd/lk/cloud.go @@ -25,11 +25,12 @@ import ( "github.com/charmbracelet/huh" "github.com/charmbracelet/huh/spinner" + "github.com/pkg/browser" "github.com/urfave/cli/v3" + authutil "github.com/livekit/livekit-cli/pkg/auth" "github.com/livekit/livekit-cli/pkg/config" "github.com/livekit/protocol/auth" - "github.com/pkg/browser" ) type ClaimAccessKeyResponse struct { @@ -196,7 +197,7 @@ func (a *AuthClient) Deauthenticate(ctx context.Context, projectName, token stri } req, err := http.NewRequestWithContext(ctx, "DELETE", reqURL.String(), nil) - req.Header = newHeaderWithToken(token) + req.Header = authutil.NewHeaderWithToken(token) if err != nil { return err } diff --git a/cmd/lk/replay.go b/cmd/lk/replay.go index eb49fa6b..6d49dbe5 100644 --- a/cmd/lk/replay.go +++ b/cmd/lk/replay.go @@ -8,6 +8,7 @@ import ( "github.com/twitchtv/twirp" "github.com/urfave/cli/v3" + authutil "github.com/livekit/livekit-cli/pkg/auth" "github.com/livekit/protocol/auth" "github.com/livekit/protocol/replay" lksdk "github.com/livekit/server-sdk-go/v2" @@ -208,11 +209,5 @@ func (c *replayServiceClient) withAuth(ctx context.Context) (context.Context, er return nil, err } - return twirp.WithHTTPRequestHeaders(ctx, newHeaderWithToken(token)) -} - -func newHeaderWithToken(token string) http.Header { - header := make(http.Header) - header.Set("Authorization", "Bearer "+token) - return header + return twirp.WithHTTPRequestHeaders(ctx, authutil.NewHeaderWithToken(token)) } diff --git a/go.mod b/go.mod index 112b0dc2..aa6aa843 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,8 @@ module github.com/livekit/livekit-cli -go 1.22 +go 1.22.0 -toolchain go1.22.2 +toolchain go1.22.4 require ( github.com/charmbracelet/huh v0.6.0 @@ -10,7 +10,7 @@ require ( github.com/charmbracelet/lipgloss v0.13.0 github.com/frostbyte73/core v0.0.12 github.com/go-logr/logr v1.4.2 - github.com/go-task/task/v3 v3.38.0 + github.com/go-task/task/v3 v3.39.0 github.com/joho/godotenv v1.5.1 github.com/livekit/protocol v1.20.2-0.20240831163355-2454665245fd github.com/livekit/server-sdk-go/v2 v2.2.1 @@ -32,7 +32,7 @@ require ( require ( buf.build/gen/go/bufbuild/protovalidate/protocolbuffers/go v1.34.2-20240717164558-a6c49f84cc0f.2 // indirect github.com/Ladicle/tabwriter v1.0.0 // indirect - github.com/Masterminds/semver/v3 v3.2.1 // indirect + github.com/Masterminds/semver/v3 v3.3.0 // indirect github.com/alecthomas/chroma/v2 v2.14.0 // indirect github.com/antlr4-go/antlr/v4 v4.13.1 // indirect github.com/atotto/clipboard v0.1.4 // indirect @@ -63,7 +63,7 @@ require ( github.com/go-jose/go-jose/v3 v3.0.3 // indirect github.com/go-logr/stdr v1.2.2 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect - github.com/go-task/template v0.0.0-20240602015157-960e6f576656 // indirect + github.com/go-task/template v0.1.0 // indirect github.com/google/cel-go v0.21.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/gorilla/websocket v1.5.3 // indirect @@ -80,7 +80,7 @@ require ( github.com/mattn/go-isatty v0.0.20 // indirect github.com/mattn/go-localereader v0.0.1 // indirect github.com/mattn/go-runewidth v0.0.16 // indirect - github.com/mattn/go-zglob v0.0.4 // indirect + github.com/mattn/go-zglob v0.0.6 // indirect github.com/mitchellh/hashstructure/v2 v2.0.2 // indirect github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect github.com/muesli/cancelreader v0.2.2 // indirect @@ -124,10 +124,10 @@ require ( golang.org/x/exp v0.0.0-20240808152545-0cdaa3abc0fa // indirect golang.org/x/net v0.28.0 // indirect golang.org/x/sys v0.25.0 // indirect - golang.org/x/term v0.23.0 // indirect + golang.org/x/term v0.24.0 // indirect golang.org/x/text v0.18.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240808171019-573a1156607a // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240808171019-573a1156607a // indirect google.golang.org/grpc v1.65.0 // indirect - mvdan.cc/sh/v3 v3.8.0 // indirect + mvdan.cc/sh/v3 v3.9.0 // indirect ) diff --git a/go.sum b/go.sum index 8a96969e..2d79dbf3 100644 --- a/go.sum +++ b/go.sum @@ -4,8 +4,8 @@ github.com/Ladicle/tabwriter v1.0.0 h1:DZQqPvMumBDwVNElso13afjYLNp0Z7pHqHnu0r4t9 github.com/Ladicle/tabwriter v1.0.0/go.mod h1:c4MdCjxQyTbGuQO/gvqJ+IA/89UEwrsD6hUCW98dyp4= github.com/MakeNowJust/heredoc v1.0.0 h1:cXCdzVdstXyiTqTvfqk9SDHpKNjxuom+DOlyEeQ4pzQ= github.com/MakeNowJust/heredoc v1.0.0/go.mod h1:mG5amYoWBHf8vpLOuehzbGGw0EHxpZZ6lCpQ4fNJ8LE= -github.com/Masterminds/semver/v3 v3.2.1 h1:RN9w6+7QoMeJVGyfmbcgs28Br8cvmnucEXnY0rYXWg0= -github.com/Masterminds/semver/v3 v3.2.1/go.mod h1:qvl/7zhW3nngYb5+80sSMF+FG2BjYrf8m9wsX0PNOMQ= +github.com/Masterminds/semver/v3 v3.3.0 h1:B8LGeaivUe71a5qox1ICM/JLl0NqZSW5CHyL+hmvYS0= +github.com/Masterminds/semver/v3 v3.3.0/go.mod h1:4V+yj/TJE1HU9XfppCwVMZq3I84lprf4nC11bSS5beM= github.com/alecthomas/assert/v2 v2.7.0 h1:QtqSACNS3tF7oasA8CU6A6sXZSBDqnm7RfpLl9bZqbE= github.com/alecthomas/assert/v2 v2.7.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= github.com/alecthomas/chroma/v2 v2.14.0 h1:R3+wzpnUArGcQz7fCETQBzO5n9IMNi13iIs46aU4V9E= @@ -75,8 +75,6 @@ github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= github.com/fatih/color v1.17.0 h1:GlRw1BRJxkpqUCBKzKOw098ed57fEsKeNjpTe3cSjK4= github.com/fatih/color v1.17.0/go.mod h1:YZ7TlrGPkiz6ku9fK3TLD/pl3CpsiFyu8N92HLgmosI= -github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHkI4W8= -github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0= github.com/frostbyte73/core v0.0.12 h1:kySA8+Os6eqnPFoExD2T7cehjSAY1MRyIViL0yTy2uc= github.com/frostbyte73/core v0.0.12/go.mod h1:XsOGqrqe/VEV7+8vJ+3a8qnCIXNbKsoEiu/czs7nrcU= github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= @@ -90,12 +88,14 @@ github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY= github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY= github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag= github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE= +github.com/go-quicktest/qt v1.101.0 h1:O1K29Txy5P2OK0dGo59b7b0LR6wKfIhttaAhHUyn7eI= +github.com/go-quicktest/qt v1.101.0/go.mod h1:14Bz/f7NwaXPtdYEgzsx46kqSxVwTbzVZsDC26tQJow= github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1vB6EwHI= github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= -github.com/go-task/task/v3 v3.38.0 h1:O7kgA6BfwktXHPrheByQO46p3teKtRuq1EpGnFxNzbo= -github.com/go-task/task/v3 v3.38.0/go.mod h1:UzLDHoXTKNAtWwFP3WVsfMhlSw3K8i9KNzEO9kCHix8= -github.com/go-task/template v0.0.0-20240602015157-960e6f576656 h1:knZZ4zVdTBQnevBz0zSES++4Mr7wr+cHopLvHabIgkA= -github.com/go-task/template v0.0.0-20240602015157-960e6f576656/go.mod h1:RgwRaZK+kni/hJJ7/AaOE2lPQFPbAdji/DyhC6pxo4k= +github.com/go-task/task/v3 v3.39.0 h1:Loe6ppP1x38Puv1M2wigp91bH/garCt0vLWkJsiTWNI= +github.com/go-task/task/v3 v3.39.0/go.mod h1:NJKIMDw2+SicDcdF+CHnJU7/PP9ZmQExKrXSOwgikpk= +github.com/go-task/template v0.1.0 h1:ym/r2G937RZA1bsgiWedNnY9e5kxDT+3YcoAnuIetTE= +github.com/go-task/template v0.1.0/go.mod h1:RgwRaZK+kni/hJJ7/AaOE2lPQFPbAdji/DyhC6pxo4k= github.com/google/cel-go v0.21.0 h1:cl6uW/gxN+Hy50tNYvI691+sXxioCnstFzLp2WO4GCI= github.com/google/cel-go v0.21.0/go.mod h1:rHUlWCcBKgyEk+eV03RPdZUekPp6YcJwV0FxuUksYxc= github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= @@ -149,8 +149,8 @@ github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2J github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= -github.com/mattn/go-zglob v0.0.4 h1:LQi2iOm0/fGgu80AioIJ/1j9w9Oh+9DZ39J4VAGzHQM= -github.com/mattn/go-zglob v0.0.4/go.mod h1:MxxjyoXXnMxfIpxTK2GAkw1w8glPsQILx3N5wrKakiY= +github.com/mattn/go-zglob v0.0.6 h1:mP8RnmCgho4oaUYDIDn6GNxYk+qJGUs8fJLn+twYj2A= +github.com/mattn/go-zglob v0.0.6/go.mod h1:MxxjyoXXnMxfIpxTK2GAkw1w8glPsQILx3N5wrKakiY= github.com/mitchellh/hashstructure/v2 v2.0.2 h1:vGKWl0YJqUNxE8d+h8f6NJLcCJrgbhC4NcD46KavDd4= github.com/mitchellh/hashstructure/v2 v2.0.2/go.mod h1:MG3aRVU/N29oo/V/IhBX8GR/zz4kQkprJgF2EVszyDE= github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= @@ -329,8 +329,8 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.11.0/go.mod h1:zC9APTIj3jG3FdV/Ons+XE1riIZXG4aZ4GTHiPZJPIU= golang.org/x/term v0.16.0/go.mod h1:yn7UURbUtPyrVJPGPq404EukNFxcm/foM+bV/bfcDsY= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= -golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= -golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= +golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= +golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -362,5 +362,5 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -mvdan.cc/sh/v3 v3.8.0 h1:ZxuJipLZwr/HLbASonmXtcvvC9HXY9d2lXZHnKGjFc8= -mvdan.cc/sh/v3 v3.8.0/go.mod h1:w04623xkgBVo7/IUK89E0g8hBykgEpN0vgOj3RJr6MY= +mvdan.cc/sh/v3 v3.9.0 h1:it14fyjCdQUk4jf/aYxLO3FG8jFarR9GzMCtnlvvD7c= +mvdan.cc/sh/v3 v3.9.0/go.mod h1:cdBk8bgoiBI7lSZqK5JhUuq7OB64VQ7fgm85xelw3Nk= diff --git a/pkg/auth/auth.go b/pkg/auth/auth.go new file mode 100644 index 00000000..2948f5d5 --- /dev/null +++ b/pkg/auth/auth.go @@ -0,0 +1,11 @@ +package auth + +import ( + "net/http" +) + +func NewHeaderWithToken(token string) http.Header { + header := make(http.Header) + header.Set("Authorization", "Bearer "+token) + return header +} diff --git a/pkg/bootstrap/bootstrap.go b/pkg/bootstrap/bootstrap.go index f249a943..a04dc985 100644 --- a/pkg/bootstrap/bootstrap.go +++ b/pkg/bootstrap/bootstrap.go @@ -19,6 +19,8 @@ package bootstrap import ( "context" + "encoding/json" + "errors" "io" "io/fs" "net/http" @@ -33,14 +35,19 @@ import ( "github.com/go-task/task/v3/taskfile/ast" "github.com/joho/godotenv" "gopkg.in/yaml.v3" + + authutil "github.com/livekit/livekit-cli/pkg/auth" ) const ( - EnvExampleFile = ".env.example" - EnvLocalFile = ".env.local" - TaskFile = "taskfile.yaml" - TemplateIndexFile = "templates.yaml" - TemplateIndexURL = "https://raw.githubusercontent.com/livekit-examples/index/main" + EnvExampleFile = ".env.example" + EnvLocalFile = ".env.local" + TaskFile = "taskfile.yaml" + TemplateIndexFile = "templates.yaml" + TemplateIndexURL = "https://raw.githubusercontent.com/livekit-examples/index/main" + TemplateBaseURL = "https://github.com/livekit-examples" + SandboxDashboardURL = "https://cloud.livekit.io/projects/p_/sandbox" + SandboxTemplateEndpoint = "/api/sandbox/template" ) type KnownTask string @@ -62,6 +69,11 @@ type Template struct { IsSandbox bool `yaml:"is_sandbox" json:"is_sandbox,omitempty"` } +type SandboxDetails struct { + Name string `json:"name"` + Template Template `json:"template"` +} + func FetchTemplates(ctx context.Context) ([]Template, error) { resp, err := http.Get(TemplateIndexURL + "/" + TemplateIndexFile) if err != nil { @@ -75,6 +87,31 @@ func FetchTemplates(ctx context.Context) ([]Template, error) { return templates, nil } +func FetchSandboxDetails(ctx context.Context, sid, token, serverURL string) (*SandboxDetails, error) { + req, err := http.NewRequestWithContext(ctx, "GET", serverURL+SandboxTemplateEndpoint, nil) + req.Header = authutil.NewHeaderWithToken(token) + query := req.URL.Query() + query.Add("id", sid) + req.URL.RawQuery = query.Encode() + if err != nil { + return nil, err + } + + resp, err := http.DefaultClient.Do(req) + if err != nil { + return nil, err + } + if resp.StatusCode != 200 { + return nil, errors.New(resp.Status) + } + + var details SandboxDetails + if err := json.NewDecoder(resp.Body).Decode(&details); err != nil { + return nil, err + } + return &details, nil +} + func ParseTaskfile(rootPath string) (*ast.Taskfile, error) { file, err := os.ReadFile(path.Join(rootPath, TaskFile)) if err != nil { diff --git a/version.go b/version.go index a21dbd08..ec7193a8 100644 --- a/version.go +++ b/version.go @@ -15,5 +15,5 @@ package livekitcli const ( - Version = "2.1.2" + Version = "2.1.3" )