diff --git a/Makefile b/Makefile index 981c9c4846012..f3e1bfc8b0317 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,10 @@ INSTALL_DIR=$(shell go env GOPATH)/bin +GOOS=$(shell go env GOOS) +GOARCH=$(shell go env GOARCH) bin/coder: mkdir -p bin - go build -o bin/coder cmd/coder/main.go + GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o bin/coder-$(GOOS)-$(GOARCH) cmd/coder/main.go .PHONY: bin/coder bin/coderd: @@ -10,7 +12,12 @@ bin/coderd: go build -o bin/coderd cmd/coderd/main.go .PHONY: bin/coderd -build: site/out bin/coder bin/coderd +bin/terraform-provider-coder: + mkdir -p bin + go build -o bin/terraform-provider-coder cmd/terraform-provider-coder/main.go +.PHONY: bin/terraform-provider-coder + +build: site/out bin/coder bin/coderd bin/terraform-provider-coder .PHONY: build # Runs migrations to output a dump of the database. @@ -59,6 +66,11 @@ install: @echo "-- CLI available at $(shell ls $(INSTALL_DIR)/coder*)" .PHONY: install +install/terraform-provider-coder: bin/terraform-provider-coder + $(eval OS_ARCH := $(shell go env GOOS)_$(shell go env GOARCH)) + mkdir -p ~/.terraform.d/plugins/coder.com/internal/coder/0.2/$(OS_ARCH) + cp bin/terraform-provider-coder ~/.terraform.d/plugins/coder.com/internal/coder/0.2/$(OS_ARCH) + peerbroker/proto: peerbroker/proto/peerbroker.proto protoc \ --go_out=. \ diff --git a/cmd/terraform-provider-coder/main.go b/cmd/terraform-provider-coder/main.go new file mode 100644 index 0000000000000..9102d33e461ef --- /dev/null +++ b/cmd/terraform-provider-coder/main.go @@ -0,0 +1,13 @@ +package main + +import ( + "github.com/hashicorp/terraform-plugin-sdk/v2/plugin" + + "github.com/coder/coder/provisioner/terraform/provider" +) + +func main() { + plugin.Serve(&plugin.ServeOpts{ + ProviderFunc: provider.New, + }) +} diff --git a/coderd/coderd.go b/coderd/coderd.go index ab9f207fe1e15..4de6135890f11 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -116,9 +116,9 @@ func New(options *Options) (http.Handler, func()) { }) }) - r.Route("/files", func(r chi.Router) { + r.Route("/upload", func(r chi.Router) { r.Use(httpmw.ExtractAPIKey(options.Database, nil)) - r.Post("/", api.postFiles) + r.Post("/", api.postUpload) }) r.Route("/projectimport/{organization}", func(r chi.Router) { diff --git a/coderd/files.go b/coderd/files.go index 069509c567ca6..e25ccd8d749b0 100644 --- a/coderd/files.go +++ b/coderd/files.go @@ -18,7 +18,7 @@ type UploadFileResponse struct { Hash string `json:"hash"` } -func (api *api) postFiles(rw http.ResponseWriter, r *http.Request) { +func (api *api) postUpload(rw http.ResponseWriter, r *http.Request) { apiKey := httpmw.APIKey(r) contentType := r.Header.Get("Content-Type") diff --git a/coderd/files_test.go b/coderd/files_test.go index 77f4085832771..ad00a6c5b656e 100644 --- a/coderd/files_test.go +++ b/coderd/files_test.go @@ -10,7 +10,7 @@ import ( "github.com/coder/coder/codersdk" ) -func TestPostFiles(t *testing.T) { +func TestPostUpload(t *testing.T) { t.Parallel() t.Run("BadContentType", func(t *testing.T) { t.Parallel() diff --git a/coderd/provisionerdaemons.go b/coderd/provisionerdaemons.go index 9f45ff2d6027a..95d212df7a13e 100644 --- a/coderd/provisionerdaemons.go +++ b/coderd/provisionerdaemons.go @@ -516,16 +516,20 @@ func (server *provisionerdServer) CompleteJob(ctx context.Context, completed *pr } // This could be a bulk insert to improve performance. for _, protoResource := range jobType.WorkspaceProvision.Resources { + var instanceID sql.NullString + if protoResource.Agent != nil && protoResource.Agent.GetGoogleInstanceIdentity() != nil { + instanceID = sql.NullString{ + String: protoResource.Agent.GetGoogleInstanceIdentity().InstanceId, + Valid: true, + } + } _, err = db.InsertWorkspaceResource(ctx, database.InsertWorkspaceResourceParams{ ID: uuid.New(), CreatedAt: database.Now(), WorkspaceHistoryID: input.WorkspaceHistoryID, - InstanceID: sql.NullString{ - Valid: protoResource.InstanceId != "", - String: protoResource.InstanceId, - }, - Type: protoResource.Type, - Name: protoResource.Name, + Type: protoResource.Type, + Name: protoResource.Name, + InstanceID: instanceID, // TODO: Generate this at the variable validation phase. // Set the value in `default_source`, and disallow overwrite. WorkspaceAgentToken: uuid.NewString(), diff --git a/coderd/workspaceagent_test.go b/coderd/workspaceagent_test.go index 86487c4c90275..c48dfc75af1d1 100644 --- a/coderd/workspaceagent_test.go +++ b/coderd/workspaceagent_test.go @@ -74,9 +74,15 @@ func TestPostWorkspaceAgentAuthenticateGoogleInstanceIdentity(t *testing.T) { Type: &proto.Provision_Response_Complete{ Complete: &proto.Provision_Complete{ Resources: []*proto.Resource{{ - Name: "somename", - Type: "someinstance", - InstanceId: instanceID, + Name: "somename", + Type: "someinstance", + Agent: &proto.Agent{ + Auth: &proto.Agent_GoogleInstanceIdentity{ + GoogleInstanceIdentity: &proto.GoogleInstanceIdentityAuth{ + InstanceId: instanceID, + }, + }, + }, }}, }, }, diff --git a/codersdk/files.go b/codersdk/files.go index f4fe82f8cd146..226391740e4b7 100644 --- a/codersdk/files.go +++ b/codersdk/files.go @@ -3,7 +3,9 @@ package codersdk import ( "context" "encoding/json" + "fmt" "net/http" + "net/url" "github.com/coder/coder/coderd" ) @@ -13,7 +15,7 @@ const ( ) func (c *Client) UploadFile(ctx context.Context, contentType string, content []byte) (coderd.UploadFileResponse, error) { - res, err := c.request(ctx, http.MethodPost, "/api/v2/files", content, func(r *http.Request) { + res, err := c.request(ctx, http.MethodPost, "/api/v2/upload", content, func(r *http.Request) { r.Header.Set("Content-Type", contentType) }) if err != nil { @@ -26,3 +28,8 @@ func (c *Client) UploadFile(ctx context.Context, contentType string, content []b var resp coderd.UploadFileResponse return resp, json.NewDecoder(res.Body).Decode(&resp) } + +// DownloadURL returns the download URL for the specified asset +func (c *Client) DownloadURL(asset string) (*url.URL, error) { + return c.URL.Parse(fmt.Sprintf("/api/v2/downloads/%s", asset)) +} diff --git a/go.mod b/go.mod index 40e1fe657e18e..35569e6f1ec01 100644 --- a/go.mod +++ b/go.mod @@ -37,6 +37,7 @@ require ( github.com/hashicorp/go-version v1.4.0 github.com/hashicorp/terraform-config-inspect v0.0.0-20211115214459-90acf1ca460f github.com/hashicorp/terraform-exec v0.15.0 + github.com/hashicorp/terraform-plugin-sdk/v2 v2.10.1 github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 github.com/justinas/nosurf v1.1.1 github.com/kirsle/configdir v0.0.0-20170128060238-e45d2f54772f @@ -96,10 +97,22 @@ require ( github.com/google/go-cmp v0.5.7 // indirect github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect + github.com/hashicorp/go-checkpoint v0.5.0 // indirect + github.com/hashicorp/go-cleanhttp v0.5.2 // indirect + github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect + github.com/hashicorp/go-hclog v1.0.0 // indirect github.com/hashicorp/go-multierror v1.1.1 // indirect + github.com/hashicorp/go-plugin v1.4.1 // indirect + github.com/hashicorp/go-uuid v1.0.2 // indirect + github.com/hashicorp/hc-install v0.3.1 // indirect github.com/hashicorp/hcl v1.0.0 // indirect github.com/hashicorp/hcl/v2 v2.11.1 // indirect + github.com/hashicorp/logutils v1.0.0 // indirect github.com/hashicorp/terraform-json v0.13.0 // indirect + github.com/hashicorp/terraform-plugin-go v0.5.0 // indirect + github.com/hashicorp/terraform-plugin-log v0.2.0 // indirect + github.com/hashicorp/terraform-registry-address v0.0.0-20210412075316-9b2996cce896 // indirect + github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 // indirect github.com/imdario/mergo v0.3.12 // indirect github.com/inconshreveable/mousetrap v1.0.0 // indirect github.com/juju/ansiterm v0.0.0-20210929141451-8b71cc96ebdc // indirect @@ -107,8 +120,12 @@ require ( github.com/leodido/go-urn v1.2.1 // indirect github.com/lunixbochs/vtclean v1.0.0 // indirect github.com/mattn/go-colorable v0.1.12 // indirect + github.com/mitchellh/copystructure v1.2.0 // indirect + github.com/mitchellh/go-testing-interface v1.14.1 // indirect github.com/mitchellh/go-wordwrap v1.0.1 // indirect + github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/moby/term v0.0.0-20210619224110-3f7ff695adc6 // indirect + github.com/oklog/run v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.0.2 // indirect github.com/opencontainers/runc v1.1.0 // indirect @@ -129,6 +146,7 @@ require ( github.com/pmezard/go-difflib v1.0.0 // indirect github.com/sirupsen/logrus v1.8.1 // indirect github.com/spf13/pflag v1.0.5 // indirect + github.com/vmihailenco/msgpack v4.0.4+incompatible // indirect github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect github.com/xeipuuv/gojsonschema v1.2.0 // indirect diff --git a/go.sum b/go.sum index 55f6d6c8cc674..6c5de14b22110 100644 --- a/go.sum +++ b/go.sum @@ -15,6 +15,7 @@ cloud.google.com/go v0.53.0/go.mod h1:fp/UouUEsRkN6ryDKNW/Upv/JBKnv6WDthjR6+vze6 cloud.google.com/go v0.54.0/go.mod h1:1rq2OEkV3YMf6n/9ZvGWI3GWw0VoqH/1x2nd8Is/bPc= cloud.google.com/go v0.56.0/go.mod h1:jr7tqZxxKOVYizybht9+26Z/gUq7tiRzu+ACVAMbKVk= cloud.google.com/go v0.57.0/go.mod h1:oXiQ6Rzq3RAkkY7N6t3TcE6jE+CIBBbA36lwQ1JyzZs= +cloud.google.com/go v0.61.0/go.mod h1:XukKJg4Y7QsUu0Hxg3qQKUWR4VuWivmyMK2+rUyxAqw= cloud.google.com/go v0.62.0/go.mod h1:jmCYTdRCQuc1PHIIJ/maLInMho30T/Y0M4hTdTShOYc= cloud.google.com/go v0.65.0/go.mod h1:O5N8zS7uWy9vkA9vayVHs65eM1ubvY4h553ofrNHObY= cloud.google.com/go v0.72.0/go.mod h1:M+5Vjvlc2wnp6tjzE102Dw08nGShTscUx2nZMufOKPI= @@ -140,9 +141,13 @@ github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuW github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/apache/arrow/go/arrow v0.0.0-20210818145353-234c94e4ce64/go.mod h1:2qMFB56yOP3KzkB3PbYZ4AlUFg3a88F67TIx5lB/WwY= github.com/apache/arrow/go/arrow v0.0.0-20211013220434-5962184e7a30/go.mod h1:Q7yQnSMnLvcXlZ8RV+jwz/6y1rQTqbX6C82SndT52Zs= +github.com/apparentlymart/go-cidr v1.0.1/go.mod h1:EBcsNrHc3zQeuaeCeCtQruQm+n9/YjEn/vI25Lg7Gwc= github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= +github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 h1:MzVXffFUye+ZcSR6opIgz9Co7WcDx6ZcY+RjfFHoA0I= +github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= github.com/apparentlymart/go-textseg v1.0.0 h1:rRmlIsPEEhUTIKQb7T++Nz/A5Q6C9IuX2wFoYVvnCs0= github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= +github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= github.com/apparentlymart/go-textseg/v13 v13.0.0/go.mod h1:ZK2fH7c4NqDTLtiYLvIkEghdlcqw7yxLeM89kiTRPUo= github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o= @@ -155,6 +160,7 @@ github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkY github.com/asaskevich/govalidator v0.0.0-20190424111038-f61b66f89f4a/go.mod h1:lB+ZfQJz7igIIfQNfa7Ml4HSf2uFQQRzpGGRXenZAgY= github.com/aws/aws-sdk-go v1.15.11/go.mod h1:mFuSZ37Z9YOHbQEwBWztmVzqXrEkub65tZoCYDt7FT0= github.com/aws/aws-sdk-go v1.17.7/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= +github.com/aws/aws-sdk-go v1.25.3/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/aws/aws-sdk-go-v2 v1.8.0/go.mod h1:xEFuWz+3TYdlPRuo+CqATbeDWIWyaT5uAPwPaWtgse0= github.com/aws/aws-sdk-go-v2 v1.9.2/go.mod h1:cK/D0BBs0b/oWPIcX/Z/obahJK1TT7IPVjy53i/mX/4= github.com/aws/aws-sdk-go-v2/config v1.6.0/go.mod h1:TNtBVmka80lRPk5+S9ZqVfFszOQAGJJ9KbT3EM3CHNU= @@ -674,12 +680,19 @@ github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FK github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU= github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.2 h1:035FKYIWjmULyFRBKPs8TBQoi0x6d9G4xc9neXJWAZQ= github.com/hashicorp/go-cleanhttp v0.5.2/go.mod h1:kO/YDlP8L1346E6Sodw+PrpBSV4/SoxCXGY6BqNFT48= +github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 h1:1/D3zfFHttUKaCaGKZ/dR2roBXv0vKbSCnssIldfQdI= +github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320/go.mod h1:EiZBMaudVLy8fmjf9Npq1dq9RalhveqZG5w/yz3mHWs= +github.com/hashicorp/go-hclog v0.0.0-20180709165350-ff2cf002a8dd/go.mod h1:9bjs9uLqI8l75knNv3lV1kA55veR+WUPSiKIWcQHudI= github.com/hashicorp/go-hclog v0.12.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.14.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v0.16.1/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= +github.com/hashicorp/go-hclog v1.0.0 h1:bkKf0BeBXcSYa7f5Fyi9gMuQ8gNsxeiNpZjR6VxNZeo= github.com/hashicorp/go-hclog v1.0.0/go.mod h1:whpDNt7SSdeAju8AWKIWsul05p54N/39EeqMAyrmvFQ= github.com/hashicorp/go-immutable-radix v1.0.0/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= github.com/hashicorp/go-immutable-radix v1.3.1/go.mod h1:0y9vanUI8NX6FsYoO3zeMjhV/C5i9g4Q3DwcSNZ4P60= @@ -689,12 +702,18 @@ github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHh github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.3.0/go.mod h1:F9eH4LrE/ZsRdbwhfjs9k9HoDUwAHnYtXdgmf1AVNs0= +github.com/hashicorp/go-plugin v1.4.1 h1:6UltRQlLN9iZO513VveELp5xyaFxVD2+1OVylE+2E+w= +github.com/hashicorp/go-plugin v1.4.1/go.mod h1:5fGEH17QVwTTcR0zV7yhDPLLmFX9YSZ38b18Udy6vYQ= github.com/hashicorp/go-retryablehttp v0.5.3/go.mod h1:9B5zBasrRhHXnJnui7y6sL7es7NDiJgTc6Er0maI1Xs= github.com/hashicorp/go-rootcerts v1.0.2/go.mod h1:pqUvnprVnM5bf7AOirdbb01K4ccR319Vf4pU3K5EGc8= github.com/hashicorp/go-sockaddr v1.0.0/go.mod h1:7Xibr9yA9JjQq1JpNB2Vw7kxv8xerXegt+ozgdvDeDU= github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdvsLplgctolz4= github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= +github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.2.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.3.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go-version v1.4.0 h1:aAQzgqIrRKRa7w75CKpbBxYsmUoPjzVm1W59ca1L0J4= github.com/hashicorp/go-version v1.4.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= @@ -707,8 +726,10 @@ github.com/hashicorp/hcl v0.0.0-20170504190234-a4b07c25de5f/go.mod h1:oZtUIOe8dh github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hashicorp/hcl/v2 v2.0.0/go.mod h1:oVVDG71tEinNGYCxinCYadcmKU9bglqW9pV3txagJ90= +github.com/hashicorp/hcl/v2 v2.3.0/go.mod h1:d+FwDBbOLvpAM3Z6J7gPj/VoAGkNe/gm352ZhjJ/Zv8= github.com/hashicorp/hcl/v2 v2.11.1 h1:yTyWcXcm9XB0TEkyU/JCRU6rYy4K+mgLtzn2wlrJbcc= github.com/hashicorp/hcl/v2 v2.11.1/go.mod h1:FwWsfWEjyV/CMj8s/gqAuiviY72rJ1/oayI9WftqcKg= +github.com/hashicorp/logutils v1.0.0 h1:dLEQVugN8vlakKOUE3ihGLTZJRB4j+M2cdTm/ORI65Y= github.com/hashicorp/logutils v1.0.0/go.mod h1:QIAnNjmIWmVIIkWDTG1z5v++HQmx9WQRO+LraFDTW64= github.com/hashicorp/mdns v1.0.1/go.mod h1:4gW7WsVCke5TE7EPeYliwHlRUyBtfCwuFwuMg2DmyNY= github.com/hashicorp/mdns v1.0.4/go.mod h1:mtBihi+LeNXGtG8L9dX59gAEa12BDtBQSp4v/YAJqrc= @@ -718,6 +739,18 @@ github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKEN github.com/hashicorp/serf v0.9.6/go.mod h1:TXZNMjZQijwlDvp+r0b63xZ45H7JmCmgg4gpTwn9UV4= github.com/hashicorp/terraform-json v0.13.0 h1:Li9L+lKD1FO5RVFRM1mMMIBDoUHslOniyEi5CM+FWGY= github.com/hashicorp/terraform-json v0.13.0/go.mod h1:y5OdLBCT+rxbwnpxZs9kGL7R9ExU76+cpdY8zHwoazk= +github.com/hashicorp/terraform-plugin-go v0.5.0 h1:+gCDdF0hcYCm0YBTxrP4+K1NGIS5ZKZBKDORBewLJmg= +github.com/hashicorp/terraform-plugin-go v0.5.0/go.mod h1:PAVN26PNGpkkmsvva1qfriae5Arky3xl3NfzKa8XFVM= +github.com/hashicorp/terraform-plugin-log v0.2.0 h1:rjflRuBqCnSk3UHOR25MP1G5BDLKktTA6lNjjcAnBfI= +github.com/hashicorp/terraform-plugin-log v0.2.0/go.mod h1:E1kJmapEHzqu1x6M++gjvhzM2yMQNXPVWZRCB8sgYjg= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.10.1 h1:B9AocC+dxrCqcf4vVhztIkSkt3gpRjUkEka8AmZWGlQ= +github.com/hashicorp/terraform-plugin-sdk/v2 v2.10.1/go.mod h1:FjM9DXWfP0w/AeOtJoSKHBZ01LqmaO6uP4bXhv3fekw= +github.com/hashicorp/terraform-registry-address v0.0.0-20210412075316-9b2996cce896 h1:1FGtlkJw87UsTMg5s8jrekrHmUPUJaMcu6ELiVhQrNw= +github.com/hashicorp/terraform-registry-address v0.0.0-20210412075316-9b2996cce896/go.mod h1:bzBPnUIkI0RxauU8Dqo+2KrZZ28Cf48s8V6IHt3p4co= +github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 h1:HKLsbzeOsfXmKNpr3GiT18XAblV0BjCbzL8KQAMZGa0= +github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734/go.mod h1:kNDNcF7sN4DocDLBkQYz73HGKwN1ANB1blq4lIYLYvg= +github.com/hashicorp/yamux v0.0.0-20180604194846-3520598351bb/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= +github.com/hashicorp/yamux v0.0.0-20181012175058-2f1d1f20f75d/go.mod h1:+NfK9FKeTrX5uv1uIXGdwYDTeHna2qgaIlx54MXqjAM= github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87 h1:xixZ2bWeofWV68J+x6AzmKuVM/JWCQwkWm6GW/MUR6I= github.com/hashicorp/yamux v0.0.0-20211028200310-0bc27b27de87/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -779,6 +812,8 @@ github.com/jackc/puddle v1.1.3/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dv github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4= +github.com/jhump/protoreflect v1.6.0 h1:h5jfMVslIg6l29nsMs0D8Wj17RDVdNYti0vDN/PZZoE= +github.com/jhump/protoreflect v1.6.0/go.mod h1:eaTn3RZAmMBcV0fifFvlm6VHNz3wSkYyXYWUh7ymB74= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/now v1.1.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.0.0-20160202185014-0b12d6b521d8/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= @@ -923,10 +958,14 @@ github.com/miekg/dns v1.1.41/go.mod h1:p6aan82bvRIyn+zDIv9xYNUpwa73JcSh9BKwknJys github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/mistifyio/go-zfs v2.1.2-0.20190413222219-f784269be439+incompatible/go.mod h1:8AuVvqP/mXw1px98n46wfvcGfQ4ci2FwoAjKYxuo3Z4= github.com/mitchellh/cli v1.1.0/go.mod h1:xcISNoH86gajksDmfB23e/pu+B+GeFRMYmoHXxx3xhI= +github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw= github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s= github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/go-testing-interface v0.0.0-20171004221916-a61a99592b77/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI= +github.com/mitchellh/go-testing-interface v1.14.1 h1:jrgshOhYAUVNMAJiKbEu7EqAwgJJ2JqpQmpLJOu07cU= +github.com/mitchellh/go-testing-interface v1.14.1/go.mod h1:gfgS7OtZj6MA4U1UrDRp04twqAjfvlZyCfX3sDjEym8= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v1.0.0/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v1.0.1 h1:TLuKupo69TCn6TQSyGxwI1EblZZEsQ0vMlAFQflz0v0= @@ -938,6 +977,7 @@ github.com/mitchellh/mapstructure v1.4.1/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RR github.com/mitchellh/mapstructure v1.4.3 h1:OVowDSCllw/YjdLkam3/sm7wEtOy59d8ndGgCcyj8cs= github.com/mitchellh/mapstructure v1.4.3/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo= github.com/mitchellh/osext v0.0.0-20151018003038-5e2d6d41470f/go.mod h1:OkQIRizQZAeMln+1tSwduZz7+Af5oFlKirV/MSYes2A= +github.com/mitchellh/reflectwalk v1.0.2 h1:G2LzWKi524PWgd3mLHV8Y5k7s6XUvT0Gef6zxSIeXaQ= github.com/mitchellh/reflectwalk v1.0.2/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/moby/locker v1.0.1/go.mod h1:S7SDdo5zpBK84bzzVlKr2V0hz+7x9hWbYC/kq7oQppc= github.com/moby/moby v20.10.12+incompatible h1:MJVrdG0tIQqVJQBTdtooPuZQFIgski5pYTXlcW8ToE0= @@ -970,8 +1010,12 @@ github.com/nakagami/firebirdsql v0.0.0-20190310045651-3c02a58cfed8/go.mod h1:86w github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= github.com/neo4j/neo4j-go-driver v1.8.1-0.20200803113522-b626aa943eba/go.mod h1:ncO5VaFWh0Nrt+4KT4mOZboaczBZcLuHrG+/sUeP8gI= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= +github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce h1:RPclfga2SEJmgMmz2k+Mg7cowZ8yv4Trqw9UsJby758= +github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce/go.mod h1:uFMI8w+ref4v2r9jz+c9i1IfIttS/OkmLfrk1jne5hs= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= +github.com/oklog/run v1.0.0/go.mod h1:dlhp/R75TPv97u0XWUtDeV/lRKWPKSdTuV0TZvrmrQA= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/onsi/ginkgo v0.0.0-20151202141238-7f8ab55aaf3b/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -1231,6 +1275,8 @@ github.com/vishvananda/netns v0.0.0-20180720170159-13995c7128cc/go.mod h1:ZjcWmF github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= github.com/vishvananda/netns v0.0.0-20200728191858-db3c7e526aae/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/vmihailenco/msgpack v3.3.3+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= +github.com/vmihailenco/msgpack v4.0.4+incompatible h1:dSLoQfGFAo3F6OoNhwUmLwVgaUXK79GlxNBwueZn0xI= +github.com/vmihailenco/msgpack v4.0.4+incompatible/go.mod h1:fy3FlTQTDXWkZ7Bh6AcGMlsjHatGryHQYUTf1ShIgkk= github.com/vmihailenco/msgpack/v4 v4.3.12/go.mod h1:gborTTJjAo/GWTqqRjrLCn9pgNN+NXzzngzBKDPIqw4= github.com/vmihailenco/tagparser v0.1.1/go.mod h1:OeAg3pn3UbLjkWt+rN9oFYB6u/cQgqMEUPoW2WPyhdI= github.com/willf/bitset v1.1.11-0.20200630133818-d5bec3311243/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= @@ -1381,6 +1427,7 @@ golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro= golang.org/x/net v0.0.0-20180218175443-cbe0f9307d01/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180530234432-1e491301e022/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180811021610-c39426892332/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= @@ -1407,6 +1454,7 @@ golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20190827160401-ba9fcec4b297/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190923162816-aa69164e4478/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191004110552-13f9640d40b9/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191009170851-d66e71096ffb/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191112182307-2180aed22343/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -1676,6 +1724,7 @@ golang.org/x/tools v0.0.0-20200512131952-2bc93b1c0c88/go.mod h1:EkVYQZoAsY45+roY golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= +golang.org/x/tools v0.0.0-20200713011307-fd294ab11aed/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA= @@ -1755,6 +1804,7 @@ google.golang.org/appengine v1.6.6/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCID google.golang.org/appengine v1.6.7 h1:FZR1q0exgwxzPzp/aF+VccGrSfxfPpkBqjIIEq3ru6c= google.golang.org/appengine v1.6.7/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= google.golang.org/cloud v0.0.0-20151119220103-975617b05ea8/go.mod h1:0H1ncTHf11KCFhTc/+EFRbzSCOZx+VUbRMk55Yv5MYk= +google.golang.org/genproto v0.0.0-20170818010345-ee236bd376b0/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= @@ -1783,6 +1833,7 @@ google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfG google.golang.org/genproto v0.0.0-20200515170657-fc4c6c6a6587/go.mod h1:YsZOwe1myG/8QRHRsmBRE1LrgQY60beZKjly0O1fX9U= google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/genproto v0.0.0-20200618031413-b414f8b61790/go.mod h1:jDfRM7FcilCzHH/e9qn6dsT145K34l5v+OpcnNgKAAA= +google.golang.org/genproto v0.0.0-20200711021454-869866162049/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200729003335-053ba62fc06f/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200804131852-c06518451d9c/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= google.golang.org/genproto v0.0.0-20200825200019-8632dd797987/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no= @@ -1833,6 +1884,7 @@ google.golang.org/genproto v0.0.0-20220218161850-94dd64e39d7c/go.mod h1:kGP+zUP2 google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf h1:SVYXkUz2yZS9FWb2Gm8ivSlbNQzL2Z/NpPKE3RG2jWk= google.golang.org/genproto v0.0.0-20220222213610-43724f9ea8cf/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI= google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= +google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.0/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= @@ -1849,6 +1901,7 @@ google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3Iji google.golang.org/grpc v1.30.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.31.1/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= +google.golang.org/grpc v1.32.0/go.mod h1:N36X2cJ7JwdamYAgDz+s+rVMFjt3numwzf/HckM8pak= google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0= google.golang.org/grpc v1.33.2/go.mod h1:JMHMWHQWaTccqQQlmk3MJZS+GWXOdAesneDmEnv2fbc= google.golang.org/grpc v1.34.0/go.mod h1:WotjhfgOW/POjDeRt8vscBtXq+2VjORFy659qA51WJ8= diff --git a/provisioner/terraform/provider/provider.go b/provisioner/terraform/provider/provider.go new file mode 100644 index 0000000000000..5daa91de54202 --- /dev/null +++ b/provisioner/terraform/provider/provider.go @@ -0,0 +1,165 @@ +package provider + +import ( + "context" + "net/url" + "reflect" + "strings" + + "github.com/google/uuid" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + + "github.com/coder/coder/provisionersdk" +) + +type config struct { + URL *url.URL +} + +// New returns a new Terraform provider. +func New() *schema.Provider { + return &schema.Provider{ + Schema: map[string]*schema.Schema{ + "url": { + Type: schema.TypeString, + Optional: true, + // The "CODER_URL" environment variable is used by default + // as the Access URL when generating scripts. + DefaultFunc: schema.EnvDefaultFunc("CODER_URL", ""), + ValidateFunc: func(i interface{}, s string) ([]string, []error) { + _, err := url.Parse(s) + if err != nil { + return nil, []error{err} + } + return nil, nil + }, + }, + }, + ConfigureContextFunc: func(c context.Context, resourceData *schema.ResourceData) (interface{}, diag.Diagnostics) { + rawURL, ok := resourceData.Get("url").(string) + if !ok { + return nil, diag.Errorf("unexpected type %q for url", reflect.TypeOf(resourceData.Get("url")).String()) + } + if rawURL == "" { + return nil, diag.Errorf("CODER_URL must not be empty; got %q", rawURL) + } + parsed, err := url.Parse(resourceData.Get("url").(string)) + if err != nil { + return nil, diag.FromErr(err) + } + return config{ + URL: parsed, + }, nil + }, + DataSourcesMap: map[string]*schema.Resource{ + "coder_agent_script": { + Description: "TODO", + ReadContext: func(c context.Context, resourceData *schema.ResourceData, i interface{}) diag.Diagnostics { + config, valid := i.(config) + if !valid { + return diag.Errorf("config was unexpected type %q", reflect.TypeOf(i).String()) + } + operatingSystem, valid := resourceData.Get("os").(string) + if !valid { + return diag.Errorf("os was unexpected type %q", reflect.TypeOf(resourceData.Get("os"))) + } + arch, valid := resourceData.Get("arch").(string) + if !valid { + return diag.Errorf("arch was unexpected type %q", reflect.TypeOf(resourceData.Get("arch"))) + } + script, err := provisionersdk.AgentScript(config.URL, operatingSystem, arch) + if err != nil { + return diag.FromErr(err) + } + err = resourceData.Set("value", script) + if err != nil { + return diag.FromErr(err) + } + resourceData.SetId(strings.Join([]string{operatingSystem, arch}, "_")) + return nil + }, + Schema: map[string]*schema.Schema{ + "os": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"linux", "darwin", "windows"}, false), + }, + "arch": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{"amd64"}, false), + }, + "value": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + ResourcesMap: map[string]*schema.Resource{ + "coder_agent": { + Description: "TODO", + CreateContext: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics { + // This should be a real authentication token! + rd.SetId(uuid.NewString()) + err := rd.Set("token", uuid.NewString()) + if err != nil { + return diag.FromErr(err) + } + return nil + }, + ReadContext: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics { + return nil + }, + DeleteContext: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics { + return nil + }, + Schema: map[string]*schema.Schema{ + "auth": { + ForceNew: true, + Description: "TODO", + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "type": { + ForceNew: true, + Description: "TODO", + Optional: true, + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice([]string{"google-instance-identity"}, false), + }, + "instance_id": { + ForceNew: true, + Description: "TODO", + Optional: true, + Type: schema.TypeString, + }, + }, + }, + }, + "env": { + ForceNew: true, + Description: "TODO", + Type: schema.TypeMap, + Optional: true, + }, + "startup_script": { + ForceNew: true, + Description: "TODO", + Type: schema.TypeString, + Optional: true, + }, + "token": { + ForceNew: true, + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, + } +} diff --git a/provisioner/terraform/provider/provider_test.go b/provisioner/terraform/provider/provider_test.go new file mode 100644 index 0000000000000..39348af351ca0 --- /dev/null +++ b/provisioner/terraform/provider/provider_test.go @@ -0,0 +1,123 @@ +package provider_test + +import ( + "fmt" + "testing" + + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/stretchr/testify/require" + + "github.com/coder/coder/provisioner/terraform/provider" +) + +func TestProvider(t *testing.T) { + t.Parallel() + tfProvider := provider.New() + err := tfProvider.InternalValidate() + require.NoError(t, err) +} + +func TestAgentScript(t *testing.T) { + t.Parallel() + resource.Test(t, resource.TestCase{ + Providers: map[string]*schema.Provider{ + "coder": provider.New(), + }, + IsUnitTest: true, + Steps: []resource.TestStep{{ + Config: ` + provider "coder" { + url = "https://example.com" + } + data "coder_agent_script" "new" { + arch = "amd64" + os = "linux" + }`, + Check: func(state *terraform.State) error { + require.Len(t, state.Modules, 1) + require.Len(t, state.Modules[0].Resources, 1) + resource := state.Modules[0].Resources["data.coder_agent_script.new"] + require.NotNil(t, resource) + value := resource.Primary.Attributes["value"] + require.NotNil(t, value) + t.Log(value) + return nil + }, + }}, + }) +} + +func TestAgent(t *testing.T) { + t.Parallel() + t.Run("Empty", func(t *testing.T) { + t.Parallel() + resource.Test(t, resource.TestCase{ + Providers: map[string]*schema.Provider{ + "coder": provider.New(), + }, + IsUnitTest: true, + Steps: []resource.TestStep{{ + Config: ` + provider "coder" { + url = "https://example.com" + } + resource "coder_agent" "new" {}`, + Check: func(state *terraform.State) error { + require.Len(t, state.Modules, 1) + require.Len(t, state.Modules[0].Resources, 1) + resource := state.Modules[0].Resources["coder_agent.new"] + require.NotNil(t, resource) + require.NotNil(t, resource.Primary.Attributes["token"]) + return nil + }, + }}, + }) + }) + + t.Run("Filled", func(t *testing.T) { + t.Parallel() + resource.Test(t, resource.TestCase{ + Providers: map[string]*schema.Provider{ + "coder": provider.New(), + }, + IsUnitTest: true, + Steps: []resource.TestStep{{ + Config: ` + provider "coder" { + url = "https://example.com" + } + resource "coder_agent" "new" { + auth { + type = "google-instance-identity" + instance_id = "instance" + } + env = { + hi = "test" + } + startup_script = "echo test" + }`, + Check: func(state *terraform.State) error { + require.Len(t, state.Modules, 1) + require.Len(t, state.Modules[0].Resources, 1) + resource := state.Modules[0].Resources["coder_agent.new"] + require.NotNil(t, resource) + for _, key := range []string{ + "token", + "auth.0.type", + "auth.0.instance_id", + "env.hi", + "startup_script", + } { + value := resource.Primary.Attributes[key] + t.Log(fmt.Sprintf("%q = %q", key, value)) + require.NotNil(t, value) + require.Greater(t, len(value), 0) + } + return nil + }, + }}, + }) + }) +} diff --git a/provisioner/terraform/provision.go b/provisioner/terraform/provision.go index cf83fbf700292..a06fae5135bf6 100644 --- a/provisioner/terraform/provision.go +++ b/provisioner/terraform/provision.go @@ -12,8 +12,11 @@ import ( "strings" "github.com/hashicorp/terraform-exec/tfexec" + "github.com/mitchellh/mapstructure" "golang.org/x/xerrors" + "cdr.dev/slog" + "github.com/coder/coder/provisionersdk/proto" ) @@ -72,7 +75,8 @@ func (t *terraform) Provision(request *proto.Provision_Request, stream proto.DRP func (t *terraform) runTerraformPlan(ctx context.Context, terraform *tfexec.Terraform, request *proto.Provision_Request, stream proto.DRPCProvisioner_ProvisionStream) error { env := map[string]string{} - options := []tfexec.PlanOption{tfexec.JSON(true)} + planfilePath := filepath.Join(request.Directory, "terraform.tfplan") + options := []tfexec.PlanOption{tfexec.JSON(true), tfexec.Out(planfilePath)} for _, param := range request.ParameterValues { switch param.DestinationScheme { case proto.ParameterDestination_ENVIRONMENT_VARIABLE: @@ -88,7 +92,6 @@ func (t *terraform) runTerraformPlan(ctx context.Context, terraform *tfexec.Terr return xerrors.Errorf("apply environment variables: %w", err) } - resources := make([]*proto.Resource, 0) reader, writer := io.Pipe() defer reader.Close() defer writer.Close() @@ -117,13 +120,6 @@ func (t *terraform) runTerraformPlan(ctx context.Context, terraform *tfexec.Terr }, }) - if log.Change != nil && log.Change.Action == "create" { - resources = append(resources, &proto.Resource{ - Name: log.Change.Resource.ResourceName, - Type: log.Change.Resource.ResourceType, - }) - } - if log.Diagnostic == nil { continue } @@ -148,12 +144,102 @@ func (t *terraform) runTerraformPlan(ctx context.Context, terraform *tfexec.Terr t.logger.Debug(ctx, "running plan") _, err = terraform.Plan(ctx, options...) if err != nil { - return xerrors.Errorf("apply terraform: %w", err) + return xerrors.Errorf("plan terraform: %w", err) } - _ = reader.Close() t.logger.Debug(ctx, "ran plan") + + plan, err := terraform.ShowPlanFile(ctx, planfilePath) + if err != nil { + return xerrors.Errorf("show terraform plan file: %w", err) + } + _ = reader.Close() <-closeChan + resources := make([]*proto.Resource, 0) + agents := map[string]*proto.Agent{} + agentDepends := map[string][]string{} + + // Store all agents inside the maps! + for _, resource := range plan.Config.RootModule.Resources { + if resource.Type != "coder_agent" { + continue + } + agent := &proto.Agent{ + Auth: &proto.Agent_Token{}, + } + if envRaw, has := resource.Expressions["env"]; has { + env, ok := envRaw.ConstantValue.(map[string]string) + if !ok { + return xerrors.Errorf("unexpected type %q for env map", reflect.TypeOf(envRaw.ConstantValue).String()) + } + agent.Env = env + } + if startupScriptRaw, has := resource.Expressions["startup_script"]; has { + startupScript, ok := startupScriptRaw.ConstantValue.(string) + if !ok { + return xerrors.Errorf("unexpected type %q for startup script", reflect.TypeOf(startupScriptRaw.ConstantValue).String()) + } + agent.StartupScript = startupScript + } + if auth, has := resource.Expressions["auth"]; has { + if len(auth.ExpressionData.NestedBlocks) > 0 { + block := auth.ExpressionData.NestedBlocks[0] + authType, has := block["type"] + if has { + authTypeValue, valid := authType.ConstantValue.(string) + if !valid { + return xerrors.Errorf("unexpected type %q for auth type", reflect.TypeOf(authType.ConstantValue)) + } + switch authTypeValue { + case "google-instance-identity": + agent.Auth = &proto.Agent_GoogleInstanceIdentity{ + GoogleInstanceIdentity: &proto.GoogleInstanceIdentityAuth{ + InstanceId: block["instance_id"].ConstantValue.(string), + }, + } + default: + return xerrors.Errorf("unknown auth type: %q", authTypeValue) + } + } + } + } + + resourceKey := strings.Join([]string{resource.Type, resource.Name}, ".") + agents[resourceKey] = agent + agentDepends[resourceKey] = resource.DependsOn + } + + for _, resource := range plan.Config.RootModule.Resources { + if resource.Type == "coder_agent" { + continue + } + var agent *proto.Agent + // Associate resources that depend on an agent. + for _, dep := range resource.DependsOn { + var has bool + agent, has = agents[dep] + if has { + break + } + } + // Associate resources where the agent depends on it. + for agentKey, dependsOn := range agentDepends { + for _, depend := range dependsOn { + if depend != strings.Join([]string{resource.Type, resource.Name}, ".") { + continue + } + agent = agents[agentKey] + break + } + } + + resources = append(resources, &proto.Resource{ + Name: resource.Name, + Type: resource.Type, + Agent: agent, + }) + } + return stream.Send(&proto.Provision_Response{ Type: &proto.Provision_Response_Complete{ Complete: &proto.Provision_Complete{ @@ -228,7 +314,7 @@ func (t *terraform) runTerraformApply(ctx context.Context, terraform *tfexec.Ter }() terraform.SetStdout(writer) - t.logger.Debug(ctx, "running apply") + t.logger.Debug(ctx, "running apply", slog.F("options", options)) err = terraform.Apply(ctx, options...) if err != nil { return xerrors.Errorf("apply terraform: %w", err) @@ -245,18 +331,83 @@ func (t *terraform) runTerraformApply(ctx context.Context, terraform *tfexec.Ter } resources := make([]*proto.Resource, 0) if state.Values != nil { + type agentAttributes struct { + ID string `mapstructure:"id"` + Token string `mapstructure:"token"` + Auth []struct { + Type string `mapstructure:"type"` + InstanceID string `mapstructure:"instance_id"` + } `mapstructure:"auth"` + Env map[string]string `mapstructure:"env"` + StartupScript string `mapstructure:"startup_script"` + } + agents := map[string]*proto.Agent{} + agentDepends := map[string][]string{} + + // Store all agents inside the maps! for _, resource := range state.Values.RootModule.Resources { - var instanceID string - if gcpInstanceID, ok := resource.AttributeValues["instance_id"]; ok { - instanceID, ok = gcpInstanceID.(string) - if !ok { - return xerrors.Errorf("invalid type for instance_id property: %s", reflect.TypeOf(gcpInstanceID).String()) + if resource.Type != "coder_agent" { + continue + } + var attrs agentAttributes + err = mapstructure.Decode(resource.AttributeValues, &attrs) + if err != nil { + return xerrors.Errorf("decode agent attributes: %w", err) + } + agent := &proto.Agent{ + Id: attrs.ID, + Env: attrs.Env, + StartupScript: attrs.StartupScript, + Auth: &proto.Agent_Token{ + Token: attrs.Token, + }, + } + if len(attrs.Auth) > 0 { + auth := attrs.Auth[0] + switch auth.Type { + case "google-instance-identity": + agent.Auth = &proto.Agent_GoogleInstanceIdentity{ + GoogleInstanceIdentity: &proto.GoogleInstanceIdentityAuth{ + InstanceId: auth.InstanceID, + }, + } + default: + return xerrors.Errorf("unknown auth type: %q", auth.Type) } } + resourceKey := strings.Join([]string{resource.Type, resource.Name}, ".") + agents[resourceKey] = agent + agentDepends[resourceKey] = resource.DependsOn + } + + for _, resource := range state.Values.RootModule.Resources { + if resource.Type == "coder_agent" { + continue + } + var agent *proto.Agent + // Associate resources that depend on an agent. + for _, dep := range resource.DependsOn { + var has bool + agent, has = agents[dep] + if has { + break + } + } + // Associate resources where the agent depends on it. + for agentKey, dependsOn := range agentDepends { + for _, depend := range dependsOn { + if depend != strings.Join([]string{resource.Type, resource.Name}, ".") { + continue + } + agent = agents[agentKey] + break + } + } + resources = append(resources, &proto.Resource{ - Name: resource.Name, - Type: resource.Type, - InstanceId: instanceID, + Name: resource.Name, + Type: resource.Type, + Agent: agent, }) } } @@ -276,17 +427,6 @@ type terraformProvisionLog struct { Message string `json:"@message"` Diagnostic *terraformProvisionLogDiagnostic `json:"diagnostic"` - Change *terraformProvisionLogChange `json:"change"` -} - -type terraformProvisionLogChange struct { - Action string `json:"action"` - Resource *terraformProvisionLogResource `json:"resource"` -} - -type terraformProvisionLogResource struct { - ResourceType string `json:"resource_type"` - ResourceName string `json:"resource_name"` } type terraformProvisionLogDiagnostic struct { diff --git a/provisioner/terraform/provision_test.go b/provisioner/terraform/provision_test.go index 90174aea84535..ca1cc0fb9683d 100644 --- a/provisioner/terraform/provision_test.go +++ b/provisioner/terraform/provision_test.go @@ -5,12 +5,18 @@ package terraform_test import ( "context" "encoding/json" + "fmt" "os" + "os/exec" "path/filepath" + "runtime" "testing" "github.com/stretchr/testify/require" + "cdr.dev/slog" + "cdr.dev/slog/sloggers/slogtest" + "github.com/coder/coder/provisioner/terraform" "github.com/coder/coder/provisionersdk" "github.com/coder/coder/provisionersdk/proto" @@ -19,6 +25,37 @@ import ( func TestProvision(t *testing.T) { t.Parallel() + // Build and output the Terraform Provider that is consumed for these tests. + homeDir, err := os.UserHomeDir() + require.NoError(t, err) + providerDest := filepath.Join(homeDir, ".terraform.d", "plugins", "coder.com", "internal", "coder", "0.0.1", fmt.Sprintf("%s_%s", runtime.GOOS, runtime.GOARCH)) + err = os.MkdirAll(providerDest, 0700) + require.NoError(t, err) + //nolint:dogsled + _, filename, _, _ := runtime.Caller(0) + providerSrc := filepath.Join(filepath.Dir(filename), "..", "..", "cmd", "terraform-provider-coder") + output, err := exec.Command("go", "build", "-o", providerDest, providerSrc).CombinedOutput() + if err != nil { + t.Log(string(output)) + } + require.NoError(t, err) + + provider := ` +terraform { + required_providers { + coder = { + source = "coder.com/internal/coder" + version = "0.0.1" + } + } +} + +provider "coder" { + url = "https://example.com" +} + ` + t.Log(provider) + client, server := provisionersdk.TransportPipe() ctx, cancelFunc := context.WithCancel(context.Background()) t.Cleanup(func() { @@ -31,6 +68,7 @@ func TestProvision(t *testing.T) { ServeOptions: &provisionersdk.ServeOptions{ Listener: server, }, + Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug), }) require.NoError(t, err) }() @@ -125,6 +163,127 @@ func TestProvision(t *testing.T) { }, }, }, + }, { + Name: "resource-associated-with-agent", + Files: map[string]string{ + "main.tf": provider + ` + resource "coder_agent" "A" {} + resource "null_resource" "A" { + depends_on = [ + coder_agent.A + ] + }`, + }, + Response: &proto.Provision_Response{ + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{ + Resources: []*proto.Resource{{ + Name: "A", + Type: "null_resource", + Agent: &proto.Agent{ + Auth: &proto.Agent_Token{ + Token: "", + }, + }, + }}, + }, + }, + }, + }, { + Name: "agent-associated-with-resource", + Files: map[string]string{ + "main.tf": provider + ` + resource "coder_agent" "A" { + depends_on = [ + null_resource.A + ] + auth { + type = "google-instance-identity" + instance_id = "an-instance" + } + } + resource "null_resource" "A" {}`, + }, + Response: &proto.Provision_Response{ + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{ + Resources: []*proto.Resource{{ + Name: "A", + Type: "null_resource", + Agent: &proto.Agent{ + Auth: &proto.Agent_GoogleInstanceIdentity{ + GoogleInstanceIdentity: &proto.GoogleInstanceIdentityAuth{ + InstanceId: "an-instance", + }, + }, + }, + }}, + }, + }, + }, + }, { + Name: "dryrun-resource-associated-with-agent", + Files: map[string]string{ + "main.tf": provider + ` + resource "coder_agent" "A" { + } + resource "null_resource" "A" { + depends_on = [ + coder_agent.A + ] + }`, + }, + Request: &proto.Provision_Request{ + DryRun: true, + }, + Response: &proto.Provision_Response{ + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{ + Resources: []*proto.Resource{{ + Name: "A", + Type: "null_resource", + Agent: &proto.Agent{ + Auth: &proto.Agent_Token{}, + }, + }}, + }, + }, + }, + }, { + Name: "dryrun-agent-associated-with-resource", + Files: map[string]string{ + "main.tf": provider + ` + resource "coder_agent" "A" { + depends_on = [ + null_resource.A + ] + auth { + type = "google-instance-identity" + instance_id = "an-instance" + } + } + resource "null_resource" "A" {}`, + }, + Request: &proto.Provision_Request{ + DryRun: true, + }, + Response: &proto.Provision_Response{ + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{ + Resources: []*proto.Resource{{ + Name: "A", + Type: "null_resource", + Agent: &proto.Agent{ + Auth: &proto.Agent_GoogleInstanceIdentity{ + GoogleInstanceIdentity: &proto.GoogleInstanceIdentityAuth{ + InstanceId: "an-instance", + }, + }, + }, + }}, + }, + }, + }, }} { testCase := testCase t.Run(testCase.Name, func(t *testing.T) { @@ -167,6 +326,20 @@ func TestProvision(t *testing.T) { require.Greater(t, len(msg.GetComplete().State), 0) } + // Remove randomly generated data. + for _, resource := range msg.GetComplete().Resources { + if resource.Agent == nil { + continue + } + resource.Agent.Id = "" + if resource.Agent.GetToken() == "" { + continue + } + resource.Agent.Auth = &proto.Agent_Token{ + Token: "", + } + } + resourcesGot, err := json.Marshal(msg.GetComplete().Resources) require.NoError(t, err) diff --git a/provisionersdk/agent.go b/provisionersdk/agent.go new file mode 100644 index 0000000000000..7d97dd38ce70a --- /dev/null +++ b/provisionersdk/agent.go @@ -0,0 +1,71 @@ +package provisionersdk + +import ( + "fmt" + "net/url" + "strings" + + "golang.org/x/xerrors" +) + +var ( + // A mapping of operating-system ($GOOS) to architecture ($GOARCH) + // to agent install and run script. ${DOWNLOAD_URL} is replaced + // with strings.ReplaceAll() when being consumed. + agentScript = map[string]map[string]string{ + "windows": { + "amd64": ` +$ProgressPreference = "SilentlyContinue" +$ErrorActionPreference = "Stop" +Invoke-WebRequest -Uri ${DOWNLOAD_URL} -OutFile $env:TEMP\coder.exe +Start-Process -FilePath $env:TEMP\coder.exe workspaces agent +`, + }, + "linux": { + "amd64": ` +#!/usr/bin/env sh +set -eu pipefail +BINARY_LOCATION=$(mktemp -d)/coder +curl -fsSL ${DOWNLOAD_URL} -o $BINARY_LOCATION +chmod +x $BINARY_LOCATION +exec $BINARY_LOCATION agent +`, + }, + "darwin": { + "amd64": ` +#!/usr/bin/env sh +set -eu pipefail +BINARY_LOCATION=$(mktemp -d)/coder +curl -fsSL ${DOWNLOAD_URL} -o $BINARY_LOCATION +chmod +x $BINARY_LOCATION +exec $BINARY_LOCATION agent +`, + }, + } +) + +// AgentScript returns an installation script for the specified operating system +// and architecture. +func AgentScript(coderURL *url.URL, operatingSystem, architecture string) (string, error) { + architectures, exists := agentScript[operatingSystem] + if !exists { + list := []string{} + for key := range agentScript { + list = append(list, key) + } + return "", xerrors.Errorf("operating system %q not supported. must be in: %v", operatingSystem, list) + } + script, exists := architectures[architecture] + if !exists { + list := []string{} + for key := range architectures { + list = append(list, key) + } + return "", xerrors.Errorf("architecture %q not supported for %q. must be in: %v", architecture, operatingSystem, list) + } + parsed, err := coderURL.Parse(fmt.Sprintf("/bin/coder-%s-%s", operatingSystem, architecture)) + if err != nil { + return "", xerrors.Errorf("parse url: %w", err) + } + return strings.ReplaceAll(script, "${DOWNLOAD_URL}", parsed.String()), nil +} diff --git a/provisionersdk/agent_test.go b/provisionersdk/agent_test.go new file mode 100644 index 0000000000000..b5ba3924f619f --- /dev/null +++ b/provisionersdk/agent_test.go @@ -0,0 +1,62 @@ +//go:build !windows +// +build !windows + +// There isn't a portable Windows binary equivalent to "echo". +// This can be tested, but it's a bit harder. + +package provisionersdk_test + +import ( + "net/http" + "net/http/httptest" + "net/url" + "os" + "os/exec" + "runtime" + "strings" + "testing" + + "github.com/go-chi/render" + "github.com/stretchr/testify/require" + + "github.com/coder/coder/provisionersdk" +) + +func TestAgentScript(t *testing.T) { + t.Parallel() + t.Run("Run", func(t *testing.T) { + t.Parallel() + srv := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + echoPath, err := exec.LookPath("echo") + require.NoError(t, err) + content, err := os.ReadFile(echoPath) + require.NoError(t, err) + render.Status(r, http.StatusOK) + render.Data(rw, r, content) + })) + t.Cleanup(srv.Close) + srvURL, err := url.Parse(srv.URL) + require.NoError(t, err) + script, err := provisionersdk.AgentScript(srvURL, runtime.GOOS, runtime.GOARCH) + require.NoError(t, err) + + output, err := exec.Command("sh", "-c", script).CombinedOutput() + t.Log(string(output)) + require.NoError(t, err) + // Because we use the "echo" binary, we should expect the arguments provided + // as the response to executing our script. + require.Equal(t, "agent", strings.TrimSpace(string(output))) + }) + + t.Run("UnsupportedOS", func(t *testing.T) { + t.Parallel() + _, err := provisionersdk.AgentScript(nil, "unsupported", "") + require.Error(t, err) + }) + + t.Run("UnsupportedArch", func(t *testing.T) { + t.Parallel() + _, err := provisionersdk.AgentScript(nil, runtime.GOOS, "unsupported") + require.Error(t, err) + }) +} diff --git a/provisionersdk/proto/provisioner.pb.go b/provisionersdk/proto/provisioner.pb.go index 1912c35f9044f..f468713d2adde 100644 --- a/provisionersdk/proto/provisioner.pb.go +++ b/provisionersdk/proto/provisioner.pb.go @@ -563,27 +563,174 @@ func (x *Log) GetOutput() string { return "" } +type GoogleInstanceIdentityAuth struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + InstanceId string `protobuf:"bytes,1,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"` +} + +func (x *GoogleInstanceIdentityAuth) Reset() { + *x = GoogleInstanceIdentityAuth{} + if protoimpl.UnsafeEnabled { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[5] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *GoogleInstanceIdentityAuth) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*GoogleInstanceIdentityAuth) ProtoMessage() {} + +func (x *GoogleInstanceIdentityAuth) ProtoReflect() protoreflect.Message { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[5] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use GoogleInstanceIdentityAuth.ProtoReflect.Descriptor instead. +func (*GoogleInstanceIdentityAuth) Descriptor() ([]byte, []int) { + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{5} +} + +func (x *GoogleInstanceIdentityAuth) GetInstanceId() string { + if x != nil { + return x.InstanceId + } + return "" +} + +// Agent represents a running agent on the workspace. +type Agent struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Id string `protobuf:"bytes,1,opt,name=id,proto3" json:"id,omitempty"` + Env map[string]string `protobuf:"bytes,2,rep,name=env,proto3" json:"env,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + StartupScript string `protobuf:"bytes,3,opt,name=startup_script,json=startupScript,proto3" json:"startup_script,omitempty"` + // Types that are assignable to Auth: + // *Agent_Token + // *Agent_GoogleInstanceIdentity + Auth isAgent_Auth `protobuf_oneof:"auth"` +} + +func (x *Agent) Reset() { + *x = Agent{} + if protoimpl.UnsafeEnabled { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[6] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Agent) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Agent) ProtoMessage() {} + +func (x *Agent) ProtoReflect() protoreflect.Message { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[6] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Agent.ProtoReflect.Descriptor instead. +func (*Agent) Descriptor() ([]byte, []int) { + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{6} +} + +func (x *Agent) GetId() string { + if x != nil { + return x.Id + } + return "" +} + +func (x *Agent) GetEnv() map[string]string { + if x != nil { + return x.Env + } + return nil +} + +func (x *Agent) GetStartupScript() string { + if x != nil { + return x.StartupScript + } + return "" +} + +func (m *Agent) GetAuth() isAgent_Auth { + if m != nil { + return m.Auth + } + return nil +} + +func (x *Agent) GetToken() string { + if x, ok := x.GetAuth().(*Agent_Token); ok { + return x.Token + } + return "" +} + +func (x *Agent) GetGoogleInstanceIdentity() *GoogleInstanceIdentityAuth { + if x, ok := x.GetAuth().(*Agent_GoogleInstanceIdentity); ok { + return x.GoogleInstanceIdentity + } + return nil +} + +type isAgent_Auth interface { + isAgent_Auth() +} + +type Agent_Token struct { + Token string `protobuf:"bytes,4,opt,name=token,proto3,oneof"` +} + +type Agent_GoogleInstanceIdentity struct { + // https://cloud.google.com/compute/docs/instances/verifying-instance-identity + GoogleInstanceIdentity *GoogleInstanceIdentityAuth `protobuf:"bytes,5,opt,name=google_instance_identity,json=googleInstanceIdentity,proto3,oneof"` +} + +func (*Agent_Token) isAgent_Auth() {} + +func (*Agent_GoogleInstanceIdentity) isAgent_Auth() {} + // Resource represents created infrastructure. type Resource struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` - Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` - // An optional identifier used for automating Workspace Agent authentication. - // Each cloud has it's own unique instance identity signatures, which can be - // used for zero-token authentication. See: - // GCP: https://cloud.google.com/compute/docs/instances/verifying-instance-identity - // AWS: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html - // Azure: https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service?tabs=linux#get-attested-data - InstanceId string `protobuf:"bytes,3,opt,name=instance_id,json=instanceId,proto3" json:"instance_id,omitempty"` + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Type string `protobuf:"bytes,2,opt,name=type,proto3" json:"type,omitempty"` + Agent *Agent `protobuf:"bytes,3,opt,name=agent,proto3" json:"agent,omitempty"` } func (x *Resource) Reset() { *x = Resource{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[5] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -596,7 +743,7 @@ func (x *Resource) String() string { func (*Resource) ProtoMessage() {} func (x *Resource) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[5] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -609,7 +756,7 @@ func (x *Resource) ProtoReflect() protoreflect.Message { // Deprecated: Use Resource.ProtoReflect.Descriptor instead. func (*Resource) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{5} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{7} } func (x *Resource) GetName() string { @@ -626,11 +773,11 @@ func (x *Resource) GetType() string { return "" } -func (x *Resource) GetInstanceId() string { +func (x *Resource) GetAgent() *Agent { if x != nil { - return x.InstanceId + return x.Agent } - return "" + return nil } // Parse consumes source-code from a directory to produce inputs. @@ -643,7 +790,7 @@ type Parse struct { func (x *Parse) Reset() { *x = Parse{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[6] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -656,7 +803,7 @@ func (x *Parse) String() string { func (*Parse) ProtoMessage() {} func (x *Parse) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[6] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -669,7 +816,7 @@ func (x *Parse) ProtoReflect() protoreflect.Message { // Deprecated: Use Parse.ProtoReflect.Descriptor instead. func (*Parse) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{6} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{8} } // Provision consumes source-code from a directory to produce resources. @@ -682,7 +829,7 @@ type Provision struct { func (x *Provision) Reset() { *x = Provision{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[7] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -695,7 +842,7 @@ func (x *Provision) String() string { func (*Provision) ProtoMessage() {} func (x *Provision) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[7] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -708,7 +855,7 @@ func (x *Provision) ProtoReflect() protoreflect.Message { // Deprecated: Use Provision.ProtoReflect.Descriptor instead. func (*Provision) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{7} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{9} } type Parse_Request struct { @@ -722,7 +869,7 @@ type Parse_Request struct { func (x *Parse_Request) Reset() { *x = Parse_Request{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[8] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -735,7 +882,7 @@ func (x *Parse_Request) String() string { func (*Parse_Request) ProtoMessage() {} func (x *Parse_Request) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[8] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -748,7 +895,7 @@ func (x *Parse_Request) ProtoReflect() protoreflect.Message { // Deprecated: Use Parse_Request.ProtoReflect.Descriptor instead. func (*Parse_Request) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{6, 0} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{8, 0} } func (x *Parse_Request) GetDirectory() string { @@ -769,7 +916,7 @@ type Parse_Complete struct { func (x *Parse_Complete) Reset() { *x = Parse_Complete{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[9] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -782,7 +929,7 @@ func (x *Parse_Complete) String() string { func (*Parse_Complete) ProtoMessage() {} func (x *Parse_Complete) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[9] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -795,7 +942,7 @@ func (x *Parse_Complete) ProtoReflect() protoreflect.Message { // Deprecated: Use Parse_Complete.ProtoReflect.Descriptor instead. func (*Parse_Complete) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{6, 1} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{8, 1} } func (x *Parse_Complete) GetParameterSchemas() []*ParameterSchema { @@ -819,7 +966,7 @@ type Parse_Response struct { func (x *Parse_Response) Reset() { *x = Parse_Response{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[10] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -832,7 +979,7 @@ func (x *Parse_Response) String() string { func (*Parse_Response) ProtoMessage() {} func (x *Parse_Response) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[10] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -845,7 +992,7 @@ func (x *Parse_Response) ProtoReflect() protoreflect.Message { // Deprecated: Use Parse_Response.ProtoReflect.Descriptor instead. func (*Parse_Response) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{6, 2} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{8, 2} } func (m *Parse_Response) GetType() isParse_Response_Type { @@ -899,7 +1046,7 @@ type Provision_Request struct { func (x *Provision_Request) Reset() { *x = Provision_Request{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[11] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -912,7 +1059,7 @@ func (x *Provision_Request) String() string { func (*Provision_Request) ProtoMessage() {} func (x *Provision_Request) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[11] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -925,7 +1072,7 @@ func (x *Provision_Request) ProtoReflect() protoreflect.Message { // Deprecated: Use Provision_Request.ProtoReflect.Descriptor instead. func (*Provision_Request) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{7, 0} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{9, 0} } func (x *Provision_Request) GetDirectory() string { @@ -968,7 +1115,7 @@ type Provision_Complete struct { func (x *Provision_Complete) Reset() { *x = Provision_Complete{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[12] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -981,7 +1128,7 @@ func (x *Provision_Complete) String() string { func (*Provision_Complete) ProtoMessage() {} func (x *Provision_Complete) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[12] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -994,7 +1141,7 @@ func (x *Provision_Complete) ProtoReflect() protoreflect.Message { // Deprecated: Use Provision_Complete.ProtoReflect.Descriptor instead. func (*Provision_Complete) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{7, 1} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{9, 1} } func (x *Provision_Complete) GetState() []byte { @@ -1025,7 +1172,7 @@ type Provision_Response struct { func (x *Provision_Response) Reset() { *x = Provision_Response{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[13] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1038,7 +1185,7 @@ func (x *Provision_Response) String() string { func (*Provision_Response) ProtoMessage() {} func (x *Provision_Response) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[13] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1051,7 +1198,7 @@ func (x *Provision_Response) ProtoReflect() protoreflect.Message { // Deprecated: Use Provision_Response.ProtoReflect.Descriptor instead. func (*Provision_Response) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{7, 2} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{9, 2} } func (m *Provision_Response) GetType() isProvision_Response_Type { @@ -1169,70 +1316,93 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x53, 0x0a, 0x08, 0x52, 0x65, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, - 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x1f, - 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x22, - 0xfc, 0x01, 0x0a, 0x05, 0x50, 0x61, 0x72, 0x73, 0x65, 0x1a, 0x27, 0x0a, 0x07, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, - 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, - 0x72, 0x79, 0x1a, 0x55, 0x0a, 0x08, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x49, - 0x0a, 0x11, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x63, 0x68, 0x65, - 0x6d, 0x61, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, - 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, - 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x1a, 0x73, 0x0a, 0x08, 0x52, 0x65, 0x73, + 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x3d, 0x0a, 0x1a, 0x47, 0x6f, + 0x6f, 0x67, 0x6c, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, + 0x74, 0x69, 0x74, 0x79, 0x41, 0x75, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, + 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x22, 0xaa, 0x02, 0x0a, 0x05, 0x41, 0x67, + 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x02, 0x69, 0x64, 0x12, 0x2d, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, + 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e, 0x76, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x03, 0x65, + 0x6e, 0x76, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x5f, 0x73, 0x63, + 0x72, 0x69, 0x70, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, + 0x74, 0x75, 0x70, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x12, 0x63, 0x0a, 0x18, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x5f, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x05, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x27, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x2e, 0x47, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x41, 0x75, 0x74, 0x68, 0x48, 0x00, 0x52, 0x16, + 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, + 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x1a, 0x36, 0x0a, 0x08, 0x45, 0x6e, 0x76, 0x45, 0x6e, 0x74, + 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x06, + 0x0a, 0x04, 0x61, 0x75, 0x74, 0x68, 0x22, 0x5c, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, + 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x28, 0x0a, 0x05, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x05, 0x61, + 0x67, 0x65, 0x6e, 0x74, 0x22, 0xfc, 0x01, 0x0a, 0x05, 0x50, 0x61, 0x72, 0x73, 0x65, 0x1a, 0x27, + 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x69, + 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x1a, 0x55, 0x0a, 0x08, 0x43, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x74, 0x65, 0x12, 0x49, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, + 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, + 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, + 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, 0x10, 0x70, 0x61, + 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x1a, 0x73, + 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x03, 0x6c, 0x6f, + 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x48, 0x00, 0x52, 0x03, 0x6c, 0x6f, 0x67, + 0x12, 0x39, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, + 0x00, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x74, + 0x79, 0x70, 0x65, 0x22, 0xfc, 0x02, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x1a, 0x9e, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, + 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x46, 0x0a, 0x10, 0x70, + 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, + 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x73, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x72, 0x79, + 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x72, 0x79, 0x52, + 0x75, 0x6e, 0x1a, 0x55, 0x0a, 0x08, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x12, 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, + 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x1a, 0x77, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, - 0x2e, 0x4c, 0x6f, 0x67, 0x48, 0x00, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x12, 0x39, 0x0a, 0x08, 0x63, - 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, - 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x08, 0x63, 0x6f, - 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xfc, - 0x02, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x9e, 0x01, 0x0a, - 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, - 0x63, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x69, 0x72, - 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x46, 0x0a, 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, - 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, - 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x70, - 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x14, - 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, - 0x74, 0x61, 0x74, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x72, 0x79, 0x5f, 0x72, 0x75, 0x6e, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x64, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x1a, 0x55, 0x0a, - 0x08, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, - 0x33, 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, - 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x73, 0x1a, 0x77, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x12, 0x24, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x48, - 0x00, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x12, 0x3d, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, - 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x08, 0x63, 0x6f, 0x6d, - 0x70, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x2a, 0x3f, 0x0a, - 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, 0x0a, 0x05, 0x54, 0x52, 0x41, - 0x43, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x45, 0x42, 0x55, 0x47, 0x10, 0x01, 0x12, - 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x02, 0x12, 0x08, 0x0a, 0x04, 0x57, 0x41, 0x52, - 0x4e, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x04, 0x32, 0xa1, - 0x01, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x12, 0x42, - 0x0a, 0x05, 0x50, 0x61, 0x72, 0x73, 0x65, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x71, 0x75, - 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, - 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x30, 0x01, 0x12, 0x4e, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, - 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, - 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, - 0x30, 0x01, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, - 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 0x4c, 0x6f, 0x67, 0x48, 0x00, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x12, 0x3d, 0x0a, 0x08, 0x63, + 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, + 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, + 0x70, 0x65, 0x2a, 0x3f, 0x0a, 0x08, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, + 0x0a, 0x05, 0x54, 0x52, 0x41, 0x43, 0x45, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x44, 0x45, 0x42, + 0x55, 0x47, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x49, 0x4e, 0x46, 0x4f, 0x10, 0x02, 0x12, 0x08, + 0x0a, 0x04, 0x57, 0x41, 0x52, 0x4e, 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, + 0x52, 0x10, 0x04, 0x32, 0xa1, 0x01, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x12, 0x42, 0x0a, 0x05, 0x50, 0x61, 0x72, 0x73, 0x65, 0x12, 0x1a, 0x2e, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, + 0x2e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x2e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x12, 0x4e, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x71, + 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x52, 0x65, 0x73, + 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x30, 0x01, 0x42, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, + 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, + 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x73, 0x64, 0x6b, + 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1248,26 +1418,29 @@ func file_provisionersdk_proto_provisioner_proto_rawDescGZIP() []byte { } var file_provisionersdk_proto_provisioner_proto_enumTypes = make([]protoimpl.EnumInfo, 4) -var file_provisionersdk_proto_provisioner_proto_msgTypes = make([]protoimpl.MessageInfo, 14) +var file_provisionersdk_proto_provisioner_proto_msgTypes = make([]protoimpl.MessageInfo, 17) var file_provisionersdk_proto_provisioner_proto_goTypes = []interface{}{ - (LogLevel)(0), // 0: provisioner.LogLevel - (ParameterSource_Scheme)(0), // 1: provisioner.ParameterSource.Scheme - (ParameterDestination_Scheme)(0), // 2: provisioner.ParameterDestination.Scheme - (ParameterSchema_TypeSystem)(0), // 3: provisioner.ParameterSchema.TypeSystem - (*ParameterSource)(nil), // 4: provisioner.ParameterSource - (*ParameterDestination)(nil), // 5: provisioner.ParameterDestination - (*ParameterValue)(nil), // 6: provisioner.ParameterValue - (*ParameterSchema)(nil), // 7: provisioner.ParameterSchema - (*Log)(nil), // 8: provisioner.Log - (*Resource)(nil), // 9: provisioner.Resource - (*Parse)(nil), // 10: provisioner.Parse - (*Provision)(nil), // 11: provisioner.Provision - (*Parse_Request)(nil), // 12: provisioner.Parse.Request - (*Parse_Complete)(nil), // 13: provisioner.Parse.Complete - (*Parse_Response)(nil), // 14: provisioner.Parse.Response - (*Provision_Request)(nil), // 15: provisioner.Provision.Request - (*Provision_Complete)(nil), // 16: provisioner.Provision.Complete - (*Provision_Response)(nil), // 17: provisioner.Provision.Response + (LogLevel)(0), // 0: provisioner.LogLevel + (ParameterSource_Scheme)(0), // 1: provisioner.ParameterSource.Scheme + (ParameterDestination_Scheme)(0), // 2: provisioner.ParameterDestination.Scheme + (ParameterSchema_TypeSystem)(0), // 3: provisioner.ParameterSchema.TypeSystem + (*ParameterSource)(nil), // 4: provisioner.ParameterSource + (*ParameterDestination)(nil), // 5: provisioner.ParameterDestination + (*ParameterValue)(nil), // 6: provisioner.ParameterValue + (*ParameterSchema)(nil), // 7: provisioner.ParameterSchema + (*Log)(nil), // 8: provisioner.Log + (*GoogleInstanceIdentityAuth)(nil), // 9: provisioner.GoogleInstanceIdentityAuth + (*Agent)(nil), // 10: provisioner.Agent + (*Resource)(nil), // 11: provisioner.Resource + (*Parse)(nil), // 12: provisioner.Parse + (*Provision)(nil), // 13: provisioner.Provision + nil, // 14: provisioner.Agent.EnvEntry + (*Parse_Request)(nil), // 15: provisioner.Parse.Request + (*Parse_Complete)(nil), // 16: provisioner.Parse.Complete + (*Parse_Response)(nil), // 17: provisioner.Parse.Response + (*Provision_Request)(nil), // 18: provisioner.Provision.Request + (*Provision_Complete)(nil), // 19: provisioner.Provision.Complete + (*Provision_Response)(nil), // 20: provisioner.Provision.Response } var file_provisionersdk_proto_provisioner_proto_depIdxs = []int32{ 1, // 0: provisioner.ParameterSource.scheme:type_name -> provisioner.ParameterSource.Scheme @@ -1277,22 +1450,25 @@ var file_provisionersdk_proto_provisioner_proto_depIdxs = []int32{ 5, // 4: provisioner.ParameterSchema.default_destination:type_name -> provisioner.ParameterDestination 3, // 5: provisioner.ParameterSchema.validation_type_system:type_name -> provisioner.ParameterSchema.TypeSystem 0, // 6: provisioner.Log.level:type_name -> provisioner.LogLevel - 7, // 7: provisioner.Parse.Complete.parameter_schemas:type_name -> provisioner.ParameterSchema - 8, // 8: provisioner.Parse.Response.log:type_name -> provisioner.Log - 13, // 9: provisioner.Parse.Response.complete:type_name -> provisioner.Parse.Complete - 6, // 10: provisioner.Provision.Request.parameter_values:type_name -> provisioner.ParameterValue - 9, // 11: provisioner.Provision.Complete.resources:type_name -> provisioner.Resource - 8, // 12: provisioner.Provision.Response.log:type_name -> provisioner.Log - 16, // 13: provisioner.Provision.Response.complete:type_name -> provisioner.Provision.Complete - 12, // 14: provisioner.Provisioner.Parse:input_type -> provisioner.Parse.Request - 15, // 15: provisioner.Provisioner.Provision:input_type -> provisioner.Provision.Request - 14, // 16: provisioner.Provisioner.Parse:output_type -> provisioner.Parse.Response - 17, // 17: provisioner.Provisioner.Provision:output_type -> provisioner.Provision.Response - 16, // [16:18] is the sub-list for method output_type - 14, // [14:16] is the sub-list for method input_type - 14, // [14:14] is the sub-list for extension type_name - 14, // [14:14] is the sub-list for extension extendee - 0, // [0:14] is the sub-list for field type_name + 14, // 7: provisioner.Agent.env:type_name -> provisioner.Agent.EnvEntry + 9, // 8: provisioner.Agent.google_instance_identity:type_name -> provisioner.GoogleInstanceIdentityAuth + 10, // 9: provisioner.Resource.agent:type_name -> provisioner.Agent + 7, // 10: provisioner.Parse.Complete.parameter_schemas:type_name -> provisioner.ParameterSchema + 8, // 11: provisioner.Parse.Response.log:type_name -> provisioner.Log + 16, // 12: provisioner.Parse.Response.complete:type_name -> provisioner.Parse.Complete + 6, // 13: provisioner.Provision.Request.parameter_values:type_name -> provisioner.ParameterValue + 11, // 14: provisioner.Provision.Complete.resources:type_name -> provisioner.Resource + 8, // 15: provisioner.Provision.Response.log:type_name -> provisioner.Log + 19, // 16: provisioner.Provision.Response.complete:type_name -> provisioner.Provision.Complete + 15, // 17: provisioner.Provisioner.Parse:input_type -> provisioner.Parse.Request + 18, // 18: provisioner.Provisioner.Provision:input_type -> provisioner.Provision.Request + 17, // 19: provisioner.Provisioner.Parse:output_type -> provisioner.Parse.Response + 20, // 20: provisioner.Provisioner.Provision:output_type -> provisioner.Provision.Response + 19, // [19:21] is the sub-list for method output_type + 17, // [17:19] is the sub-list for method input_type + 17, // [17:17] is the sub-list for extension type_name + 17, // [17:17] is the sub-list for extension extendee + 0, // [0:17] is the sub-list for field type_name } func init() { file_provisionersdk_proto_provisioner_proto_init() } @@ -1362,7 +1538,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Resource); i { + switch v := v.(*GoogleInstanceIdentityAuth); i { case 0: return &v.state case 1: @@ -1374,7 +1550,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Parse); i { + switch v := v.(*Agent); i { case 0: return &v.state case 1: @@ -1386,7 +1562,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Provision); i { + switch v := v.(*Resource); i { case 0: return &v.state case 1: @@ -1398,7 +1574,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Parse_Request); i { + switch v := v.(*Parse); i { case 0: return &v.state case 1: @@ -1410,6 +1586,30 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Provision); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_provisionersdk_proto_provisioner_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Parse_Request); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_provisionersdk_proto_provisioner_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Parse_Complete); i { case 0: return &v.state @@ -1421,7 +1621,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Parse_Response); i { case 0: return &v.state @@ -1433,7 +1633,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Provision_Request); i { case 0: return &v.state @@ -1445,7 +1645,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Provision_Complete); i { case 0: return &v.state @@ -1457,7 +1657,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Provision_Response); i { case 0: return &v.state @@ -1470,11 +1670,15 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } } - file_provisionersdk_proto_provisioner_proto_msgTypes[10].OneofWrappers = []interface{}{ + file_provisionersdk_proto_provisioner_proto_msgTypes[6].OneofWrappers = []interface{}{ + (*Agent_Token)(nil), + (*Agent_GoogleInstanceIdentity)(nil), + } + file_provisionersdk_proto_provisioner_proto_msgTypes[13].OneofWrappers = []interface{}{ (*Parse_Response_Log)(nil), (*Parse_Response_Complete)(nil), } - file_provisionersdk_proto_provisioner_proto_msgTypes[13].OneofWrappers = []interface{}{ + file_provisionersdk_proto_provisioner_proto_msgTypes[16].OneofWrappers = []interface{}{ (*Provision_Response_Log)(nil), (*Provision_Response_Complete)(nil), } @@ -1484,7 +1688,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_provisionersdk_proto_provisioner_proto_rawDesc, NumEnums: 4, - NumMessages: 14, + NumMessages: 17, NumExtensions: 0, NumServices: 1, }, diff --git a/provisionersdk/proto/provisioner.proto b/provisionersdk/proto/provisioner.proto index bcad8d7b312b1..f77d147c0e291 100644 --- a/provisionersdk/proto/provisioner.proto +++ b/provisionersdk/proto/provisioner.proto @@ -64,17 +64,27 @@ message Log { string output = 2; } +message GoogleInstanceIdentityAuth { + string instance_id = 1; +} + +// Agent represents a running agent on the workspace. +message Agent { + string id = 1; + map env = 2; + string startup_script = 3; + oneof auth { + string token = 4; + // https://cloud.google.com/compute/docs/instances/verifying-instance-identity + GoogleInstanceIdentityAuth google_instance_identity = 5; + } +} + // Resource represents created infrastructure. message Resource { string name = 1; string type = 2; - // An optional identifier used for automating Workspace Agent authentication. - // Each cloud has it's own unique instance identity signatures, which can be - // used for zero-token authentication. See: - // GCP: https://cloud.google.com/compute/docs/instances/verifying-instance-identity - // AWS: https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-identity-documents.html - // Azure: https://docs.microsoft.com/en-us/azure/virtual-machines/windows/instance-metadata-service?tabs=linux#get-attested-data - string instance_id = 3; + Agent agent = 3; } // Parse consumes source-code from a directory to produce inputs.