From 48bcf2ccdc8885793252069514a92334712ac1a0 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Thu, 24 Feb 2022 16:37:35 +0000 Subject: [PATCH 01/21] ci: Update DataDog GitHub branch to fallback to GITHUB_REF This was detecting branches, but not our "main" branch before. Hopefully this fixes it! --- scripts/datadog-cireport/main.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/scripts/datadog-cireport/main.go b/scripts/datadog-cireport/main.go index 2c0b3a3e67844..51fb902b1689e 100644 --- a/scripts/datadog-cireport/main.go +++ b/scripts/datadog-cireport/main.go @@ -59,9 +59,16 @@ func main() { } commitParts := strings.Split(string(commitData), ",") + // On pull requests, this will be set! branch := os.Getenv("GITHUB_HEAD_REF") if branch == "" { - branch = os.Getenv("GITHUB_BASE_REF") + githubRef := os.Getenv("GITHUB_REF") + for _, prefix := range []string{"refs/heads/", "refs/tags/"} { + if !strings.HasPrefix(githubRef, prefix) { + continue + } + branch = strings.TrimPrefix(githubRef, prefix) + } } tags := map[string]string{ From eb50cda5f7446b984e328c66ed642286791adefb Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Fri, 25 Feb 2022 17:09:55 +0000 Subject: [PATCH 02/21] Add basic Terraform Provider --- Makefile | 12 +- cmd/terraform-provider-coder/main.go | 12 + coderd/downloads.go | 5 + codersdk/files.go | 7 + go.mod | 18 + go.sum | 53 ++ provisioner/terraform/provider/provider.go | 125 +++++ .../terraform/provider/provider_test.go | 69 +++ provisionersdk/agent.go | 77 +++ provisionersdk/agent_test.go | 51 ++ provisionersdk/proto/provisioner.pb.go | 510 ++++++++++++------ provisionersdk/proto/provisioner.proto | 25 +- 12 files changed, 799 insertions(+), 165 deletions(-) create mode 100644 cmd/terraform-provider-coder/main.go create mode 100644 coderd/downloads.go create mode 100644 provisioner/terraform/provider/provider.go create mode 100644 provisioner/terraform/provider/provider_test.go create mode 100644 provisionersdk/agent.go create mode 100644 provisionersdk/agent_test.go diff --git a/Makefile b/Makefile index 981c9c4846012..ba0fc488443ed 100644 --- a/Makefile +++ b/Makefile @@ -10,7 +10,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 +64,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..2cff70b9d0172 --- /dev/null +++ b/cmd/terraform-provider-coder/main.go @@ -0,0 +1,12 @@ +package main + +import ( + "github.com/coder/coder/provisioner/terraform/provider" + "github.com/hashicorp/terraform-plugin-sdk/v2/plugin" +) + +func main() { + plugin.Serve(&plugin.ServeOpts{ + ProviderFunc: provider.New, + }) +} diff --git a/coderd/downloads.go b/coderd/downloads.go new file mode 100644 index 0000000000000..621347e8b7ff5 --- /dev/null +++ b/coderd/downloads.go @@ -0,0 +1,5 @@ +package coderd + +func downloads() { + +} diff --git a/codersdk/files.go b/codersdk/files.go index f4fe82f8cd146..efd25adae27d7 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" ) @@ -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 +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..8972a4158aaca --- /dev/null +++ b/provisioner/terraform/provider/provider.go @@ -0,0 +1,125 @@ +package provider + +import ( + "context" + "fmt" + + "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" +) + +// New returns a new schema provider for Terraform. +func New() *schema.Provider { + return &schema.Provider{ + Schema: map[string]*schema.Schema{ + "workspace_history_id": { + Type: schema.TypeString, + Optional: true, + }, + }, + DataSourcesMap: map[string]*schema.Resource{ + "coder_agent_script": { + Description: "TODO", + ReadContext: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics { + osRaw := rd.Get("os") + os := osRaw.(string) + + archRaw := rd.Get("arch") + arch := archRaw.(string) + + fmt.Printf("Got OS: %s_%s\n", os, arch) + + err := rd.Set("value", "SOME SCRIPT") + if err != nil { + return diag.FromErr(err) + } + rd.SetId("something") + 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, + }, + "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()) + rd.Set("token", uuid.NewString()) + return nil + }, + ReadContext: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics { + authRaw := rd.Get("auth").([]interface{})[0] + if authRaw != nil { + auth := authRaw.(map[string]interface{}) + fmt.Printf("Auth got %+v\n", auth) + } + + env := rd.Get("env").(map[string]interface{}) + for key, value := range env { + fmt.Printf("Got: %s, %s\n", key, value) + } + 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": { + Description: "TODO", + Optional: true, + Type: schema.TypeString, + }, + "instance_id": { + 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": { + 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..4a59b9fcb2705 --- /dev/null +++ b/provisioner/terraform/provider/provider_test.go @@ -0,0 +1,69 @@ +package provider_test + +import ( + "encoding/json" + "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 TestSomething(t *testing.T) { + resource.Test(t, resource.TestCase{ + Providers: map[string]*schema.Provider{ + "coder": provider.New(), + }, + IsUnitTest: true, + Steps: []resource.TestStep{{ + Config: `data "coder_agent_script" "new" { + arch = "x64" + os = "linux" + }`, + Check: func(s *terraform.State) error { + fmt.Printf("check state: %+v\n", s) + return nil + }, + }}, + }) +} + +func TestAnother(t *testing.T) { + resource.Test(t, resource.TestCase{ + Providers: map[string]*schema.Provider{ + "coder": provider.New(), + }, + IsUnitTest: true, + Steps: []resource.TestStep{{ + Config: `resource "coder_agent" "new" { + auth { + type = "gcp" + } + env = { + test = "some magic value" + } + }`, + Check: func(s *terraform.State) error { + fmt.Printf("State: %+v\n", s) + // for _, mod := range s.Modules { + // fmt.Printf("check state: %+v\n", mod.Resources) + // } + data, _ := json.MarshalIndent(s, "", "\t") + fmt.Printf("Data: %s\n", data) + + return nil + }, + }}, + }) +} diff --git a/provisionersdk/agent.go b/provisionersdk/agent.go new file mode 100644 index 0000000000000..86c26856c3d2a --- /dev/null +++ b/provisionersdk/agent.go @@ -0,0 +1,77 @@ +package provisionersdk + +import ( + "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 +`, + }, + } +) + +// AgentBinaryName returns the binary name for an operating system and agent. +func AgentBinaryName(operatingSystem, architecture string) (string, error) { + +} + +// AgentScript returns an installation script for the specified operating system +// and architecture. +// +// baseURL is +func AgentScript(operatingSystem, architecture string, baseURL *url.URL) (string, error) { + architectures, ok := agentScript[operatingSystem] + if !ok { + 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, ok := architectures[architecture] + if !ok { + 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) + } + if !strings.HasPrefix(baseURL.Path, "/api/v2/downloads") { + + } + + return strings.ReplaceAll(script, "${DOWNLOAD_URL}", baseURL.String()), nil +} diff --git a/provisionersdk/agent_test.go b/provisionersdk/agent_test.go new file mode 100644 index 0000000000000..9e3a0dd23fbcc --- /dev/null +++ b/provisionersdk/agent_test.go @@ -0,0 +1,51 @@ +package provisionersdk_test + +import ( + "net/http" + "net/http/httptest" + "os" + "os/exec" + "runtime" + "strings" + "testing" + + "github.com/coder/coder/provisionersdk" + "github.com/go-chi/render" + "github.com/stretchr/testify/require" +) + +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) { + content, err := os.ReadFile("/usr/bin/echo") + require.NoError(t, err) + render.Status(r, http.StatusOK) + render.Data(rw, r, content) + })) + t.Cleanup(srv.Close) + + script, err := provisionersdk.AgentScript(runtime.GOOS, runtime.GOARCH, srv.URL) + 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("unsupported", "", nil) + require.Error(t, err) + }) + + t.Run("UnsupportedArch", func(t *testing.T) { + t.Parallel() + _, err := provisionersdk.AgentScript(runtime.GOOS, "unsupported", nil) + require.Error(t, err) + }) +} diff --git a/provisionersdk/proto/provisioner.pb.go b/provisionersdk/proto/provisioner.pb.go index 1912c35f9044f..5c158fab41bee 100644 --- a/provisionersdk/proto/provisioner.pb.go +++ b/provisionersdk/proto/provisioner.pb.go @@ -563,27 +563,166 @@ 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 + + Env map[string]string `protobuf:"bytes,3,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,4,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) 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,5,opt,name=token,proto3,oneof"` +} + +type Agent_GoogleInstanceIdentity struct { + // https://cloud.google.com/compute/docs/instances/verifying-instance-identity + GoogleInstanceIdentity *GoogleInstanceIdentityAuth `protobuf:"bytes,6,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 +735,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 +748,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 +765,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 +782,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 +795,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 +808,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 +821,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 +834,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 +847,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 +861,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 +874,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 +887,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 +908,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 +921,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 +934,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 +958,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 +971,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 +984,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 { @@ -893,13 +1032,12 @@ type Provision_Request struct { Directory string `protobuf:"bytes,1,opt,name=directory,proto3" json:"directory,omitempty"` ParameterValues []*ParameterValue `protobuf:"bytes,2,rep,name=parameter_values,json=parameterValues,proto3" json:"parameter_values,omitempty"` State []byte `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"` - DryRun bool `protobuf:"varint,4,opt,name=dry_run,json=dryRun,proto3" json:"dry_run,omitempty"` } 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 +1050,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 +1063,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 { @@ -949,13 +1087,6 @@ func (x *Provision_Request) GetState() []byte { return nil } -func (x *Provision_Request) GetDryRun() bool { - if x != nil { - return x.DryRun - } - return false -} - type Provision_Complete struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -963,12 +1094,13 @@ type Provision_Complete struct { State []byte `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"` Resources []*Resource `protobuf:"bytes,2,rep,name=resources,proto3" json:"resources,omitempty"` + Agents []*Agent `protobuf:"bytes,3,rep,name=agents,proto3" json:"agents,omitempty"` } 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 +1113,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 +1126,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 { @@ -1011,6 +1143,13 @@ func (x *Provision_Complete) GetResources() []*Resource { return nil } +func (x *Provision_Complete) GetAgents() []*Agent { + if x != nil { + return x.Agents + } + return nil +} + type Provision_Response struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1025,7 +1164,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 +1177,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 +1190,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 +1308,94 @@ 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, - 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, + 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, 0x9a, 0x02, 0x0a, 0x05, 0x41, 0x67, + 0x65, 0x6e, 0x74, 0x12, 0x2d, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x03, 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, 0x04, 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, 0x05, 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, 0x06, 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, 0x90, 0x03, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x1a, 0x85, 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, 0x1a, 0x81, 0x01, 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, 0x12, 0x2a, 0x0a, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, + 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 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, 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, 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 +1411,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 +1443,26 @@ 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 + 10, // 15: provisioner.Provision.Complete.agents:type_name -> provisioner.Agent + 8, // 16: provisioner.Provision.Response.log:type_name -> provisioner.Log + 19, // 17: provisioner.Provision.Response.complete:type_name -> provisioner.Provision.Complete + 15, // 18: provisioner.Provisioner.Parse:input_type -> provisioner.Parse.Request + 18, // 19: provisioner.Provisioner.Provision:input_type -> provisioner.Provision.Request + 17, // 20: provisioner.Provisioner.Parse:output_type -> provisioner.Parse.Response + 20, // 21: provisioner.Provisioner.Provision:output_type -> provisioner.Provision.Response + 20, // [20:22] is the sub-list for method output_type + 18, // [18:20] is the sub-list for method input_type + 18, // [18:18] is the sub-list for extension type_name + 18, // [18:18] is the sub-list for extension extendee + 0, // [0:18] is the sub-list for field type_name } func init() { file_provisionersdk_proto_provisioner_proto_init() } @@ -1362,7 +1532,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 +1544,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 +1556,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 +1568,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 +1580,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 +1615,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 +1627,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 +1639,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 +1651,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 +1664,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 +1682,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..8517f4d08c5b6 100644 --- a/provisionersdk/proto/provisioner.proto +++ b/provisionersdk/proto/provisioner.proto @@ -64,17 +64,26 @@ message Log { string output = 2; } +message GoogleInstanceIdentityAuth { + string instance_id = 1; +} + +// Agent represents a running agent on the workspace. +message Agent { + map env = 3; + string startup_script = 4; + oneof auth { + string token = 5; + // https://cloud.google.com/compute/docs/instances/verifying-instance-identity + GoogleInstanceIdentityAuth google_instance_identity = 6; + } +} + // 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. @@ -99,11 +108,11 @@ message Provision { string directory = 1; repeated ParameterValue parameter_values = 2; bytes state = 3; - bool dry_run = 4; } message Complete { bytes state = 1; repeated Resource resources = 2; + repeated Agent agents = 3; } message Response { oneof type { From 773e38f02582be1fbf46a839fcb82dcae6b591fb Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Fri, 25 Feb 2022 20:41:56 +0000 Subject: [PATCH 03/21] Rename post files to upload --- coderd/coderd.go | 4 +- coderd/downloads.go | 5 -- coderd/files.go | 2 +- coderd/files_test.go | 2 +- codersdk/files.go | 2 +- provisioner/terraform/provider/provider.go | 49 ++++++++++++++++--- .../terraform/provider/provider_test.go | 20 +++++--- provisionersdk/agent.go | 20 +++----- 8 files changed, 68 insertions(+), 36 deletions(-) delete mode 100644 coderd/downloads.go 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/downloads.go b/coderd/downloads.go deleted file mode 100644 index 621347e8b7ff5..0000000000000 --- a/coderd/downloads.go +++ /dev/null @@ -1,5 +0,0 @@ -package coderd - -func downloads() { - -} 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/codersdk/files.go b/codersdk/files.go index efd25adae27d7..c7eb642f76b68 100644 --- a/codersdk/files.go +++ b/codersdk/files.go @@ -15,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 { diff --git a/provisioner/terraform/provider/provider.go b/provisioner/terraform/provider/provider.go index 8972a4158aaca..22ee99374a797 100644 --- a/provisioner/terraform/provider/provider.go +++ b/provisioner/terraform/provider/provider.go @@ -3,39 +3,74 @@ package provider import ( "context" "fmt" + "net/url" + "os" + "strings" + "github.com/coder/coder/provisionersdk" "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" ) -// New returns a new schema provider for Terraform. +type config struct { + URL *url.URL +} + +// New returns a new Terraform provider. func New() *schema.Provider { return &schema.Provider{ Schema: map[string]*schema.Schema{ - "workspace_history_id": { + "url": { Type: schema.TypeString, Optional: true, + // The "CODER_URL" environment variable is used by default + // as the Access URL when generating scripts. + DefaultFunc: func() (interface{}, error) { + return os.Getenv("CODER_URL"), nil + }, + 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, rd *schema.ResourceData) (interface{}, diag.Diagnostics) { + rawURL := rd.Get("url").(string) + if rawURL == "" { + return nil, diag.Errorf("CODER_URL must not be empty; got %q", rawURL) + } + parsed, err := url.Parse(rd.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, rd *schema.ResourceData, i interface{}) diag.Diagnostics { + config := i.(config) osRaw := rd.Get("os") os := osRaw.(string) - archRaw := rd.Get("arch") arch := archRaw.(string) - fmt.Printf("Got OS: %s_%s\n", os, arch) - - err := rd.Set("value", "SOME SCRIPT") + script, err := provisionersdk.AgentScript(os, arch, config.URL) + if err != nil { + return diag.FromErr(err) + } + err = rd.Set("value", script) if err != nil { return diag.FromErr(err) } - rd.SetId("something") + rd.SetId(strings.Join([]string{os, arch}, "_")) return nil }, Schema: map[string]*schema.Schema{ diff --git a/provisioner/terraform/provider/provider_test.go b/provisioner/terraform/provider/provider_test.go index 4a59b9fcb2705..bdaa10f43a623 100644 --- a/provisioner/terraform/provider/provider_test.go +++ b/provisioner/terraform/provider/provider_test.go @@ -1,7 +1,6 @@ package provider_test import ( - "encoding/json" "fmt" "testing" @@ -27,8 +26,12 @@ func TestSomething(t *testing.T) { }, IsUnitTest: true, Steps: []resource.TestStep{{ - Config: `data "coder_agent_script" "new" { - arch = "x64" + Config: ` + provider "coder" { + url = "https://example.com" + } + data "coder_agent_script" "new" { + arch = "amd64" os = "linux" }`, Check: func(s *terraform.State) error { @@ -46,7 +49,12 @@ func TestAnother(t *testing.T) { }, IsUnitTest: true, Steps: []resource.TestStep{{ - Config: `resource "coder_agent" "new" { + Config: ` + provider "coder" { + url = "https://example.com" + } + + resource "coder_agent" "new" { auth { type = "gcp" } @@ -59,8 +67,8 @@ func TestAnother(t *testing.T) { // for _, mod := range s.Modules { // fmt.Printf("check state: %+v\n", mod.Resources) // } - data, _ := json.MarshalIndent(s, "", "\t") - fmt.Printf("Data: %s\n", data) + // data, _ := json.MarshalIndent(s, "", "\t") + // fmt.Printf("Data: %s\n", data) return nil }, diff --git a/provisionersdk/agent.go b/provisionersdk/agent.go index 86c26856c3d2a..e78ef67bdc594 100644 --- a/provisionersdk/agent.go +++ b/provisionersdk/agent.go @@ -43,35 +43,29 @@ exec $BINARY_LOCATION agent } ) -// AgentBinaryName returns the binary name for an operating system and agent. -func AgentBinaryName(operatingSystem, architecture string) (string, error) { - -} +// CODER_URL, operating system, and architecture can return the URL of the Coder binary. // AgentScript returns an installation script for the specified operating system // and architecture. // // baseURL is -func AgentScript(operatingSystem, architecture string, baseURL *url.URL) (string, error) { - architectures, ok := agentScript[operatingSystem] - if !ok { +func AgentScript(operatingSystem, architecture string, binaryDownloadURL *url.URL) (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, ok := architectures[architecture] - if !ok { + 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) } - if !strings.HasPrefix(baseURL.Path, "/api/v2/downloads") { - - } - return strings.ReplaceAll(script, "${DOWNLOAD_URL}", baseURL.String()), nil + return strings.ReplaceAll(script, "${DOWNLOAD_URL}", binaryDownloadURL.String()), nil } From 89ca1d7723be9c20197c377c66f0418dcdd76b9c Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 26 Feb 2022 17:43:26 +0000 Subject: [PATCH 04/21] Add tests for resources --- Makefile | 4 +- coderd/provisionerdaemons.go | 8 +- coderd/workspaceagent_test.go | 5 +- provisioner/terraform/provider/provider.go | 16 +--- .../terraform/provider/provider_test.go | 48 +++++++---- provisioner/terraform/provision.go | 13 +-- provisionersdk/agent.go | 14 ++-- provisionersdk/agent_test.go | 16 +++- provisionersdk/proto/provisioner.pb.go | 83 ++++++++++--------- provisionersdk/proto/provisioner.proto | 1 + 10 files changed, 111 insertions(+), 97 deletions(-) diff --git a/Makefile b/Makefile index ba0fc488443ed..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: diff --git a/coderd/provisionerdaemons.go b/coderd/provisionerdaemons.go index 9f45ff2d6027a..72f2761eb5ea4 100644 --- a/coderd/provisionerdaemons.go +++ b/coderd/provisionerdaemons.go @@ -520,12 +520,8 @@ func (server *provisionerdServer) CompleteJob(ctx context.Context, completed *pr 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, // 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..abdcb8b149816 100644 --- a/coderd/workspaceagent_test.go +++ b/coderd/workspaceagent_test.go @@ -74,9 +74,8 @@ 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", }}, }, }, diff --git a/provisioner/terraform/provider/provider.go b/provisioner/terraform/provider/provider.go index 22ee99374a797..8c2b3515f646f 100644 --- a/provisioner/terraform/provider/provider.go +++ b/provisioner/terraform/provider/provider.go @@ -2,16 +2,16 @@ package provider import ( "context" - "fmt" "net/url" "os" "strings" - "github.com/coder/coder/provisionersdk" "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 { @@ -62,7 +62,7 @@ func New() *schema.Provider { archRaw := rd.Get("arch") arch := archRaw.(string) - script, err := provisionersdk.AgentScript(os, arch, config.URL) + script, err := provisionersdk.AgentScript(config.URL, os, arch) if err != nil { return diag.FromErr(err) } @@ -100,16 +100,6 @@ func New() *schema.Provider { return nil }, ReadContext: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics { - authRaw := rd.Get("auth").([]interface{})[0] - if authRaw != nil { - auth := authRaw.(map[string]interface{}) - fmt.Printf("Auth got %+v\n", auth) - } - - env := rd.Get("env").(map[string]interface{}) - for key, value := range env { - fmt.Printf("Got: %s, %s\n", key, value) - } return nil }, DeleteContext: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics { diff --git a/provisioner/terraform/provider/provider_test.go b/provisioner/terraform/provider/provider_test.go index bdaa10f43a623..5bce83ef6b2f2 100644 --- a/provisioner/terraform/provider/provider_test.go +++ b/provisioner/terraform/provider/provider_test.go @@ -19,7 +19,8 @@ func TestProvider(t *testing.T) { require.NoError(t, err) } -func TestSomething(t *testing.T) { +func TestAgentScript(t *testing.T) { + t.Parallel() resource.Test(t, resource.TestCase{ Providers: map[string]*schema.Provider{ "coder": provider.New(), @@ -34,15 +35,22 @@ func TestSomething(t *testing.T) { arch = "amd64" os = "linux" }`, - Check: func(s *terraform.State) error { - fmt.Printf("check state: %+v\n", s) + 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 TestAnother(t *testing.T) { +func TestAgent(t *testing.T) { + t.Parallel() resource.Test(t, resource.TestCase{ Providers: map[string]*schema.Provider{ "coder": provider.New(), @@ -53,23 +61,33 @@ func TestAnother(t *testing.T) { provider "coder" { url = "https://example.com" } - resource "coder_agent" "new" { auth { - type = "gcp" + type = "something" + instance_id = "instance" } env = { - test = "some magic value" + hi = "test" } + startup_script = "echo test" }`, - Check: func(s *terraform.State) error { - fmt.Printf("State: %+v\n", s) - // for _, mod := range s.Modules { - // fmt.Printf("check state: %+v\n", mod.Resources) - // } - // data, _ := json.MarshalIndent(s, "", "\t") - // fmt.Printf("Data: %s\n", data) - + 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 _, k := range []string{ + "token", + "auth.0.type", + "auth.0.instance_id", + "env.hi", + "startup_script", + } { + v := resource.Primary.Attributes[k] + t.Log(fmt.Sprintf("%q = %q", k, v)) + require.NotNil(t, v) + require.Greater(t, len(v), 0) + } return nil }, }}, diff --git a/provisioner/terraform/provision.go b/provisioner/terraform/provision.go index cf83fbf700292..3e82f568023b1 100644 --- a/provisioner/terraform/provision.go +++ b/provisioner/terraform/provision.go @@ -8,7 +8,6 @@ import ( "io" "os" "path/filepath" - "reflect" "strings" "github.com/hashicorp/terraform-exec/tfexec" @@ -246,17 +245,9 @@ func (t *terraform) runTerraformApply(ctx context.Context, terraform *tfexec.Ter resources := make([]*proto.Resource, 0) if state.Values != nil { 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()) - } - } resources = append(resources, &proto.Resource{ - Name: resource.Name, - Type: resource.Type, - InstanceId: instanceID, + Name: resource.Name, + Type: resource.Type, }) } } diff --git a/provisionersdk/agent.go b/provisionersdk/agent.go index e78ef67bdc594..7d97dd38ce70a 100644 --- a/provisionersdk/agent.go +++ b/provisionersdk/agent.go @@ -1,6 +1,7 @@ package provisionersdk import ( + "fmt" "net/url" "strings" @@ -43,13 +44,9 @@ exec $BINARY_LOCATION agent } ) -// CODER_URL, operating system, and architecture can return the URL of the Coder binary. - // AgentScript returns an installation script for the specified operating system // and architecture. -// -// baseURL is -func AgentScript(operatingSystem, architecture string, binaryDownloadURL *url.URL) (string, error) { +func AgentScript(coderURL *url.URL, operatingSystem, architecture string) (string, error) { architectures, exists := agentScript[operatingSystem] if !exists { list := []string{} @@ -66,6 +63,9 @@ func AgentScript(operatingSystem, architecture string, binaryDownloadURL *url.UR } return "", xerrors.Errorf("architecture %q not supported for %q. must be in: %v", architecture, operatingSystem, list) } - - return strings.ReplaceAll(script, "${DOWNLOAD_URL}", binaryDownloadURL.String()), nil + 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 index 9e3a0dd23fbcc..b1f77b79ff25f 100644 --- a/provisionersdk/agent_test.go +++ b/provisionersdk/agent_test.go @@ -1,8 +1,15 @@ +//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" @@ -25,8 +32,9 @@ func TestAgentScript(t *testing.T) { render.Data(rw, r, content) })) t.Cleanup(srv.Close) - - script, err := provisionersdk.AgentScript(runtime.GOOS, runtime.GOARCH, srv.URL) + 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() @@ -39,13 +47,13 @@ func TestAgentScript(t *testing.T) { t.Run("UnsupportedOS", func(t *testing.T) { t.Parallel() - _, err := provisionersdk.AgentScript("unsupported", "", nil) + _, err := provisionersdk.AgentScript(nil, "unsupported", "") require.Error(t, err) }) t.Run("UnsupportedArch", func(t *testing.T) { t.Parallel() - _, err := provisionersdk.AgentScript(runtime.GOOS, "unsupported", nil) + _, 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 5c158fab41bee..8fb2bb5de383f 100644 --- a/provisionersdk/proto/provisioner.pb.go +++ b/provisionersdk/proto/provisioner.pb.go @@ -1032,6 +1032,7 @@ type Provision_Request struct { Directory string `protobuf:"bytes,1,opt,name=directory,proto3" json:"directory,omitempty"` ParameterValues []*ParameterValue `protobuf:"bytes,2,rep,name=parameter_values,json=parameterValues,proto3" json:"parameter_values,omitempty"` State []byte `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"` + DryRun bool `protobuf:"varint,4,opt,name=dry_run,json=dryRun,proto3" json:"dry_run,omitempty"` } func (x *Provision_Request) Reset() { @@ -1087,6 +1088,13 @@ func (x *Provision_Request) GetState() []byte { return nil } +func (x *Provision_Request) GetDryRun() bool { + if x != nil { + return x.DryRun + } + return false +} + type Provision_Complete struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1352,8 +1360,8 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 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, 0x90, 0x03, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x1a, 0x85, 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, + 0x79, 0x70, 0x65, 0x22, 0xa9, 0x03, 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, @@ -1361,41 +1369,42 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 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, 0x1a, 0x81, 0x01, 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, 0x12, 0x2a, 0x0a, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, - 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 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, + 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, 0x81, 0x01, 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, 0x12, 0x2a, 0x0a, 0x06, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x06, + 0x61, 0x67, 0x65, 0x6e, 0x74, 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, } var ( diff --git a/provisionersdk/proto/provisioner.proto b/provisionersdk/proto/provisioner.proto index 8517f4d08c5b6..9236c8bc1d582 100644 --- a/provisionersdk/proto/provisioner.proto +++ b/provisionersdk/proto/provisioner.proto @@ -108,6 +108,7 @@ message Provision { string directory = 1; repeated ParameterValue parameter_values = 2; bytes state = 3; + bool dry_run = 4; } message Complete { bytes state = 1; From 29b574033bed821ccec2c07d4fa12662dbc10ce7 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 26 Feb 2022 17:48:05 +0000 Subject: [PATCH 05/21] Skip instance identity test --- coderd/workspaceagent_test.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/coderd/workspaceagent_test.go b/coderd/workspaceagent_test.go index abdcb8b149816..857b650ecc233 100644 --- a/coderd/workspaceagent_test.go +++ b/coderd/workspaceagent_test.go @@ -29,6 +29,8 @@ import ( ) func TestPostWorkspaceAgentAuthenticateGoogleInstanceIdentity(t *testing.T) { + t.Skip("Will be fixed once the Terraform Provider is implemented!") + t.Parallel() t.Run("Expired", func(t *testing.T) { t.Parallel() From 604e9958a53c2f3f89e9eca99c13cf66ac04fb37 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 26 Feb 2022 19:58:53 +0000 Subject: [PATCH 06/21] Add tests for ensuring agent get's passed through properly --- provisioner/terraform/provider/provider.go | 10 +- .../terraform/provider/provider_test.go | 102 ++++++---- provisioner/terraform/provision.go | 183 +++++++++++++++--- provisioner/terraform/provision_test.go | 171 ++++++++++++++++ provisionersdk/proto/provisioner.pb.go | 125 ++++++------ provisionersdk/proto/provisioner.proto | 10 +- 6 files changed, 466 insertions(+), 135 deletions(-) diff --git a/provisioner/terraform/provider/provider.go b/provisioner/terraform/provider/provider.go index 8c2b3515f646f..74e80559f4e47 100644 --- a/provisioner/terraform/provider/provider.go +++ b/provisioner/terraform/provider/provider.go @@ -115,11 +115,14 @@ func New() *schema.Provider { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "type": { - Description: "TODO", - Optional: true, - Type: schema.TypeString, + 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, @@ -140,6 +143,7 @@ func New() *schema.Provider { 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 index 5bce83ef6b2f2..628b066d84854 100644 --- a/provisioner/terraform/provider/provider_test.go +++ b/provisioner/terraform/provider/provider_test.go @@ -51,45 +51,71 @@ func TestAgentScript(t *testing.T) { func TestAgent(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 = "something" - 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 _, k := range []string{ - "token", - "auth.0.type", - "auth.0.instance_id", - "env.hi", - "startup_script", - } { - v := resource.Primary.Attributes[k] - t.Log(fmt.Sprintf("%q = %q", k, v)) - require.NotNil(t, v) - require.Greater(t, len(v), 0) + t.Run("Empty", func(t *testing.T) { + 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" } - return nil + 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) { + 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 _, k := range []string{ + "token", + "auth.0.type", + "auth.0.instance_id", + "env.hi", + "startup_script", + } { + v := resource.Primary.Attributes[k] + t.Log(fmt.Sprintf("%q = %q", k, v)) + require.NotNil(t, v) + require.Greater(t, len(v), 0) + } + return nil + }, + }}, + }) }) } diff --git a/provisioner/terraform/provision.go b/provisioner/terraform/provision.go index 3e82f568023b1..64cccd25d2c08 100644 --- a/provisioner/terraform/provision.go +++ b/provisioner/terraform/provision.go @@ -10,7 +10,9 @@ import ( "path/filepath" "strings" + "cdr.dev/slog" "github.com/hashicorp/terraform-exec/tfexec" + "github.com/mitchellh/mapstructure" "golang.org/x/xerrors" "github.com/coder/coder/provisionersdk/proto" @@ -71,7 +73,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: @@ -87,7 +90,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() @@ -116,13 +118,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 } @@ -147,12 +142,88 @@ 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 env, has := resource.Expressions["env"]; has { + agent.Env = env.ConstantValue.(map[string]string) + } + if startupScript, has := resource.Expressions["startup_script"]; has { + agent.StartupScript = startupScript.ConstantValue.(string) + } + if auth, has := resource.Expressions["auth"]; has { + if len(auth.ExpressionData.NestedBlocks) > 0 { + block := auth.ExpressionData.NestedBlocks[0] + authType, has := block["type"] + if has { + switch authType.ConstantValue.(string) { + case "google-instance-identity": + agent.Auth = &proto.Agent_GoogleInstanceIdentity{ + GoogleInstanceIdentity: &proto.GoogleInstanceIdentityAuth{ + InstanceId: block["instance_id"].ConstantValue.(string), + }, + } + } + } + } + } + + 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{ @@ -227,7 +298,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) @@ -244,10 +315,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 { + 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, + Name: resource.Name, + Type: resource.Type, + Agent: agent, }) } } @@ -267,17 +411,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..aa59be9727418 100644 --- a/provisioner/terraform/provision_test.go +++ b/provisioner/terraform/provision_test.go @@ -5,10 +5,15 @@ package terraform_test import ( "context" "encoding/json" + "fmt" "os" + "os/exec" "path/filepath" + "runtime" "testing" + "cdr.dev/slog" + "cdr.dev/slog/sloggers/slogtest" "github.com/stretchr/testify/require" "github.com/coder/coder/provisioner/terraform" @@ -19,6 +24,36 @@ 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) + _, 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 +66,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 +161,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 +324,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/proto/provisioner.pb.go b/provisionersdk/proto/provisioner.pb.go index 8fb2bb5de383f..f468713d2adde 100644 --- a/provisionersdk/proto/provisioner.pb.go +++ b/provisionersdk/proto/provisioner.pb.go @@ -616,8 +616,9 @@ type Agent struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Env map[string]string `protobuf:"bytes,3,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,4,opt,name=startup_script,json=startupScript,proto3" json:"startup_script,omitempty"` + 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 @@ -656,6 +657,13 @@ 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 @@ -696,12 +704,12 @@ type isAgent_Auth interface { } type Agent_Token struct { - Token string `protobuf:"bytes,5,opt,name=token,proto3,oneof"` + 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,6,opt,name=google_instance_identity,json=googleInstanceIdentity,proto3,oneof"` + GoogleInstanceIdentity *GoogleInstanceIdentityAuth `protobuf:"bytes,5,opt,name=google_instance_identity,json=googleInstanceIdentity,proto3,oneof"` } func (*Agent_Token) isAgent_Auth() {} @@ -1102,7 +1110,6 @@ type Provision_Complete struct { State []byte `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"` Resources []*Resource `protobuf:"bytes,2,rep,name=resources,proto3" json:"resources,omitempty"` - Agents []*Agent `protobuf:"bytes,3,rep,name=agents,proto3" json:"agents,omitempty"` } func (x *Provision_Complete) Reset() { @@ -1151,13 +1158,6 @@ func (x *Provision_Complete) GetResources() []*Resource { return nil } -func (x *Provision_Complete) GetAgents() []*Agent { - if x != nil { - return x.Agents - } - return nil -} - type Provision_Response struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1320,16 +1320,17 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 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, 0x9a, 0x02, 0x0a, 0x05, 0x41, 0x67, - 0x65, 0x6e, 0x74, 0x12, 0x2d, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 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, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, + 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, 0x05, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, + 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, 0x06, 0x20, + 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, @@ -1360,7 +1361,7 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 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, 0xa9, 0x03, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 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, @@ -1371,40 +1372,37 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 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, 0x81, 0x01, 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, 0x12, 0x2a, 0x0a, 0x06, 0x61, 0x67, - 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x06, - 0x61, 0x67, 0x65, 0x6e, 0x74, 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, + 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, } var ( @@ -1460,18 +1458,17 @@ var file_provisionersdk_proto_provisioner_proto_depIdxs = []int32{ 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 - 10, // 15: provisioner.Provision.Complete.agents:type_name -> provisioner.Agent - 8, // 16: provisioner.Provision.Response.log:type_name -> provisioner.Log - 19, // 17: provisioner.Provision.Response.complete:type_name -> provisioner.Provision.Complete - 15, // 18: provisioner.Provisioner.Parse:input_type -> provisioner.Parse.Request - 18, // 19: provisioner.Provisioner.Provision:input_type -> provisioner.Provision.Request - 17, // 20: provisioner.Provisioner.Parse:output_type -> provisioner.Parse.Response - 20, // 21: provisioner.Provisioner.Provision:output_type -> provisioner.Provision.Response - 20, // [20:22] is the sub-list for method output_type - 18, // [18:20] is the sub-list for method input_type - 18, // [18:18] is the sub-list for extension type_name - 18, // [18:18] is the sub-list for extension extendee - 0, // [0:18] is the sub-list for field type_name + 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() } diff --git a/provisionersdk/proto/provisioner.proto b/provisionersdk/proto/provisioner.proto index 9236c8bc1d582..f77d147c0e291 100644 --- a/provisionersdk/proto/provisioner.proto +++ b/provisionersdk/proto/provisioner.proto @@ -70,12 +70,13 @@ message GoogleInstanceIdentityAuth { // Agent represents a running agent on the workspace. message Agent { - map env = 3; - string startup_script = 4; + string id = 1; + map env = 2; + string startup_script = 3; oneof auth { - string token = 5; + string token = 4; // https://cloud.google.com/compute/docs/instances/verifying-instance-identity - GoogleInstanceIdentityAuth google_instance_identity = 6; + GoogleInstanceIdentityAuth google_instance_identity = 5; } } @@ -113,7 +114,6 @@ message Provision { message Complete { bytes state = 1; repeated Resource resources = 2; - repeated Agent agents = 3; } message Response { oneof type { From f8cab499cf28a8384a5004be96738b30702d271f Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 26 Feb 2022 20:20:01 +0000 Subject: [PATCH 07/21] Fix linting errors --- cmd/terraform-provider-coder/main.go | 3 +- provisioner/terraform/provider/provider.go | 41 ++++++++++++------- .../terraform/provider/provider_test.go | 12 +++--- provisioner/terraform/provision.go | 28 ++++++++++--- provisioner/terraform/provision_test.go | 4 +- provisionersdk/agent_test.go | 3 +- 6 files changed, 63 insertions(+), 28 deletions(-) diff --git a/cmd/terraform-provider-coder/main.go b/cmd/terraform-provider-coder/main.go index 2cff70b9d0172..9102d33e461ef 100644 --- a/cmd/terraform-provider-coder/main.go +++ b/cmd/terraform-provider-coder/main.go @@ -1,8 +1,9 @@ package main import ( - "github.com/coder/coder/provisioner/terraform/provider" "github.com/hashicorp/terraform-plugin-sdk/v2/plugin" + + "github.com/coder/coder/provisioner/terraform/provider" ) func main() { diff --git a/provisioner/terraform/provider/provider.go b/provisioner/terraform/provider/provider.go index 74e80559f4e47..fa0ec83695073 100644 --- a/provisioner/terraform/provider/provider.go +++ b/provisioner/terraform/provider/provider.go @@ -4,6 +4,7 @@ import ( "context" "net/url" "os" + "reflect" "strings" "github.com/google/uuid" @@ -39,12 +40,15 @@ func New() *schema.Provider { }, }, }, - ConfigureContextFunc: func(c context.Context, rd *schema.ResourceData) (interface{}, diag.Diagnostics) { - rawURL := rd.Get("url").(string) + 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(rd.Get("url").(string)) + parsed, err := url.Parse(resourceData.Get("url").(string)) if err != nil { return nil, diag.FromErr(err) } @@ -55,22 +59,28 @@ func New() *schema.Provider { DataSourcesMap: map[string]*schema.Resource{ "coder_agent_script": { Description: "TODO", - ReadContext: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics { - config := i.(config) - osRaw := rd.Get("os") - os := osRaw.(string) - archRaw := rd.Get("arch") - arch := archRaw.(string) - - script, err := provisionersdk.AgentScript(config.URL, os, arch) + 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 = rd.Set("value", script) + err = resourceData.Set("value", script) if err != nil { return diag.FromErr(err) } - rd.SetId(strings.Join([]string{os, arch}, "_")) + resourceData.SetId(strings.Join([]string{operatingSystem, arch}, "_")) return nil }, Schema: map[string]*schema.Schema{ @@ -96,7 +106,10 @@ func New() *schema.Provider { CreateContext: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics { // This should be a real authentication token! rd.SetId(uuid.NewString()) - rd.Set("token", 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 { diff --git a/provisioner/terraform/provider/provider_test.go b/provisioner/terraform/provider/provider_test.go index 628b066d84854..39348af351ca0 100644 --- a/provisioner/terraform/provider/provider_test.go +++ b/provisioner/terraform/provider/provider_test.go @@ -52,6 +52,7 @@ func TestAgentScript(t *testing.T) { 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(), @@ -76,6 +77,7 @@ func TestAgent(t *testing.T) { }) t.Run("Filled", func(t *testing.T) { + t.Parallel() resource.Test(t, resource.TestCase{ Providers: map[string]*schema.Provider{ "coder": provider.New(), @@ -101,17 +103,17 @@ func TestAgent(t *testing.T) { require.Len(t, state.Modules[0].Resources, 1) resource := state.Modules[0].Resources["coder_agent.new"] require.NotNil(t, resource) - for _, k := range []string{ + for _, key := range []string{ "token", "auth.0.type", "auth.0.instance_id", "env.hi", "startup_script", } { - v := resource.Primary.Attributes[k] - t.Log(fmt.Sprintf("%q = %q", k, v)) - require.NotNil(t, v) - require.Greater(t, len(v), 0) + 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 64cccd25d2c08..a06fae5135bf6 100644 --- a/provisioner/terraform/provision.go +++ b/provisioner/terraform/provision.go @@ -8,13 +8,15 @@ import ( "io" "os" "path/filepath" + "reflect" "strings" - "cdr.dev/slog" "github.com/hashicorp/terraform-exec/tfexec" "github.com/mitchellh/mapstructure" "golang.org/x/xerrors" + "cdr.dev/slog" + "github.com/coder/coder/provisionersdk/proto" ) @@ -165,24 +167,38 @@ func (t *terraform) runTerraformPlan(ctx context.Context, terraform *tfexec.Terr agent := &proto.Agent{ Auth: &proto.Agent_Token{}, } - if env, has := resource.Expressions["env"]; has { - agent.Env = env.ConstantValue.(map[string]string) + 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 startupScript, has := resource.Expressions["startup_script"]; has { - agent.StartupScript = startupScript.ConstantValue.(string) + 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 { - switch authType.ConstantValue.(string) { + 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) } } } diff --git a/provisioner/terraform/provision_test.go b/provisioner/terraform/provision_test.go index aa59be9727418..ca1cc0fb9683d 100644 --- a/provisioner/terraform/provision_test.go +++ b/provisioner/terraform/provision_test.go @@ -12,9 +12,10 @@ import ( "runtime" "testing" + "github.com/stretchr/testify/require" + "cdr.dev/slog" "cdr.dev/slog/sloggers/slogtest" - "github.com/stretchr/testify/require" "github.com/coder/coder/provisioner/terraform" "github.com/coder/coder/provisionersdk" @@ -30,6 +31,7 @@ func TestProvision(t *testing.T) { 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() diff --git a/provisionersdk/agent_test.go b/provisionersdk/agent_test.go index b1f77b79ff25f..31e93f89ef438 100644 --- a/provisionersdk/agent_test.go +++ b/provisionersdk/agent_test.go @@ -16,9 +16,10 @@ import ( "strings" "testing" - "github.com/coder/coder/provisionersdk" "github.com/go-chi/render" "github.com/stretchr/testify/require" + + "github.com/coder/coder/provisionersdk" ) func TestAgentScript(t *testing.T) { From 444109d82bd89de377bc6307b153878dcd57109d Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 26 Feb 2022 20:56:03 +0000 Subject: [PATCH 08/21] Add echo path --- provisionersdk/agent_test.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/provisionersdk/agent_test.go b/provisionersdk/agent_test.go index 31e93f89ef438..b5ba3924f619f 100644 --- a/provisionersdk/agent_test.go +++ b/provisionersdk/agent_test.go @@ -27,7 +27,9 @@ func TestAgentScript(t *testing.T) { t.Run("Run", func(t *testing.T) { t.Parallel() srv := httptest.NewServer(http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { - content, err := os.ReadFile("/usr/bin/echo") + 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) From 108f1b5f0c8061539f5b46eb32cbdd3c71a064e8 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sat, 26 Feb 2022 21:51:22 +0000 Subject: [PATCH 09/21] Fix agent authentication --- coderd/provisionerdaemons.go | 8 ++++++++ coderd/workspaceagent_test.go | 9 +++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/coderd/provisionerdaemons.go b/coderd/provisionerdaemons.go index 72f2761eb5ea4..95d212df7a13e 100644 --- a/coderd/provisionerdaemons.go +++ b/coderd/provisionerdaemons.go @@ -516,12 +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, 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 857b650ecc233..c48dfc75af1d1 100644 --- a/coderd/workspaceagent_test.go +++ b/coderd/workspaceagent_test.go @@ -29,8 +29,6 @@ import ( ) func TestPostWorkspaceAgentAuthenticateGoogleInstanceIdentity(t *testing.T) { - t.Skip("Will be fixed once the Terraform Provider is implemented!") - t.Parallel() t.Run("Expired", func(t *testing.T) { t.Parallel() @@ -78,6 +76,13 @@ func TestPostWorkspaceAgentAuthenticateGoogleInstanceIdentity(t *testing.T) { Resources: []*proto.Resource{{ Name: "somename", Type: "someinstance", + Agent: &proto.Agent{ + Auth: &proto.Agent_GoogleInstanceIdentity{ + GoogleInstanceIdentity: &proto.GoogleInstanceIdentityAuth{ + InstanceId: instanceID, + }, + }, + }, }}, }, }, From 89b188709afee3f67948262b3b6e6ae33cbbdbaa Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sun, 27 Feb 2022 17:35:33 +0000 Subject: [PATCH 10/21] fix: Convert all jobs to use a common resource and agent type This enables a consistent API for project import and provisioned resources. --- .vscode/settings.json | 1 + cli/projects.go | 2 +- coderd/projectimport.go | 7 +- coderd/provisionerdaemons.go | 87 +++- coderd/provisionerjobs.go | 21 +- coderd/workspaceagent.go | 42 +- codersdk/projectimport.go | 4 +- database/databasefake/databasefake.go | 264 +++++----- database/dump.sql | 87 ++-- database/migrations/000003_workspaces.up.sql | 33 -- database/migrations/000004_jobs.up.sql | 35 +- database/models.go | 53 +- database/querier.go | 13 +- database/query.sql | 84 ++- database/query.sql.go | 521 +++++++++---------- go.mod | 1 + go.sum | 2 + 17 files changed, 629 insertions(+), 628 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 8c642faa6402b..32e7a2ddf4e34 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -50,6 +50,7 @@ "ntqry", "oneof", "parameterscopeid", + "pqtype", "promptui", "protobuf", "provisionerd", diff --git a/cli/projects.go b/cli/projects.go index 763b1fcc42809..0f04dc05cd259 100644 --- a/cli/projects.go +++ b/cli/projects.go @@ -40,7 +40,7 @@ func projects() *cobra.Command { return cmd } -func displayProjectImportInfo(cmd *cobra.Command, parameterSchemas []coderd.ParameterSchema, parameterValues []coderd.ComputedParameterValue, resources []coderd.ProjectImportJobResource) error { +func displayProjectImportInfo(cmd *cobra.Command, parameterSchemas []coderd.ParameterSchema, parameterValues []coderd.ComputedParameterValue, resources []coderd.ProvisionerJobResource) error { schemaByID := map[string]coderd.ParameterSchema{} for _, schema := range parameterSchemas { schemaByID[schema.ID.String()] = schema diff --git a/coderd/projectimport.go b/coderd/projectimport.go index d3032f9b1eee5..5ece718c99a90 100644 --- a/coderd/projectimport.go +++ b/coderd/projectimport.go @@ -21,9 +21,6 @@ type ParameterSchema database.ParameterSchema // ComputedParameterValue represents a computed parameter value. type ComputedParameterValue parameter.ComputedValue -// ProjectImportJobResource is a resource created by a project import job. -type ProjectImportJobResource database.ProjectImportJobResource - // CreateProjectImportJobRequest provides options to create a project import job. type CreateProjectImportJobRequest struct { StorageMethod database.ProvisionerStorageMethod `json:"storage_method" validate:"oneof=file,required"` @@ -167,7 +164,7 @@ func (api *api) projectImportJobResourcesByID(rw http.ResponseWriter, r *http.Re }) return } - resources, err := api.Database.GetProjectImportJobResourcesByJobID(r.Context(), job.ID) + resources, err := api.Database.GetProvisionerJobResourcesByJobID(r.Context(), job.ID) if errors.Is(err, sql.ErrNoRows) { err = nil } @@ -178,7 +175,7 @@ func (api *api) projectImportJobResourcesByID(rw http.ResponseWriter, r *http.Re return } if resources == nil { - resources = []database.ProjectImportJobResource{} + resources = []database.ProvisionerJobResource{} } render.Status(r, http.StatusOK) render.JSON(rw, r, resources) diff --git a/coderd/provisionerdaemons.go b/coderd/provisionerdaemons.go index 95d212df7a13e..1a50f808dd5fc 100644 --- a/coderd/provisionerdaemons.go +++ b/coderd/provisionerdaemons.go @@ -15,6 +15,7 @@ import ( "github.com/google/uuid" "github.com/hashicorp/yamux" "github.com/moby/moby/pkg/namesgenerator" + "github.com/tabbed/pqtype" "golang.org/x/xerrors" "nhooyr.io/websocket" "storj.io/drpc/drpcmux" @@ -453,14 +454,8 @@ func (server *provisionerdServer) CompleteJob(ctx context.Context, completed *pr slog.F("resource_name", resource.Name), slog.F("resource_type", resource.Type), slog.F("transition", transition)) - _, err = server.Database.InsertProjectImportJobResource(ctx, database.InsertProjectImportJobResourceParams{ - ID: uuid.New(), - CreatedAt: database.Now(), - JobID: jobID, - Transition: transition, - Type: resource.Type, - Name: resource.Name, - }) + + err = insertProvisionerJobResource(ctx, server.Database, jobID, transition, resource) if err != nil { return nil, xerrors.Errorf("insert resource: %w", err) } @@ -516,26 +511,9 @@ 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, - 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(), - }) + err = insertProvisionerJobResource(ctx, db, job.ID, workspaceHistory.Transition, protoResource) if err != nil { - return xerrors.Errorf("insert workspace resource %q: %w", protoResource.Name, err) + return xerrors.Errorf("insert provisioner job: %w", err) } } return nil @@ -551,6 +529,61 @@ func (server *provisionerdServer) CompleteJob(ctx context.Context, completed *pr return &proto.Empty{}, nil } +func insertProvisionerJobResource(ctx context.Context, db database.Store, jobID uuid.UUID, transition database.WorkspaceTransition, protoResource *sdkproto.Resource) error { + resource, err := db.InsertProvisionerJobResource(ctx, database.InsertProvisionerJobResourceParams{ + ID: uuid.New(), + CreatedAt: database.Now(), + JobID: jobID, + Transition: transition, + Type: protoResource.Type, + Name: protoResource.Name, + AgentID: uuid.NullUUID{ + UUID: uuid.New(), + Valid: protoResource.Agent != nil, + }, + }) + if err != nil { + return xerrors.Errorf("insert provisioner job resource %q: %w", protoResource.Name, err) + } + if resource.AgentID.Valid { + var instanceID sql.NullString + if protoResource.Agent.GetGoogleInstanceIdentity() != nil { + instanceID = sql.NullString{ + String: protoResource.Agent.GetGoogleInstanceIdentity().InstanceId, + Valid: true, + } + } + var env pqtype.NullRawMessage + if protoResource.Agent.Env != nil { + data, err := json.Marshal(protoResource.Agent.Env) + if err != nil { + return xerrors.Errorf("marshal env: %w", err) + } + env = pqtype.NullRawMessage{ + RawMessage: data, + Valid: true, + } + } + + _, err := db.InsertProvisionerJobAgent(ctx, database.InsertProvisionerJobAgentParams{ + ID: resource.AgentID.UUID, + CreatedAt: database.Now(), + ResourceID: resource.ID, + AuthToken: uuid.New(), + AuthInstanceID: instanceID, + EnvironmentVariables: env, + StartupScript: sql.NullString{ + String: protoResource.Agent.StartupScript, + Valid: protoResource.Agent.StartupScript != "", + }, + }) + if err != nil { + return xerrors.Errorf("insert agent: %w", err) + } + } + return nil +} + func convertValidationTypeSystem(typeSystem sdkproto.ParameterSchema_TypeSystem) (database.ParameterTypeSystem, error) { switch typeSystem { case sdkproto.ParameterSchema_None: diff --git a/coderd/provisionerjobs.go b/coderd/provisionerjobs.go index a99ca905c83c5..aab66b55e4a2f 100644 --- a/coderd/provisionerjobs.go +++ b/coderd/provisionerjobs.go @@ -50,13 +50,32 @@ type ProvisionerJob struct { // ProvisionerJobLog represents a single log from a provisioner job. type ProvisionerJobLog struct { - ID uuid.UUID + ID uuid.UUID `json:"id"` CreatedAt time.Time `json:"created_at"` Source database.LogSource `json:"log_source"` Level database.LogLevel `json:"log_level"` Output string `json:"output"` } +type ProvisionerJobResource struct { + ID uuid.UUID `json:"id"` + CreatedAt time.Time `json:"created_at"` + JobID uuid.UUID `json:"job_id"` + Transition database.WorkspaceTransition `json:"workspace_transition"` + Type string `json:"type"` + Name string `json:"name"` +} + +type ProvisionerJobAgent struct { + ID uuid.UUID `json:"id"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + ResourceID uuid.UUID `json:"resource_id"` + InstanceID string `json:"instance_id,omitempty"` + EnvironmentVariables map[string]string `json:"environment_variables"` + StartupScript string `json:"startup_script,omitempty"` +} + func (*api) provisionerJobByID(rw http.ResponseWriter, r *http.Request) { job := httpmw.ProvisionerJobParam(r) render.Status(r, http.StatusOK) diff --git a/coderd/workspaceagent.go b/coderd/workspaceagent.go index 4f4c88baddc1e..2e45046fa3ff0 100644 --- a/coderd/workspaceagent.go +++ b/coderd/workspaceagent.go @@ -2,12 +2,14 @@ package coderd import ( "database/sql" + "encoding/json" "errors" "fmt" "net/http" "github.com/go-chi/render" + "github.com/coder/coder/database" "github.com/coder/coder/httpapi" "github.com/mitchellh/mapstructure" @@ -54,14 +56,48 @@ func (api *api) postAuthenticateWorkspaceAgentUsingGoogleInstanceIdentity(rw htt }) return } - resource, err := api.Database.GetWorkspaceResourceByInstanceID(r.Context(), claims.Google.ComputeEngine.InstanceID) + agent, err := api.Database.GetProvisionerJobAgentByInstanceID(r.Context(), claims.Google.ComputeEngine.InstanceID) if errors.Is(err, sql.ErrNoRows) { httpapi.Write(rw, http.StatusNotFound, httpapi.Response{ Message: fmt.Sprintf("instance with id %q not found", claims.Google.ComputeEngine.InstanceID), }) return } - resourceHistory, err := api.Database.GetWorkspaceHistoryByID(r.Context(), resource.WorkspaceHistoryID) + if err != nil { + httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ + Message: fmt.Sprintf("get provisioner job agent: %s", err), + }) + return + } + resource, err := api.Database.GetProvisionerJobResourceByID(r.Context(), agent.ResourceID) + if err != nil { + httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ + Message: fmt.Sprintf("get provisioner job resource: %s", err), + }) + return + } + job, err := api.Database.GetProvisionerJobByID(r.Context(), resource.JobID) + if err != nil { + httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ + Message: fmt.Sprintf("get provisioner job: %s", err), + }) + return + } + if job.Type != database.ProvisionerJobTypeWorkspaceProvision { + httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{ + Message: fmt.Sprintf("%q jobs cannot be authenticated", job.Type), + }) + return + } + var jobData workspaceProvisionJob + err = json.Unmarshal(job.Input, &jobData) + if err != nil { + httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ + Message: fmt.Sprintf("extract job data: %s", err), + }) + return + } + resourceHistory, err := api.Database.GetWorkspaceHistoryByID(r.Context(), jobData.WorkspaceHistoryID) if err != nil { httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ Message: fmt.Sprintf("get workspace history: %s", err), @@ -86,6 +122,6 @@ func (api *api) postAuthenticateWorkspaceAgentUsingGoogleInstanceIdentity(rw htt } render.Status(r, http.StatusOK) render.JSON(rw, r, WorkspaceAgentAuthenticateResponse{ - SessionToken: resource.WorkspaceAgentToken, + SessionToken: agent.AuthToken.String(), }) } diff --git a/codersdk/projectimport.go b/codersdk/projectimport.go index 95f7cb6812872..7001d63153c09 100644 --- a/codersdk/projectimport.go +++ b/codersdk/projectimport.go @@ -81,7 +81,7 @@ func (c *Client) ProjectImportJobParameters(ctx context.Context, organization st } // ProjectImportJobResources returns resources for a project import job. -func (c *Client) ProjectImportJobResources(ctx context.Context, organization string, job uuid.UUID) ([]coderd.ProjectImportJobResource, error) { +func (c *Client) ProjectImportJobResources(ctx context.Context, organization string, job uuid.UUID) ([]coderd.ProvisionerJobResource, error) { res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/projectimport/%s/%s/resources", organization, job), nil) if err != nil { return nil, err @@ -90,6 +90,6 @@ func (c *Client) ProjectImportJobResources(ctx context.Context, organization str if res.StatusCode != http.StatusOK { return nil, readBodyAsError(res) } - var resources []coderd.ProjectImportJobResource + var resources []coderd.ProvisionerJobResource return resources, json.NewDecoder(res.Body).Decode(&resources) } diff --git a/database/databasefake/databasefake.go b/database/databasefake/databasefake.go index f8d1ed2c5fefc..1e09a2a74f4f9 100644 --- a/database/databasefake/databasefake.go +++ b/database/databasefake/databasefake.go @@ -19,19 +19,18 @@ func New() database.Store { organizationMembers: make([]database.OrganizationMember, 0), users: make([]database.User, 0), - files: make([]database.File, 0), - parameterValue: make([]database.ParameterValue, 0), - parameterSchema: make([]database.ParameterSchema, 0), - project: make([]database.Project, 0), - projectVersion: make([]database.ProjectVersion, 0), - projectImportJobResource: make([]database.ProjectImportJobResource, 0), - provisionerDaemons: make([]database.ProvisionerDaemon, 0), - provisionerJobs: make([]database.ProvisionerJob, 0), - provisionerJobLog: make([]database.ProvisionerJobLog, 0), - workspace: make([]database.Workspace, 0), - workspaceResource: make([]database.WorkspaceResource, 0), - workspaceHistory: make([]database.WorkspaceHistory, 0), - workspaceAgent: make([]database.WorkspaceAgent, 0), + files: make([]database.File, 0), + parameterValue: make([]database.ParameterValue, 0), + parameterSchema: make([]database.ParameterSchema, 0), + project: make([]database.Project, 0), + projectVersion: make([]database.ProjectVersion, 0), + provisionerDaemons: make([]database.ProvisionerDaemon, 0), + provisionerJobs: make([]database.ProvisionerJob, 0), + provisionerJobLog: make([]database.ProvisionerJobLog, 0), + workspace: make([]database.Workspace, 0), + provisionerJobResource: make([]database.ProvisionerJobResource, 0), + workspaceHistory: make([]database.WorkspaceHistory, 0), + provisionerJobAgent: make([]database.ProvisionerJobAgent, 0), } } @@ -46,19 +45,18 @@ type fakeQuerier struct { users []database.User // New tables - files []database.File - parameterValue []database.ParameterValue - parameterSchema []database.ParameterSchema - project []database.Project - projectVersion []database.ProjectVersion - projectImportJobResource []database.ProjectImportJobResource - provisionerDaemons []database.ProvisionerDaemon - provisionerJobs []database.ProvisionerJob - provisionerJobLog []database.ProvisionerJobLog - workspace []database.Workspace - workspaceAgent []database.WorkspaceAgent - workspaceHistory []database.WorkspaceHistory - workspaceResource []database.WorkspaceResource + files []database.File + parameterValue []database.ParameterValue + parameterSchema []database.ParameterSchema + project []database.Project + projectVersion []database.ProjectVersion + provisionerDaemons []database.ProvisionerDaemon + provisionerJobs []database.ProvisionerJob + provisionerJobAgent []database.ProvisionerJobAgent + provisionerJobResource []database.ProvisionerJobResource + provisionerJobLog []database.ProvisionerJobLog + workspace []database.Workspace + workspaceHistory []database.WorkspaceHistory } // InTx doesn't rollback data properly for in-memory yet. @@ -149,24 +147,6 @@ func (q *fakeQuerier) GetUserCount(_ context.Context) (int64, error) { return int64(len(q.users)), nil } -func (q *fakeQuerier) GetWorkspaceAgentsByResourceIDs(_ context.Context, ids []uuid.UUID) ([]database.WorkspaceAgent, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - agents := make([]database.WorkspaceAgent, 0) - for _, workspaceAgent := range q.workspaceAgent { - for _, id := range ids { - if workspaceAgent.WorkspaceResourceID.String() == id.String() { - agents = append(agents, workspaceAgent) - } - } - } - if len(agents) == 0 { - return nil, sql.ErrNoRows - } - return agents, nil -} - func (q *fakeQuerier) GetWorkspaceByID(_ context.Context, id uuid.UUID) (database.Workspace, error) { q.mutex.Lock() defer q.mutex.Unlock() @@ -195,18 +175,6 @@ func (q *fakeQuerier) GetWorkspaceByUserIDAndName(_ context.Context, arg databas return database.Workspace{}, sql.ErrNoRows } -func (q *fakeQuerier) GetWorkspaceResourceByInstanceID(_ context.Context, instanceID string) (database.WorkspaceResource, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - for _, workspaceResource := range q.workspaceResource { - if workspaceResource.InstanceID.String == instanceID { - return workspaceResource, nil - } - } - return database.WorkspaceResource{}, sql.ErrNoRows -} - func (q *fakeQuerier) GetWorkspaceOwnerCountsByProjectIDs(_ context.Context, projectIDs []uuid.UUID) ([]database.GetWorkspaceOwnerCountsByProjectIDsRow, error) { counts := map[string]map[string]struct{}{} for _, projectID := range projectIDs { @@ -242,22 +210,6 @@ func (q *fakeQuerier) GetWorkspaceOwnerCountsByProjectIDs(_ context.Context, pro return res, nil } -func (q *fakeQuerier) GetWorkspaceResourcesByHistoryID(_ context.Context, workspaceHistoryID uuid.UUID) ([]database.WorkspaceResource, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - resources := make([]database.WorkspaceResource, 0) - for _, workspaceResource := range q.workspaceResource { - if workspaceResource.WorkspaceHistoryID.String() == workspaceHistoryID.String() { - resources = append(resources, workspaceResource) - } - } - if len(resources) == 0 { - return nil, sql.ErrNoRows - } - return resources, nil -} - func (q *fakeQuerier) GetWorkspaceHistoryByID(_ context.Context, id uuid.UUID) (database.WorkspaceHistory, error) { q.mutex.Lock() defer q.mutex.Unlock() @@ -448,23 +400,6 @@ func (q *fakeQuerier) GetProjectByOrganizationAndName(_ context.Context, arg dat return database.Project{}, sql.ErrNoRows } -func (q *fakeQuerier) GetProjectImportJobResourcesByJobID(_ context.Context, jobID uuid.UUID) ([]database.ProjectImportJobResource, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - resources := make([]database.ProjectImportJobResource, 0) - for _, resource := range q.projectImportJobResource { - if resource.JobID.String() != jobID.String() { - continue - } - resources = append(resources, resource) - } - if len(resources) == 0 { - return nil, sql.ErrNoRows - } - return resources, nil -} - func (q *fakeQuerier) GetProjectVersionsByProjectID(_ context.Context, projectID uuid.UUID) ([]database.ProjectVersion, error) { q.mutex.Lock() defer q.mutex.Unlock() @@ -573,6 +508,38 @@ func (q *fakeQuerier) GetProvisionerDaemons(_ context.Context) ([]database.Provi return q.provisionerDaemons, nil } +func (q *fakeQuerier) GetProvisionerJobAgentByInstanceID(_ context.Context, instanceID string) (database.ProvisionerJobAgent, error) { + q.mutex.Lock() + defer q.mutex.Unlock() + + // The schema sorts this by created at, so we iterate the array backwards. + for i := len(q.provisionerJobAgent) - 1; i >= 0; i-- { + agent := q.provisionerJobAgent[i] + if agent.AuthInstanceID.Valid && agent.AuthInstanceID.String == instanceID { + return agent, nil + } + } + return database.ProvisionerJobAgent{}, sql.ErrNoRows +} + +func (q *fakeQuerier) GetProvisionerJobAgentsByResourceIDs(_ context.Context, ids []uuid.UUID) ([]database.ProvisionerJobAgent, error) { + q.mutex.Lock() + defer q.mutex.Unlock() + + agents := make([]database.ProvisionerJobAgent, 0) + for _, agent := range q.provisionerJobAgent { + for _, id := range ids { + if agent.ResourceID.String() == id.String() { + agents = append(agents, agent) + } + } + } + if len(agents) == 0 { + return nil, sql.ErrNoRows + } + return agents, nil +} + func (q *fakeQuerier) GetProvisionerDaemonByID(_ context.Context, id uuid.UUID) (database.ProvisionerDaemon, error) { q.mutex.Lock() defer q.mutex.Unlock() @@ -599,6 +566,35 @@ func (q *fakeQuerier) GetProvisionerJobByID(_ context.Context, id uuid.UUID) (da return database.ProvisionerJob{}, sql.ErrNoRows } +func (q *fakeQuerier) GetProvisionerJobResourceByID(_ context.Context, id uuid.UUID) (database.ProvisionerJobResource, error) { + q.mutex.Lock() + defer q.mutex.Unlock() + + for _, resource := range q.provisionerJobResource { + if resource.ID.String() == id.String() { + return resource, nil + } + } + return database.ProvisionerJobResource{}, sql.ErrNoRows +} + +func (q *fakeQuerier) GetProvisionerJobResourcesByJobID(_ context.Context, jobID uuid.UUID) ([]database.ProvisionerJobResource, error) { + q.mutex.Lock() + defer q.mutex.Unlock() + + resources := make([]database.ProvisionerJobResource, 0) + for _, resource := range q.provisionerJobResource { + if resource.JobID.String() != jobID.String() { + continue + } + resources = append(resources, resource) + } + if len(resources) == 0 { + return nil, sql.ErrNoRows + } + return resources, nil +} + func (q *fakeQuerier) GetProvisionerLogsByIDBetween(_ context.Context, arg database.GetProvisionerLogsByIDBetweenParams) ([]database.ProvisionerJobLog, error) { q.mutex.Lock() defer q.mutex.Unlock() @@ -732,23 +728,6 @@ func (q *fakeQuerier) InsertProject(_ context.Context, arg database.InsertProjec return project, nil } -func (q *fakeQuerier) InsertProjectImportJobResource(_ context.Context, arg database.InsertProjectImportJobResourceParams) (database.ProjectImportJobResource, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - //nolint:gosimple - projectResource := database.ProjectImportJobResource{ - ID: arg.ID, - CreatedAt: arg.CreatedAt, - JobID: arg.JobID, - Transition: arg.Transition, - Type: arg.Type, - Name: arg.Name, - } - q.projectImportJobResource = append(q.projectImportJobResource, projectResource) - return projectResource, nil -} - func (q *fakeQuerier) InsertProjectVersion(_ context.Context, arg database.InsertProjectVersionParams) (database.ProjectVersion, error) { q.mutex.Lock() defer q.mutex.Unlock() @@ -847,6 +826,45 @@ func (q *fakeQuerier) InsertProvisionerJob(_ context.Context, arg database.Inser return job, nil } +func (q *fakeQuerier) InsertProvisionerJobAgent(_ context.Context, arg database.InsertProvisionerJobAgentParams) (database.ProvisionerJobAgent, error) { + q.mutex.Lock() + defer q.mutex.Unlock() + + //nolint:gosimple + agent := database.ProvisionerJobAgent{ + ID: arg.ID, + CreatedAt: arg.CreatedAt, + UpdatedAt: arg.UpdatedAt, + ResourceID: arg.ResourceID, + AuthToken: arg.AuthToken, + AuthInstanceID: arg.AuthInstanceID, + EnvironmentVariables: arg.EnvironmentVariables, + StartupScript: arg.StartupScript, + InstanceMetadata: arg.InstanceMetadata, + ResourceMetadata: arg.ResourceMetadata, + } + q.provisionerJobAgent = append(q.provisionerJobAgent, agent) + return agent, nil +} + +func (q *fakeQuerier) InsertProvisionerJobResource(_ context.Context, arg database.InsertProvisionerJobResourceParams) (database.ProvisionerJobResource, error) { + q.mutex.Lock() + defer q.mutex.Unlock() + + //nolint:gosimple + resource := database.ProvisionerJobResource{ + ID: arg.ID, + CreatedAt: arg.CreatedAt, + JobID: arg.JobID, + Transition: arg.Transition, + Type: arg.Type, + Name: arg.Name, + AgentID: arg.AgentID, + } + q.provisionerJobResource = append(q.provisionerJobResource, resource) + return resource, nil +} + func (q *fakeQuerier) InsertUser(_ context.Context, arg database.InsertUserParams) (database.User, error) { q.mutex.Lock() defer q.mutex.Unlock() @@ -882,23 +900,6 @@ func (q *fakeQuerier) InsertWorkspace(_ context.Context, arg database.InsertWork return workspace, nil } -func (q *fakeQuerier) InsertWorkspaceAgent(_ context.Context, arg database.InsertWorkspaceAgentParams) (database.WorkspaceAgent, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - //nolint:gosimple - workspaceAgent := database.WorkspaceAgent{ - ID: arg.ID, - CreatedAt: arg.CreatedAt, - UpdatedAt: arg.UpdatedAt, - WorkspaceResourceID: arg.WorkspaceResourceID, - InstanceMetadata: arg.InstanceMetadata, - ResourceMetadata: arg.ResourceMetadata, - } - q.workspaceAgent = append(q.workspaceAgent, workspaceAgent) - return workspaceAgent, nil -} - func (q *fakeQuerier) InsertWorkspaceHistory(_ context.Context, arg database.InsertWorkspaceHistoryParams) (database.WorkspaceHistory, error) { q.mutex.Lock() defer q.mutex.Unlock() @@ -920,23 +921,6 @@ func (q *fakeQuerier) InsertWorkspaceHistory(_ context.Context, arg database.Ins return workspaceHistory, nil } -func (q *fakeQuerier) InsertWorkspaceResource(_ context.Context, arg database.InsertWorkspaceResourceParams) (database.WorkspaceResource, error) { - q.mutex.Lock() - defer q.mutex.Unlock() - - workspaceResource := database.WorkspaceResource{ - ID: arg.ID, - CreatedAt: arg.CreatedAt, - WorkspaceHistoryID: arg.WorkspaceHistoryID, - InstanceID: arg.InstanceID, - Type: arg.Type, - Name: arg.Name, - WorkspaceAgentToken: arg.WorkspaceAgentToken, - } - q.workspaceResource = append(q.workspaceResource, workspaceResource) - return workspaceResource, nil -} - func (q *fakeQuerier) UpdateAPIKeyByID(_ context.Context, arg database.UpdateAPIKeyByIDParams) error { q.mutex.Lock() defer q.mutex.Unlock() diff --git a/database/dump.sql b/database/dump.sql index 371ad221e3b57..23095aad1819f 100644 --- a/database/dump.sql +++ b/database/dump.sql @@ -163,15 +163,6 @@ CREATE TABLE project ( active_version_id uuid NOT NULL ); -CREATE TABLE project_import_job_resource ( - id uuid NOT NULL, - created_at timestamp with time zone NOT NULL, - job_id uuid NOT NULL, - transition workspace_transition NOT NULL, - type character varying(256) NOT NULL, - name character varying(64) NOT NULL -); - CREATE TABLE project_version ( id uuid NOT NULL, project_id uuid NOT NULL, @@ -208,6 +199,19 @@ CREATE TABLE provisioner_job ( worker_id uuid ); +CREATE TABLE provisioner_job_agent ( + id uuid NOT NULL, + created_at timestamp with time zone NOT NULL, + updated_at timestamp with time zone, + resource_id uuid NOT NULL, + auth_token uuid NOT NULL, + auth_instance_id character varying(64), + environment_variables jsonb, + startup_script character varying(65534), + instance_metadata jsonb, + resource_metadata jsonb +); + CREATE TABLE provisioner_job_log ( id uuid NOT NULL, job_id uuid NOT NULL, @@ -217,6 +221,16 @@ CREATE TABLE provisioner_job_log ( output character varying(1024) NOT NULL ); +CREATE TABLE provisioner_job_resource ( + id uuid NOT NULL, + created_at timestamp with time zone NOT NULL, + job_id uuid NOT NULL, + transition workspace_transition NOT NULL, + type character varying(256) NOT NULL, + name character varying(64) NOT NULL, + agent_id uuid +); + CREATE TABLE users ( id text NOT NULL, email text NOT NULL, @@ -248,15 +262,6 @@ CREATE TABLE workspace ( name character varying(64) NOT NULL ); -CREATE TABLE workspace_agent ( - id uuid NOT NULL, - workspace_resource_id uuid NOT NULL, - created_at timestamp with time zone NOT NULL, - updated_at timestamp with time zone NOT NULL, - instance_metadata jsonb NOT NULL, - resource_metadata jsonb NOT NULL -); - CREATE TABLE workspace_history ( id uuid NOT NULL, created_at timestamp with time zone NOT NULL, @@ -272,17 +277,6 @@ CREATE TABLE workspace_history ( provision_job_id uuid NOT NULL ); -CREATE TABLE workspace_resource ( - id uuid NOT NULL, - created_at timestamp with time zone NOT NULL, - workspace_history_id uuid NOT NULL, - instance_id character varying(64), - type character varying(256) NOT NULL, - name character varying(64) NOT NULL, - workspace_agent_token character varying(128) NOT NULL, - workspace_agent_id uuid -); - ALTER TABLE ONLY file ADD CONSTRAINT file_hash_key UNIQUE (hash); @@ -301,9 +295,6 @@ ALTER TABLE ONLY parameter_value ALTER TABLE ONLY project ADD CONSTRAINT project_id_key UNIQUE (id); -ALTER TABLE ONLY project_import_job_resource - ADD CONSTRAINT project_import_job_resource_id_key UNIQUE (id); - ALTER TABLE ONLY project ADD CONSTRAINT project_organization_id_name_key UNIQUE (organization_id, name); @@ -319,14 +310,20 @@ ALTER TABLE ONLY provisioner_daemon ALTER TABLE ONLY provisioner_daemon ADD CONSTRAINT provisioner_daemon_name_key UNIQUE (name); +ALTER TABLE ONLY provisioner_job_agent + ADD CONSTRAINT provisioner_job_agent_auth_token_key UNIQUE (auth_token); + +ALTER TABLE ONLY provisioner_job_agent + ADD CONSTRAINT provisioner_job_agent_id_key UNIQUE (id); + ALTER TABLE ONLY provisioner_job ADD CONSTRAINT provisioner_job_id_key UNIQUE (id); ALTER TABLE ONLY provisioner_job_log ADD CONSTRAINT provisioner_job_log_id_key UNIQUE (id); -ALTER TABLE ONLY workspace_agent - ADD CONSTRAINT workspace_agent_id_key UNIQUE (id); +ALTER TABLE ONLY provisioner_job_resource + ADD CONSTRAINT provisioner_job_resource_id_key UNIQUE (id); ALTER TABLE ONLY workspace_history ADD CONSTRAINT workspace_history_id_key UNIQUE (id); @@ -340,29 +337,20 @@ ALTER TABLE ONLY workspace ALTER TABLE ONLY workspace ADD CONSTRAINT workspace_owner_id_name_key UNIQUE (owner_id, name); -ALTER TABLE ONLY workspace_resource - ADD CONSTRAINT workspace_resource_id_key UNIQUE (id); - -ALTER TABLE ONLY workspace_resource - ADD CONSTRAINT workspace_resource_workspace_agent_token_key UNIQUE (workspace_agent_token); - -ALTER TABLE ONLY workspace_resource - ADD CONSTRAINT workspace_resource_workspace_history_id_type_name_key UNIQUE (workspace_history_id, type, name); - ALTER TABLE ONLY parameter_schema ADD CONSTRAINT parameter_schema_job_id_fkey FOREIGN KEY (job_id) REFERENCES provisioner_job(id) ON DELETE CASCADE; -ALTER TABLE ONLY project_import_job_resource - ADD CONSTRAINT project_import_job_resource_job_id_fkey FOREIGN KEY (job_id) REFERENCES provisioner_job(id) ON DELETE CASCADE; - ALTER TABLE ONLY project_version ADD CONSTRAINT project_version_project_id_fkey FOREIGN KEY (project_id) REFERENCES project(id); +ALTER TABLE ONLY provisioner_job_agent + ADD CONSTRAINT provisioner_job_agent_resource_id_fkey FOREIGN KEY (resource_id) REFERENCES provisioner_job_resource(id) ON DELETE CASCADE; + ALTER TABLE ONLY provisioner_job_log ADD CONSTRAINT provisioner_job_log_job_id_fkey FOREIGN KEY (job_id) REFERENCES provisioner_job(id) ON DELETE CASCADE; -ALTER TABLE ONLY workspace_agent - ADD CONSTRAINT workspace_agent_workspace_resource_id_fkey FOREIGN KEY (workspace_resource_id) REFERENCES workspace_resource(id) ON DELETE CASCADE; +ALTER TABLE ONLY provisioner_job_resource + ADD CONSTRAINT provisioner_job_resource_job_id_fkey FOREIGN KEY (job_id) REFERENCES provisioner_job(id) ON DELETE CASCADE; ALTER TABLE ONLY workspace_history ADD CONSTRAINT workspace_history_project_version_id_fkey FOREIGN KEY (project_version_id) REFERENCES project_version(id) ON DELETE CASCADE; @@ -373,6 +361,3 @@ ALTER TABLE ONLY workspace_history ALTER TABLE ONLY workspace ADD CONSTRAINT workspace_project_id_fkey FOREIGN KEY (project_id) REFERENCES project(id); -ALTER TABLE ONLY workspace_resource - ADD CONSTRAINT workspace_resource_workspace_history_id_fkey FOREIGN KEY (workspace_history_id) REFERENCES workspace_history(id) ON DELETE CASCADE; - diff --git a/database/migrations/000003_workspaces.up.sql b/database/migrations/000003_workspaces.up.sql index 81e894caa3ae3..97e3083d31a5f 100644 --- a/database/migrations/000003_workspaces.up.sql +++ b/database/migrations/000003_workspaces.up.sql @@ -32,36 +32,3 @@ CREATE TABLE workspace_history ( provision_job_id uuid NOT NULL, UNIQUE(workspace_id, name) ); - --- Cloud resources produced by a provision job. -CREATE TABLE workspace_resource ( - id uuid NOT NULL UNIQUE, - created_at timestamptz NOT NULL, - workspace_history_id uuid NOT NULL REFERENCES workspace_history (id) ON DELETE CASCADE, - -- A unique identifier for the resource. This can be used - -- to exchange for an agent token with various providers. - instance_id varchar(64), - -- Resource type produced by a provisioner. - -- eg. "google_compute_instance" - type varchar(256) NOT NULL, - -- Name of the resource. - -- eg. "kyle-dev-instance" - name varchar(64) NOT NULL, - -- Token for an agent to connect. - workspace_agent_token varchar(128) NOT NULL UNIQUE, - -- If an agent has been conencted for this resource, - -- the agent table is not null. - workspace_agent_id uuid, - UNIQUE(workspace_history_id, type, name) -); - -CREATE TABLE workspace_agent ( - id uuid NOT NULL UNIQUE, - workspace_resource_id uuid NOT NULL REFERENCES workspace_resource (id) ON DELETE CASCADE, - created_at timestamptz NOT NULL, - updated_at timestamptz NOT NULL, - -- Identifies instance architecture, cloud, etc. - instance_metadata jsonb NOT NULL, - -- Identifies resources. - resource_metadata jsonb NOT NULL -); diff --git a/database/migrations/000004_jobs.up.sql b/database/migrations/000004_jobs.up.sql index 4d100e7f6fa80..f8e1ca8db9fd5 100644 --- a/database/migrations/000004_jobs.up.sql +++ b/database/migrations/000004_jobs.up.sql @@ -55,6 +55,31 @@ CREATE TABLE IF NOT EXISTS provisioner_job_log ( output varchar(1024) NOT NULL ); +-- Resources from multiple workspace states are stored here post project-import job. +CREATE TABLE provisioner_job_resource ( + id uuid NOT NULL UNIQUE, + created_at timestamptz NOT NULL, + job_id uuid NOT NULL REFERENCES provisioner_job(id) ON DELETE CASCADE, + transition workspace_transition NOT NULL, + type varchar(256) NOT NULL, + name varchar(64) NOT NULL, + agent_id uuid +); + +-- Agents that associate with a specific resource. +CREATE TABLE provisioner_job_agent ( + id uuid NOT NULL UNIQUE, + created_at timestamptz NOT NULL, + updated_at timestamptz, + resource_id uuid NOT NULL REFERENCES provisioner_job_resource (id) ON DELETE CASCADE, + auth_token uuid NOT NULL UNIQUE, + auth_instance_id varchar(64), + environment_variables jsonb, + startup_script varchar(65534), + instance_metadata jsonb, + resource_metadata jsonb +); + CREATE TYPE parameter_scope AS ENUM ( 'organization', 'project', @@ -119,13 +144,3 @@ CREATE TABLE parameter_value ( -- Prevents duplicates for parameters in the same scope. UNIQUE(name, scope, scope_id) ); - --- Resources from multiple workspace states are stored here post project-import job. -CREATE TABLE project_import_job_resource ( - id uuid NOT NULL UNIQUE, - created_at timestamptz NOT NULL, - job_id uuid NOT NULL REFERENCES provisioner_job(id) ON DELETE CASCADE, - transition workspace_transition NOT NULL, - type varchar(256) NOT NULL, - name varchar(64) NOT NULL -); diff --git a/database/models.go b/database/models.go index 82154d2c2f54b..bf4ffbbe30524 100644 --- a/database/models.go +++ b/database/models.go @@ -9,6 +9,7 @@ import ( "time" "github.com/google/uuid" + "github.com/tabbed/pqtype" ) type LogLevel string @@ -342,15 +343,6 @@ type Project struct { ActiveVersionID uuid.UUID `db:"active_version_id" json:"active_version_id"` } -type ProjectImportJobResource struct { - ID uuid.UUID `db:"id" json:"id"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - JobID uuid.UUID `db:"job_id" json:"job_id"` - Transition WorkspaceTransition `db:"transition" json:"transition"` - Type string `db:"type" json:"type"` - Name string `db:"name" json:"name"` -} - type ProjectVersion struct { ID uuid.UUID `db:"id" json:"id"` ProjectID uuid.UUID `db:"project_id" json:"project_id"` @@ -387,6 +379,19 @@ type ProvisionerJob struct { WorkerID uuid.NullUUID `db:"worker_id" json:"worker_id"` } +type ProvisionerJobAgent struct { + ID uuid.UUID `db:"id" json:"id"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt sql.NullTime `db:"updated_at" json:"updated_at"` + ResourceID uuid.UUID `db:"resource_id" json:"resource_id"` + AuthToken uuid.UUID `db:"auth_token" json:"auth_token"` + AuthInstanceID sql.NullString `db:"auth_instance_id" json:"auth_instance_id"` + EnvironmentVariables pqtype.NullRawMessage `db:"environment_variables" json:"environment_variables"` + StartupScript sql.NullString `db:"startup_script" json:"startup_script"` + InstanceMetadata pqtype.NullRawMessage `db:"instance_metadata" json:"instance_metadata"` + ResourceMetadata pqtype.NullRawMessage `db:"resource_metadata" json:"resource_metadata"` +} + type ProvisionerJobLog struct { ID uuid.UUID `db:"id" json:"id"` JobID uuid.UUID `db:"job_id" json:"job_id"` @@ -396,6 +401,16 @@ type ProvisionerJobLog struct { Output string `db:"output" json:"output"` } +type ProvisionerJobResource struct { + ID uuid.UUID `db:"id" json:"id"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + JobID uuid.UUID `db:"job_id" json:"job_id"` + Transition WorkspaceTransition `db:"transition" json:"transition"` + Type string `db:"type" json:"type"` + Name string `db:"name" json:"name"` + AgentID uuid.NullUUID `db:"agent_id" json:"agent_id"` +} + type User struct { ID string `db:"id" json:"id"` Email string `db:"email" json:"email"` @@ -427,15 +442,6 @@ type Workspace struct { Name string `db:"name" json:"name"` } -type WorkspaceAgent struct { - ID uuid.UUID `db:"id" json:"id"` - WorkspaceResourceID uuid.UUID `db:"workspace_resource_id" json:"workspace_resource_id"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - UpdatedAt time.Time `db:"updated_at" json:"updated_at"` - InstanceMetadata json.RawMessage `db:"instance_metadata" json:"instance_metadata"` - ResourceMetadata json.RawMessage `db:"resource_metadata" json:"resource_metadata"` -} - type WorkspaceHistory struct { ID uuid.UUID `db:"id" json:"id"` CreatedAt time.Time `db:"created_at" json:"created_at"` @@ -450,14 +456,3 @@ type WorkspaceHistory struct { ProvisionerState []byte `db:"provisioner_state" json:"provisioner_state"` ProvisionJobID uuid.UUID `db:"provision_job_id" json:"provision_job_id"` } - -type WorkspaceResource struct { - ID uuid.UUID `db:"id" json:"id"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - WorkspaceHistoryID uuid.UUID `db:"workspace_history_id" json:"workspace_history_id"` - InstanceID sql.NullString `db:"instance_id" json:"instance_id"` - Type string `db:"type" json:"type"` - Name string `db:"name" json:"name"` - WorkspaceAgentToken string `db:"workspace_agent_token" json:"workspace_agent_token"` - WorkspaceAgentID uuid.NullUUID `db:"workspace_agent_id" json:"workspace_agent_id"` -} diff --git a/database/querier.go b/database/querier.go index 0c3445d31d1eb..faa24ac3a4970 100644 --- a/database/querier.go +++ b/database/querier.go @@ -20,19 +20,21 @@ type querier interface { GetParameterValuesByScope(ctx context.Context, arg GetParameterValuesByScopeParams) ([]ParameterValue, error) GetProjectByID(ctx context.Context, id uuid.UUID) (Project, error) GetProjectByOrganizationAndName(ctx context.Context, arg GetProjectByOrganizationAndNameParams) (Project, error) - GetProjectImportJobResourcesByJobID(ctx context.Context, jobID uuid.UUID) ([]ProjectImportJobResource, error) GetProjectVersionByID(ctx context.Context, id uuid.UUID) (ProjectVersion, error) GetProjectVersionByProjectIDAndName(ctx context.Context, arg GetProjectVersionByProjectIDAndNameParams) (ProjectVersion, error) GetProjectVersionsByProjectID(ctx context.Context, projectID uuid.UUID) ([]ProjectVersion, error) GetProjectsByOrganizationIDs(ctx context.Context, ids []string) ([]Project, error) GetProvisionerDaemonByID(ctx context.Context, id uuid.UUID) (ProvisionerDaemon, error) GetProvisionerDaemons(ctx context.Context) ([]ProvisionerDaemon, error) + GetProvisionerJobAgentByInstanceID(ctx context.Context, authInstanceID string) (ProvisionerJobAgent, error) + GetProvisionerJobAgentsByResourceIDs(ctx context.Context, ids []uuid.UUID) ([]ProvisionerJobAgent, error) GetProvisionerJobByID(ctx context.Context, id uuid.UUID) (ProvisionerJob, error) + GetProvisionerJobResourceByID(ctx context.Context, id uuid.UUID) (ProvisionerJobResource, error) + GetProvisionerJobResourcesByJobID(ctx context.Context, jobID uuid.UUID) ([]ProvisionerJobResource, error) GetProvisionerLogsByIDBetween(ctx context.Context, arg GetProvisionerLogsByIDBetweenParams) ([]ProvisionerJobLog, error) GetUserByEmailOrUsername(ctx context.Context, arg GetUserByEmailOrUsernameParams) (User, error) GetUserByID(ctx context.Context, id string) (User, error) GetUserCount(ctx context.Context) (int64, error) - GetWorkspaceAgentsByResourceIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceAgent, error) GetWorkspaceByID(ctx context.Context, id uuid.UUID) (Workspace, error) GetWorkspaceByUserIDAndName(ctx context.Context, arg GetWorkspaceByUserIDAndNameParams) (Workspace, error) GetWorkspaceHistoryByID(ctx context.Context, id uuid.UUID) (WorkspaceHistory, error) @@ -40,8 +42,6 @@ type querier interface { GetWorkspaceHistoryByWorkspaceIDAndName(ctx context.Context, arg GetWorkspaceHistoryByWorkspaceIDAndNameParams) (WorkspaceHistory, error) GetWorkspaceHistoryByWorkspaceIDWithoutAfter(ctx context.Context, workspaceID uuid.UUID) (WorkspaceHistory, error) GetWorkspaceOwnerCountsByProjectIDs(ctx context.Context, ids []uuid.UUID) ([]GetWorkspaceOwnerCountsByProjectIDsRow, error) - GetWorkspaceResourceByInstanceID(ctx context.Context, instanceID string) (WorkspaceResource, error) - GetWorkspaceResourcesByHistoryID(ctx context.Context, workspaceHistoryID uuid.UUID) ([]WorkspaceResource, error) GetWorkspacesByProjectAndUserID(ctx context.Context, arg GetWorkspacesByProjectAndUserIDParams) ([]Workspace, error) GetWorkspacesByUserID(ctx context.Context, ownerID string) ([]Workspace, error) InsertAPIKey(ctx context.Context, arg InsertAPIKeyParams) (APIKey, error) @@ -51,16 +51,15 @@ type querier interface { InsertParameterSchema(ctx context.Context, arg InsertParameterSchemaParams) (ParameterSchema, error) InsertParameterValue(ctx context.Context, arg InsertParameterValueParams) (ParameterValue, error) InsertProject(ctx context.Context, arg InsertProjectParams) (Project, error) - InsertProjectImportJobResource(ctx context.Context, arg InsertProjectImportJobResourceParams) (ProjectImportJobResource, error) InsertProjectVersion(ctx context.Context, arg InsertProjectVersionParams) (ProjectVersion, error) InsertProvisionerDaemon(ctx context.Context, arg InsertProvisionerDaemonParams) (ProvisionerDaemon, error) InsertProvisionerJob(ctx context.Context, arg InsertProvisionerJobParams) (ProvisionerJob, error) + InsertProvisionerJobAgent(ctx context.Context, arg InsertProvisionerJobAgentParams) (ProvisionerJobAgent, error) InsertProvisionerJobLogs(ctx context.Context, arg InsertProvisionerJobLogsParams) ([]ProvisionerJobLog, error) + InsertProvisionerJobResource(ctx context.Context, arg InsertProvisionerJobResourceParams) (ProvisionerJobResource, error) InsertUser(ctx context.Context, arg InsertUserParams) (User, error) InsertWorkspace(ctx context.Context, arg InsertWorkspaceParams) (Workspace, error) - InsertWorkspaceAgent(ctx context.Context, arg InsertWorkspaceAgentParams) (WorkspaceAgent, error) InsertWorkspaceHistory(ctx context.Context, arg InsertWorkspaceHistoryParams) (WorkspaceHistory, error) - InsertWorkspaceResource(ctx context.Context, arg InsertWorkspaceResourceParams) (WorkspaceResource, error) UpdateAPIKeyByID(ctx context.Context, arg UpdateAPIKeyByIDParams) error UpdateProvisionerDaemonByID(ctx context.Context, arg UpdateProvisionerDaemonByIDParams) error UpdateProvisionerJobByID(ctx context.Context, arg UpdateProvisionerJobByIDParams) error diff --git a/database/query.sql b/database/query.sql index 5f950404b1014..eabea0c43d709 100644 --- a/database/query.sql +++ b/database/query.sql @@ -173,14 +173,6 @@ FROM WHERE job_id = $1; --- name: GetProjectImportJobResourcesByJobID :many -SELECT - * -FROM - project_import_job_resource -WHERE - job_id = $1; - -- name: GetProjectVersionsByProjectID :many SELECT * @@ -220,19 +212,29 @@ WHERE ORDER BY created_at; +-- name: GetProvisionerDaemonByID :one +SELECT + * +FROM + provisioner_daemon +WHERE + id = $1; + -- name: GetProvisionerDaemons :many SELECT * FROM provisioner_daemon; --- name: GetProvisionerDaemonByID :one +-- name: GetProvisionerJobAgentByInstanceID :one SELECT * FROM - provisioner_daemon + provisioner_job_agent WHERE - id = $1; + auth_instance_id = @auth_instance_id :: text +ORDER BY + created_at DESC; -- name: GetProvisionerJobByID :one SELECT @@ -328,31 +330,29 @@ WHERE LIMIT 1; --- name: GetWorkspaceResourceByInstanceID :one +-- name: GetProvisionerJobResourceByID :one SELECT * FROM - workspace_resource + provisioner_job_resource WHERE - instance_id = @instance_id :: text -ORDER BY - created_at; + id = $1; --- name: GetWorkspaceResourcesByHistoryID :many +-- name: GetProvisionerJobResourcesByJobID :many SELECT * FROM - workspace_resource + provisioner_job_resource WHERE - workspace_history_id = $1; + job_id = $1; --- name: GetWorkspaceAgentsByResourceIDs :many +-- name: GetProvisionerJobAgentsByResourceIDs :many SELECT * FROM - workspace_agent + provisioner_job_agent WHERE - workspace_resource_id = ANY(@ids :: uuid [ ]); + resource_id = ANY(@ids :: uuid [ ]); -- name: InsertAPIKey :one INSERT INTO @@ -457,11 +457,19 @@ INSERT INTO VALUES ($1, $2, $3, $4, $5, $6, $7) RETURNING *; --- name: InsertProjectImportJobResource :one +-- name: InsertProvisionerJobResource :one INSERT INTO - project_import_job_resource (id, created_at, job_id, transition, type, name) + provisioner_job_resource ( + id, + created_at, + job_id, + transition, + type, + name, + agent_id + ) VALUES - ($1, $2, $3, $4, $5, $6) RETURNING *; + ($1, $2, $3, $4, $5, $6, $7) RETURNING *; -- name: InsertProjectVersion :one INSERT INTO @@ -569,18 +577,22 @@ INSERT INTO VALUES ($1, $2, $3, $4, $5, $6) RETURNING *; --- name: InsertWorkspaceAgent :one +-- name: InsertProvisionerJobAgent :one INSERT INTO - workspace_agent ( + provisioner_job_agent ( id, - workspace_resource_id, created_at, updated_at, + resource_id, + auth_token, + auth_instance_id, + environment_variables, + startup_script, instance_metadata, resource_metadata ) VALUES - ($1, $2, $3, $4, $5, $6) RETURNING *; + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) RETURNING *; -- name: InsertWorkspaceHistory :one INSERT INTO @@ -600,20 +612,6 @@ INSERT INTO VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) RETURNING *; --- name: InsertWorkspaceResource :one -INSERT INTO - workspace_resource ( - id, - created_at, - workspace_history_id, - instance_id, - type, - name, - workspace_agent_token - ) -VALUES - ($1, $2, $3, $4, $5, $6, $7) RETURNING *; - -- name: UpdateAPIKeyByID :exec UPDATE api_keys diff --git a/database/query.sql.go b/database/query.sql.go index a8f4c4b5f418e..c74ecbcbf94e5 100644 --- a/database/query.sql.go +++ b/database/query.sql.go @@ -11,6 +11,7 @@ import ( "github.com/google/uuid" "github.com/lib/pq" + "github.com/tabbed/pqtype" ) const acquireProvisionerJob = `-- name: AcquireProvisionerJob :one @@ -424,45 +425,6 @@ func (q *sqlQuerier) GetProjectByOrganizationAndName(ctx context.Context, arg Ge return i, err } -const getProjectImportJobResourcesByJobID = `-- name: GetProjectImportJobResourcesByJobID :many -SELECT - id, created_at, job_id, transition, type, name -FROM - project_import_job_resource -WHERE - job_id = $1 -` - -func (q *sqlQuerier) GetProjectImportJobResourcesByJobID(ctx context.Context, jobID uuid.UUID) ([]ProjectImportJobResource, error) { - rows, err := q.db.QueryContext(ctx, getProjectImportJobResourcesByJobID, jobID) - if err != nil { - return nil, err - } - defer rows.Close() - var items []ProjectImportJobResource - for rows.Next() { - var i ProjectImportJobResource - if err := rows.Scan( - &i.ID, - &i.CreatedAt, - &i.JobID, - &i.Transition, - &i.Type, - &i.Name, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Close(); err != nil { - return nil, err - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - const getProjectVersionByID = `-- name: GetProjectVersionByID :one SELECT id, project_id, created_at, updated_at, name, description, import_job_id @@ -655,6 +617,78 @@ func (q *sqlQuerier) GetProvisionerDaemons(ctx context.Context) ([]ProvisionerDa return items, nil } +const getProvisionerJobAgentByInstanceID = `-- name: GetProvisionerJobAgentByInstanceID :one +SELECT + id, created_at, updated_at, resource_id, auth_token, auth_instance_id, environment_variables, startup_script, instance_metadata, resource_metadata +FROM + provisioner_job_agent +WHERE + auth_instance_id = $1 :: text +ORDER BY + created_at DESC +` + +func (q *sqlQuerier) GetProvisionerJobAgentByInstanceID(ctx context.Context, authInstanceID string) (ProvisionerJobAgent, error) { + row := q.db.QueryRowContext(ctx, getProvisionerJobAgentByInstanceID, authInstanceID) + var i ProvisionerJobAgent + err := row.Scan( + &i.ID, + &i.CreatedAt, + &i.UpdatedAt, + &i.ResourceID, + &i.AuthToken, + &i.AuthInstanceID, + &i.EnvironmentVariables, + &i.StartupScript, + &i.InstanceMetadata, + &i.ResourceMetadata, + ) + return i, err +} + +const getProvisionerJobAgentsByResourceIDs = `-- name: GetProvisionerJobAgentsByResourceIDs :many +SELECT + id, created_at, updated_at, resource_id, auth_token, auth_instance_id, environment_variables, startup_script, instance_metadata, resource_metadata +FROM + provisioner_job_agent +WHERE + resource_id = ANY($1 :: uuid [ ]) +` + +func (q *sqlQuerier) GetProvisionerJobAgentsByResourceIDs(ctx context.Context, ids []uuid.UUID) ([]ProvisionerJobAgent, error) { + rows, err := q.db.QueryContext(ctx, getProvisionerJobAgentsByResourceIDs, pq.Array(ids)) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ProvisionerJobAgent + for rows.Next() { + var i ProvisionerJobAgent + if err := rows.Scan( + &i.ID, + &i.CreatedAt, + &i.UpdatedAt, + &i.ResourceID, + &i.AuthToken, + &i.AuthInstanceID, + &i.EnvironmentVariables, + &i.StartupScript, + &i.InstanceMetadata, + &i.ResourceMetadata, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const getProvisionerJobByID = `-- name: GetProvisionerJobByID :one SELECT id, created_at, updated_at, started_at, cancelled_at, completed_at, error, organization_id, initiator_id, provisioner, storage_method, storage_source, type, input, worker_id @@ -687,6 +721,70 @@ func (q *sqlQuerier) GetProvisionerJobByID(ctx context.Context, id uuid.UUID) (P return i, err } +const getProvisionerJobResourceByID = `-- name: GetProvisionerJobResourceByID :one +SELECT + id, created_at, job_id, transition, type, name, agent_id +FROM + provisioner_job_resource +WHERE + id = $1 +` + +func (q *sqlQuerier) GetProvisionerJobResourceByID(ctx context.Context, id uuid.UUID) (ProvisionerJobResource, error) { + row := q.db.QueryRowContext(ctx, getProvisionerJobResourceByID, id) + var i ProvisionerJobResource + err := row.Scan( + &i.ID, + &i.CreatedAt, + &i.JobID, + &i.Transition, + &i.Type, + &i.Name, + &i.AgentID, + ) + return i, err +} + +const getProvisionerJobResourcesByJobID = `-- name: GetProvisionerJobResourcesByJobID :many +SELECT + id, created_at, job_id, transition, type, name, agent_id +FROM + provisioner_job_resource +WHERE + job_id = $1 +` + +func (q *sqlQuerier) GetProvisionerJobResourcesByJobID(ctx context.Context, jobID uuid.UUID) ([]ProvisionerJobResource, error) { + rows, err := q.db.QueryContext(ctx, getProvisionerJobResourcesByJobID, jobID) + if err != nil { + return nil, err + } + defer rows.Close() + var items []ProvisionerJobResource + for rows.Next() { + var i ProvisionerJobResource + if err := rows.Scan( + &i.ID, + &i.CreatedAt, + &i.JobID, + &i.Transition, + &i.Type, + &i.Name, + &i.AgentID, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Close(); err != nil { + return nil, err + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + const getProvisionerLogsByIDBetween = `-- name: GetProvisionerLogsByIDBetween :many SELECT id, job_id, created_at, source, level, output @@ -834,45 +932,6 @@ func (q *sqlQuerier) GetUserCount(ctx context.Context) (int64, error) { return count, err } -const getWorkspaceAgentsByResourceIDs = `-- name: GetWorkspaceAgentsByResourceIDs :many -SELECT - id, workspace_resource_id, created_at, updated_at, instance_metadata, resource_metadata -FROM - workspace_agent -WHERE - workspace_resource_id = ANY($1 :: uuid [ ]) -` - -func (q *sqlQuerier) GetWorkspaceAgentsByResourceIDs(ctx context.Context, ids []uuid.UUID) ([]WorkspaceAgent, error) { - rows, err := q.db.QueryContext(ctx, getWorkspaceAgentsByResourceIDs, pq.Array(ids)) - if err != nil { - return nil, err - } - defer rows.Close() - var items []WorkspaceAgent - for rows.Next() { - var i WorkspaceAgent - if err := rows.Scan( - &i.ID, - &i.WorkspaceResourceID, - &i.CreatedAt, - &i.UpdatedAt, - &i.InstanceMetadata, - &i.ResourceMetadata, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Close(); err != nil { - return nil, err - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - const getWorkspaceByID = `-- name: GetWorkspaceByID :one SELECT id, created_at, updated_at, owner_id, project_id, name @@ -1111,74 +1170,6 @@ func (q *sqlQuerier) GetWorkspaceOwnerCountsByProjectIDs(ctx context.Context, id return items, nil } -const getWorkspaceResourceByInstanceID = `-- name: GetWorkspaceResourceByInstanceID :one -SELECT - id, created_at, workspace_history_id, instance_id, type, name, workspace_agent_token, workspace_agent_id -FROM - workspace_resource -WHERE - instance_id = $1 :: text -ORDER BY - created_at -` - -func (q *sqlQuerier) GetWorkspaceResourceByInstanceID(ctx context.Context, instanceID string) (WorkspaceResource, error) { - row := q.db.QueryRowContext(ctx, getWorkspaceResourceByInstanceID, instanceID) - var i WorkspaceResource - err := row.Scan( - &i.ID, - &i.CreatedAt, - &i.WorkspaceHistoryID, - &i.InstanceID, - &i.Type, - &i.Name, - &i.WorkspaceAgentToken, - &i.WorkspaceAgentID, - ) - return i, err -} - -const getWorkspaceResourcesByHistoryID = `-- name: GetWorkspaceResourcesByHistoryID :many -SELECT - id, created_at, workspace_history_id, instance_id, type, name, workspace_agent_token, workspace_agent_id -FROM - workspace_resource -WHERE - workspace_history_id = $1 -` - -func (q *sqlQuerier) GetWorkspaceResourcesByHistoryID(ctx context.Context, workspaceHistoryID uuid.UUID) ([]WorkspaceResource, error) { - rows, err := q.db.QueryContext(ctx, getWorkspaceResourcesByHistoryID, workspaceHistoryID) - if err != nil { - return nil, err - } - defer rows.Close() - var items []WorkspaceResource - for rows.Next() { - var i WorkspaceResource - if err := rows.Scan( - &i.ID, - &i.CreatedAt, - &i.WorkspaceHistoryID, - &i.InstanceID, - &i.Type, - &i.Name, - &i.WorkspaceAgentToken, - &i.WorkspaceAgentID, - ); err != nil { - return nil, err - } - items = append(items, i) - } - if err := rows.Close(); err != nil { - return nil, err - } - if err := rows.Err(); err != nil { - return nil, err - } - return items, nil -} - const getWorkspacesByProjectAndUserID = `-- name: GetWorkspacesByProjectAndUserID :many SELECT id, created_at, updated_at, owner_id, project_id, name @@ -1677,43 +1668,6 @@ func (q *sqlQuerier) InsertProject(ctx context.Context, arg InsertProjectParams) return i, err } -const insertProjectImportJobResource = `-- name: InsertProjectImportJobResource :one -INSERT INTO - project_import_job_resource (id, created_at, job_id, transition, type, name) -VALUES - ($1, $2, $3, $4, $5, $6) RETURNING id, created_at, job_id, transition, type, name -` - -type InsertProjectImportJobResourceParams struct { - ID uuid.UUID `db:"id" json:"id"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - JobID uuid.UUID `db:"job_id" json:"job_id"` - Transition WorkspaceTransition `db:"transition" json:"transition"` - Type string `db:"type" json:"type"` - Name string `db:"name" json:"name"` -} - -func (q *sqlQuerier) InsertProjectImportJobResource(ctx context.Context, arg InsertProjectImportJobResourceParams) (ProjectImportJobResource, error) { - row := q.db.QueryRowContext(ctx, insertProjectImportJobResource, - arg.ID, - arg.CreatedAt, - arg.JobID, - arg.Transition, - arg.Type, - arg.Name, - ) - var i ProjectImportJobResource - err := row.Scan( - &i.ID, - &i.CreatedAt, - &i.JobID, - &i.Transition, - &i.Type, - &i.Name, - ) - return i, err -} - const insertProjectVersion = `-- name: InsertProjectVersion :one INSERT INTO project_version ( @@ -1859,6 +1813,66 @@ func (q *sqlQuerier) InsertProvisionerJob(ctx context.Context, arg InsertProvisi return i, err } +const insertProvisionerJobAgent = `-- name: InsertProvisionerJobAgent :one +INSERT INTO + provisioner_job_agent ( + id, + created_at, + updated_at, + resource_id, + auth_token, + auth_instance_id, + environment_variables, + startup_script, + instance_metadata, + resource_metadata + ) +VALUES + ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10) RETURNING id, created_at, updated_at, resource_id, auth_token, auth_instance_id, environment_variables, startup_script, instance_metadata, resource_metadata +` + +type InsertProvisionerJobAgentParams struct { + ID uuid.UUID `db:"id" json:"id"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + UpdatedAt sql.NullTime `db:"updated_at" json:"updated_at"` + ResourceID uuid.UUID `db:"resource_id" json:"resource_id"` + AuthToken uuid.UUID `db:"auth_token" json:"auth_token"` + AuthInstanceID sql.NullString `db:"auth_instance_id" json:"auth_instance_id"` + EnvironmentVariables pqtype.NullRawMessage `db:"environment_variables" json:"environment_variables"` + StartupScript sql.NullString `db:"startup_script" json:"startup_script"` + InstanceMetadata pqtype.NullRawMessage `db:"instance_metadata" json:"instance_metadata"` + ResourceMetadata pqtype.NullRawMessage `db:"resource_metadata" json:"resource_metadata"` +} + +func (q *sqlQuerier) InsertProvisionerJobAgent(ctx context.Context, arg InsertProvisionerJobAgentParams) (ProvisionerJobAgent, error) { + row := q.db.QueryRowContext(ctx, insertProvisionerJobAgent, + arg.ID, + arg.CreatedAt, + arg.UpdatedAt, + arg.ResourceID, + arg.AuthToken, + arg.AuthInstanceID, + arg.EnvironmentVariables, + arg.StartupScript, + arg.InstanceMetadata, + arg.ResourceMetadata, + ) + var i ProvisionerJobAgent + err := row.Scan( + &i.ID, + &i.CreatedAt, + &i.UpdatedAt, + &i.ResourceID, + &i.AuthToken, + &i.AuthInstanceID, + &i.EnvironmentVariables, + &i.StartupScript, + &i.InstanceMetadata, + &i.ResourceMetadata, + ) + return i, err +} + const insertProvisionerJobLogs = `-- name: InsertProvisionerJobLogs :many INSERT INTO provisioner_job_log @@ -1917,6 +1931,54 @@ func (q *sqlQuerier) InsertProvisionerJobLogs(ctx context.Context, arg InsertPro return items, nil } +const insertProvisionerJobResource = `-- name: InsertProvisionerJobResource :one +INSERT INTO + provisioner_job_resource ( + id, + created_at, + job_id, + transition, + type, + name, + agent_id + ) +VALUES + ($1, $2, $3, $4, $5, $6, $7) RETURNING id, created_at, job_id, transition, type, name, agent_id +` + +type InsertProvisionerJobResourceParams struct { + ID uuid.UUID `db:"id" json:"id"` + CreatedAt time.Time `db:"created_at" json:"created_at"` + JobID uuid.UUID `db:"job_id" json:"job_id"` + Transition WorkspaceTransition `db:"transition" json:"transition"` + Type string `db:"type" json:"type"` + Name string `db:"name" json:"name"` + AgentID uuid.NullUUID `db:"agent_id" json:"agent_id"` +} + +func (q *sqlQuerier) InsertProvisionerJobResource(ctx context.Context, arg InsertProvisionerJobResourceParams) (ProvisionerJobResource, error) { + row := q.db.QueryRowContext(ctx, insertProvisionerJobResource, + arg.ID, + arg.CreatedAt, + arg.JobID, + arg.Transition, + arg.Type, + arg.Name, + arg.AgentID, + ) + var i ProvisionerJobResource + err := row.Scan( + &i.ID, + &i.CreatedAt, + &i.JobID, + &i.Transition, + &i.Type, + &i.Name, + &i.AgentID, + ) + return i, err +} + const insertUser = `-- name: InsertUser :one INSERT INTO users ( @@ -2025,50 +2087,6 @@ func (q *sqlQuerier) InsertWorkspace(ctx context.Context, arg InsertWorkspacePar return i, err } -const insertWorkspaceAgent = `-- name: InsertWorkspaceAgent :one -INSERT INTO - workspace_agent ( - id, - workspace_resource_id, - created_at, - updated_at, - instance_metadata, - resource_metadata - ) -VALUES - ($1, $2, $3, $4, $5, $6) RETURNING id, workspace_resource_id, created_at, updated_at, instance_metadata, resource_metadata -` - -type InsertWorkspaceAgentParams struct { - ID uuid.UUID `db:"id" json:"id"` - WorkspaceResourceID uuid.UUID `db:"workspace_resource_id" json:"workspace_resource_id"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - UpdatedAt time.Time `db:"updated_at" json:"updated_at"` - InstanceMetadata json.RawMessage `db:"instance_metadata" json:"instance_metadata"` - ResourceMetadata json.RawMessage `db:"resource_metadata" json:"resource_metadata"` -} - -func (q *sqlQuerier) InsertWorkspaceAgent(ctx context.Context, arg InsertWorkspaceAgentParams) (WorkspaceAgent, error) { - row := q.db.QueryRowContext(ctx, insertWorkspaceAgent, - arg.ID, - arg.WorkspaceResourceID, - arg.CreatedAt, - arg.UpdatedAt, - arg.InstanceMetadata, - arg.ResourceMetadata, - ) - var i WorkspaceAgent - err := row.Scan( - &i.ID, - &i.WorkspaceResourceID, - &i.CreatedAt, - &i.UpdatedAt, - &i.InstanceMetadata, - &i.ResourceMetadata, - ) - return i, err -} - const insertWorkspaceHistory = `-- name: InsertWorkspaceHistory :one INSERT INTO workspace_history ( @@ -2134,55 +2152,6 @@ func (q *sqlQuerier) InsertWorkspaceHistory(ctx context.Context, arg InsertWorks return i, err } -const insertWorkspaceResource = `-- name: InsertWorkspaceResource :one -INSERT INTO - workspace_resource ( - id, - created_at, - workspace_history_id, - instance_id, - type, - name, - workspace_agent_token - ) -VALUES - ($1, $2, $3, $4, $5, $6, $7) RETURNING id, created_at, workspace_history_id, instance_id, type, name, workspace_agent_token, workspace_agent_id -` - -type InsertWorkspaceResourceParams struct { - ID uuid.UUID `db:"id" json:"id"` - CreatedAt time.Time `db:"created_at" json:"created_at"` - WorkspaceHistoryID uuid.UUID `db:"workspace_history_id" json:"workspace_history_id"` - InstanceID sql.NullString `db:"instance_id" json:"instance_id"` - Type string `db:"type" json:"type"` - Name string `db:"name" json:"name"` - WorkspaceAgentToken string `db:"workspace_agent_token" json:"workspace_agent_token"` -} - -func (q *sqlQuerier) InsertWorkspaceResource(ctx context.Context, arg InsertWorkspaceResourceParams) (WorkspaceResource, error) { - row := q.db.QueryRowContext(ctx, insertWorkspaceResource, - arg.ID, - arg.CreatedAt, - arg.WorkspaceHistoryID, - arg.InstanceID, - arg.Type, - arg.Name, - arg.WorkspaceAgentToken, - ) - var i WorkspaceResource - err := row.Scan( - &i.ID, - &i.CreatedAt, - &i.WorkspaceHistoryID, - &i.InstanceID, - &i.Type, - &i.Name, - &i.WorkspaceAgentToken, - &i.WorkspaceAgentID, - ) - return i, err -} - const updateAPIKeyByID = `-- name: UpdateAPIKeyByID :exec UPDATE api_keys diff --git a/go.mod b/go.mod index 35569e6f1ec01..1180eba9f01cc 100644 --- a/go.mod +++ b/go.mod @@ -55,6 +55,7 @@ require ( github.com/quasilyte/go-ruleguard/dsl v0.3.17 github.com/spf13/cobra v1.3.0 github.com/stretchr/testify v1.7.0 + github.com/tabbed/pqtype v0.1.1 github.com/unrolled/secure v1.10.0 github.com/xlab/treeprint v1.1.0 go.opencensus.io v0.23.0 diff --git a/go.sum b/go.sum index 6c5de14b22110..68dd21a43d74e 100644 --- a/go.sum +++ b/go.sum @@ -1251,6 +1251,8 @@ github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69 github.com/syndtr/gocapability v0.0.0-20170704070218-db04d3cc01c8/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20180916011248-d98352740cb2/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= github.com/syndtr/gocapability v0.0.0-20200815063812-42c35b437635/go.mod h1:hkRG7XYTFWNJGYcbNJQlaLq0fg1yr4J4t/NcTQtrfww= +github.com/tabbed/pqtype v0.1.1 h1:PhEcb9JZ8jr7SUjJDFjRPxny0M8fkXZrxn/a9yQfoZg= +github.com/tabbed/pqtype v0.1.1/go.mod h1:HLt2kLJPcUhODQkYn3mJkMHXVsuv3Z2n5NZEeKXL0Uk= github.com/tchap/go-patricia v2.2.6+incompatible/go.mod h1:bmLyhP68RS6kStMGxByiQ23RP/odRBOTVjwp2cDyi6I= github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk= github.com/tmc/grpc-websocket-proxy v0.0.0-20170815181823-89b8d40f7ca8/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U= From 8de9e61c6b71ee9d7b45a0a1432920629c8c497f Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sun, 27 Feb 2022 18:11:11 +0000 Subject: [PATCH 11/21] Add "coder_workspace" data source --- provisioner/terraform/provider/provider.go | 19 ++++++++++++ .../terraform/provider/provider_test.go | 29 +++++++++++++++++++ 2 files changed, 48 insertions(+) diff --git a/provisioner/terraform/provider/provider.go b/provisioner/terraform/provider/provider.go index fa0ec83695073..034b091dc66d1 100644 --- a/provisioner/terraform/provider/provider.go +++ b/provisioner/terraform/provider/provider.go @@ -12,6 +12,7 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/coder/coder/database" "github.com/coder/coder/provisionersdk" ) @@ -57,6 +58,24 @@ func New() *schema.Provider { }, nil }, DataSourcesMap: map[string]*schema.Resource{ + "coder_workspace": { + Description: "TODO", + ReadContext: func(c context.Context, rd *schema.ResourceData, i interface{}) diag.Diagnostics { + rd.SetId(uuid.NewString()) + return nil + }, + Schema: map[string]*schema.Schema{ + "transition": { + Type: schema.TypeString, + Optional: true, + Description: "TODO", + DefaultFunc: func() (interface{}, error) { + return os.Getenv("CODER_WORKSPACE_TRANSITION"), nil + }, + ValidateFunc: validation.StringInSlice([]string{string(database.WorkspaceTransitionStart), string(database.WorkspaceTransitionStop)}, false), + }, + }, + }, "coder_agent_script": { Description: "TODO", ReadContext: func(c context.Context, resourceData *schema.ResourceData, i interface{}) diag.Diagnostics { diff --git a/provisioner/terraform/provider/provider_test.go b/provisioner/terraform/provider/provider_test.go index 39348af351ca0..c77db5de85f9a 100644 --- a/provisioner/terraform/provider/provider_test.go +++ b/provisioner/terraform/provider/provider_test.go @@ -19,6 +19,35 @@ func TestProvider(t *testing.T) { require.NoError(t, err) } +func TestWorkspace(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_workspace" "me" { + transition = "start" + }`, + 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_workspace.me"] + require.NotNil(t, resource) + value := resource.Primary.Attributes["transition"] + require.NotNil(t, value) + t.Log(value) + return nil + }, + }}, + }) +} + func TestAgentScript(t *testing.T) { t.Parallel() resource.Test(t, resource.TestCase{ From cb1c883116b31395c5e751ce421c8e6fafbb3056 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sun, 27 Feb 2022 18:56:10 +0000 Subject: [PATCH 12/21] feat: Remove magical parameters from being injected This is a much cleaner abstraction. Explicitly declaring the user parameters for each provisioner makes for significantly simpler testing. --- cli/projectcreate.go | 4 - cli/projectcreate_test.go | 2 +- coderd/cmd/root.go | 16 +- coderd/coderd.go | 8 +- coderd/coderdtest/coderdtest.go | 19 +- coderd/parameter/compute.go | 5 - coderd/provisionerdaemons.go | 33 ++- coderd/provisionerjobs_test.go | 11 +- provisioner/terraform/provision.go | 10 +- provisioner/terraform/provision_test.go | 21 +- provisionerd/proto/provisionerd.pb.go | 249 +++++++++------- provisionerd/proto/provisionerd.proto | 4 +- provisionerd/provisionerd.go | 52 +--- provisionerd/provisionerd_test.go | 27 +- provisionersdk/proto/provisioner.pb.go | 366 ++++++++++++++++-------- provisionersdk/proto/provisioner.proto | 14 +- 16 files changed, 518 insertions(+), 323 deletions(-) diff --git a/cli/projectcreate.go b/cli/projectcreate.go index 2b1d17f0711f6..a1e5027c26715 100644 --- a/cli/projectcreate.go +++ b/cli/projectcreate.go @@ -18,7 +18,6 @@ import ( "golang.org/x/xerrors" "github.com/coder/coder/coderd" - "github.com/coder/coder/coderd/parameter" "github.com/coder/coder/codersdk" "github.com/coder/coder/database" "github.com/coder/coder/provisionerd" @@ -187,9 +186,6 @@ func validateProjectVersionSource(cmd *cobra.Command, client *codersdk.Client, o if ok { continue } - if parameterSchema.Name == parameter.CoderWorkspaceTransition { - continue - } value, err := prompt(cmd, &promptui.Prompt{ Label: fmt.Sprintf("Enter value for %s:", color.HiCyanString(parameterSchema.Name)), }) diff --git a/cli/projectcreate_test.go b/cli/projectcreate_test.go index 29cd674601c1b..b973de4688295 100644 --- a/cli/projectcreate_test.go +++ b/cli/projectcreate_test.go @@ -86,7 +86,7 @@ func TestProjectCreate(t *testing.T) { matches := []string{ "organization?", "y", "name?", "test-project", - "somevar:", "value", + "somevar", "value", "project?", "y", "created!", "n", } diff --git a/coderd/cmd/root.go b/coderd/cmd/root.go index 2778cb320a17e..162390898aa77 100644 --- a/coderd/cmd/root.go +++ b/coderd/cmd/root.go @@ -33,10 +33,15 @@ func Root() *cobra.Command { Use: "coderd", RunE: func(cmd *cobra.Command, args []string) error { logger := slog.Make(sloghuman.Sink(os.Stderr)) + accessURL := &url.URL{ + Scheme: "http", + Host: address, + } handler, closeCoderd := coderd.New(&coderd.Options{ - Logger: logger, - Database: databasefake.New(), - Pubsub: database.NewPubsubInMemory(), + AccessURL: accessURL, + Logger: logger, + Database: databasefake.New(), + Pubsub: database.NewPubsubInMemory(), }) listener, err := net.Listen("tcp", address) @@ -45,10 +50,7 @@ func Root() *cobra.Command { } defer listener.Close() - client := codersdk.New(&url.URL{ - Scheme: "http", - Host: address, - }) + client := codersdk.New(accessURL) daemonClose, err := newProvisionerDaemon(cmd.Context(), client, logger) if err != nil { return xerrors.Errorf("create provisioner daemon: %w", err) diff --git a/coderd/coderd.go b/coderd/coderd.go index 4de6135890f11..69a8432aa53bf 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -2,6 +2,7 @@ package coderd import ( "net/http" + "net/url" "sync" "github.com/go-chi/chi/v5" @@ -16,9 +17,10 @@ import ( // Options are requires parameters for Coder to start. type Options struct { - Logger slog.Logger - Database database.Store - Pubsub database.Pubsub + AccessURL *url.URL + Logger slog.Logger + Database database.Store + Pubsub database.Pubsub GoogleTokenValidator *idtoken.Validator } diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index 01cb3aa9759f6..58dd9ceb53292 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -80,14 +80,7 @@ func New(t *testing.T, options *Options) *codersdk.Client { }) } - handler, closeWait := coderd.New(&coderd.Options{ - Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug), - Database: db, - Pubsub: pubsub, - - GoogleTokenValidator: options.GoogleTokenValidator, - }) - srv := httptest.NewUnstartedServer(handler) + srv := httptest.NewUnstartedServer(nil) srv.Config.BaseContext = func(_ net.Listener) context.Context { ctx, cancelFunc := context.WithCancel(context.Background()) t.Cleanup(cancelFunc) @@ -96,6 +89,16 @@ func New(t *testing.T, options *Options) *codersdk.Client { srv.Start() serverURL, err := url.Parse(srv.URL) require.NoError(t, err) + var closeWait func() + // We set the handler after server creation for the access URL. + srv.Config.Handler, closeWait = coderd.New(&coderd.Options{ + AccessURL: serverURL, + Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug), + Database: db, + Pubsub: pubsub, + + GoogleTokenValidator: options.GoogleTokenValidator, + }) t.Cleanup(func() { srv.Close() closeWait() diff --git a/coderd/parameter/compute.go b/coderd/parameter/compute.go index d7c68a5ac30e1..ef3f624b14e7a 100644 --- a/coderd/parameter/compute.go +++ b/coderd/parameter/compute.go @@ -11,11 +11,6 @@ import ( "github.com/coder/coder/database" ) -const ( - CoderUsername = "coder_username" - CoderWorkspaceTransition = "coder_workspace_transition" -) - // ComputeScope targets identifiers to pull parameters from. type ComputeScope struct { ProjectImportJobID uuid.UUID diff --git a/coderd/provisionerdaemons.go b/coderd/provisionerdaemons.go index 1a50f808dd5fc..d630ddf56c670 100644 --- a/coderd/provisionerdaemons.go +++ b/coderd/provisionerdaemons.go @@ -8,6 +8,7 @@ import ( "fmt" "io" "net/http" + "net/url" "reflect" "time" @@ -90,6 +91,7 @@ func (api *api) provisionerDaemonsServe(rw http.ResponseWriter, r *http.Request) } mux := drpcmux.New() err = proto.DRPCRegisterProvisionerDaemon(mux, &provisionerdServer{ + AccessURL: api.AccessURL, ID: daemon.ID, Database: api.Database, Pubsub: api.Pubsub, @@ -117,6 +119,7 @@ type workspaceProvisionJob struct { // Implementation of the provisioner daemon protobuf server. type provisionerdServer struct { + AccessURL *url.URL ID uuid.UUID Logger slog.Logger Provisioners []database.ProvisionerType @@ -228,11 +231,10 @@ func (server *provisionerdServer) AcquireJob(ctx context.Context, _ *proto.Empty } protoParameters = append(protoParameters, converted) } - protoParameters = append(protoParameters, &sdkproto.ParameterValue{ - DestinationScheme: sdkproto.ParameterDestination_PROVISIONER_VARIABLE, - Name: parameter.CoderWorkspaceTransition, - Value: string(workspaceHistory.Transition), - }) + transition, err := convertWorkspaceTransition(workspaceHistory.Transition) + if err != nil { + return nil, failJob(fmt.Sprint("convert workspace transition: %w", err)) + } protoJob.Type = &proto.AcquiredJob_WorkspaceProvision_{ WorkspaceProvision: &proto.AcquiredJob_WorkspaceProvision{ @@ -240,11 +242,19 @@ func (server *provisionerdServer) AcquireJob(ctx context.Context, _ *proto.Empty WorkspaceName: workspace.Name, State: workspaceHistory.ProvisionerState, ParameterValues: protoParameters, + Metadata: &sdkproto.Provision_Metadata{ + CoderUrl: server.AccessURL.String(), + WorkspaceTransition: transition, + }, }, } case database.ProvisionerJobTypeProjectVersionImport: protoJob.Type = &proto.AcquiredJob_ProjectImport_{ - ProjectImport: &proto.AcquiredJob_ProjectImport{}, + ProjectImport: &proto.AcquiredJob_ProjectImport{ + Metadata: &sdkproto.Provision_Metadata{ + CoderUrl: server.AccessURL.String(), + }, + }, } } switch job.StorageMethod { @@ -660,3 +670,14 @@ func convertComputedParameterValue(param parameter.ComputedValue) (*sdkproto.Par Value: param.SourceValue, }, nil } + +func convertWorkspaceTransition(transition database.WorkspaceTransition) (sdkproto.WorkspaceTransition, error) { + switch transition { + case database.WorkspaceTransitionStart: + return sdkproto.WorkspaceTransition_START, nil + case database.WorkspaceTransitionStop: + return sdkproto.WorkspaceTransition_STOP, nil + default: + return 0, xerrors.Errorf("unrecognized transition: %q", transition) + } +} diff --git a/coderd/provisionerjobs_test.go b/coderd/provisionerjobs_test.go index 355f601ddb2d9..b33169a58fd1a 100644 --- a/coderd/provisionerjobs_test.go +++ b/coderd/provisionerjobs_test.go @@ -10,7 +10,6 @@ import ( "github.com/coder/coder/coderd" "github.com/coder/coder/coderd/coderdtest" - "github.com/coder/coder/coderd/parameter" "github.com/coder/coder/codersdk" "github.com/coder/coder/database" "github.com/coder/coder/provisioner/echo" @@ -180,15 +179,7 @@ func TestProvisionerJobResourcesByID(t *testing.T) { user := coderdtest.CreateInitialUser(t, client) _ = coderdtest.NewProvisionerDaemon(t, client) job := coderdtest.CreateProjectImportJob(t, client, user.Organization, &echo.Responses{ - Parse: []*proto.Parse_Response{{ - Type: &proto.Parse_Response_Complete{ - Complete: &proto.Parse_Complete{ - ParameterSchemas: []*proto.ParameterSchema{{ - Name: parameter.CoderWorkspaceTransition, - }}, - }, - }, - }}, + Parse: echo.ParseComplete, Provision: []*proto.Provision_Response{{ Type: &proto.Provision_Response_Complete{ Complete: &proto.Provision_Complete{ diff --git a/provisioner/terraform/provision.go b/provisioner/terraform/provision.go index a06fae5135bf6..37617f32479d2 100644 --- a/provisioner/terraform/provision.go +++ b/provisioner/terraform/provision.go @@ -74,7 +74,10 @@ 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{} + env := map[string]string{ + "CODER_URL": request.Metadata.CoderUrl, + "CODER_WORKSPACE_TRANSITION": strings.ToLower(request.Metadata.WorkspaceTransition.String()), + } planfilePath := filepath.Join(request.Directory, "terraform.tfplan") options := []tfexec.PlanOption{tfexec.JSON(true), tfexec.Out(planfilePath)} for _, param := range request.ParameterValues { @@ -250,7 +253,10 @@ func (t *terraform) runTerraformPlan(ctx context.Context, terraform *tfexec.Terr } func (t *terraform) runTerraformApply(ctx context.Context, terraform *tfexec.Terraform, request *proto.Provision_Request, stream proto.DRPCProvisioner_ProvisionStream, statefilePath string) error { - env := map[string]string{} + env := map[string]string{ + "CODER_URL": request.Metadata.CoderUrl, + "CODER_WORKSPACE_TRANSITION": strings.ToLower(request.Metadata.WorkspaceTransition.String()), + } options := []tfexec.ApplyOption{tfexec.JSON(true)} for _, param := range request.ParameterValues { switch param.DestinationScheme { diff --git a/provisioner/terraform/provision_test.go b/provisioner/terraform/provision_test.go index ca1cc0fb9683d..edaf1aff0c1cf 100644 --- a/provisioner/terraform/provision_test.go +++ b/provisioner/terraform/provision_test.go @@ -51,7 +51,6 @@ terraform { } provider "coder" { - url = "https://example.com" } ` t.Log(provider) @@ -174,6 +173,11 @@ provider "coder" { ] }`, }, + Request: &proto.Provision_Request{ + Metadata: &proto.Provision_Metadata{ + CoderUrl: "https://example.com", + }, + }, Response: &proto.Provision_Response{ Type: &proto.Provision_Response_Complete{ Complete: &proto.Provision_Complete{ @@ -204,6 +208,11 @@ provider "coder" { } resource "null_resource" "A" {}`, }, + Request: &proto.Provision_Request{ + Metadata: &proto.Provision_Metadata{ + CoderUrl: "https://example.com", + }, + }, Response: &proto.Provision_Response{ Type: &proto.Provision_Response_Complete{ Complete: &proto.Provision_Complete{ @@ -235,6 +244,9 @@ provider "coder" { }, Request: &proto.Provision_Request{ DryRun: true, + Metadata: &proto.Provision_Metadata{ + CoderUrl: "https://example.com", + }, }, Response: &proto.Provision_Response{ Type: &proto.Provision_Response_Complete{ @@ -266,6 +278,9 @@ provider "coder" { }, Request: &proto.Provision_Request{ DryRun: true, + Metadata: &proto.Provision_Metadata{ + CoderUrl: "https://example.com", + }, }, Response: &proto.Provision_Response{ Type: &proto.Provision_Response_Complete{ @@ -302,6 +317,10 @@ provider "coder" { request.ParameterValues = testCase.Request.ParameterValues request.State = testCase.Request.State request.DryRun = testCase.Request.DryRun + request.Metadata = testCase.Request.Metadata + } + if request.Metadata == nil { + request.Metadata = &proto.Provision_Metadata{} } response, err := api.Provision(ctx, request) require.NoError(t, err) diff --git a/provisionerd/proto/provisionerd.pb.go b/provisionerd/proto/provisionerd.pb.go index 1c3db72fd341b..c1292c4a0eb69 100644 --- a/provisionerd/proto/provisionerd.pb.go +++ b/provisionerd/proto/provisionerd.pb.go @@ -562,10 +562,11 @@ type AcquiredJob_WorkspaceProvision struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - WorkspaceHistoryId string `protobuf:"bytes,1,opt,name=workspace_history_id,json=workspaceHistoryId,proto3" json:"workspace_history_id,omitempty"` - WorkspaceName string `protobuf:"bytes,2,opt,name=workspace_name,json=workspaceName,proto3" json:"workspace_name,omitempty"` - ParameterValues []*proto.ParameterValue `protobuf:"bytes,3,rep,name=parameter_values,json=parameterValues,proto3" json:"parameter_values,omitempty"` - State []byte `protobuf:"bytes,4,opt,name=state,proto3" json:"state,omitempty"` + WorkspaceHistoryId string `protobuf:"bytes,1,opt,name=workspace_history_id,json=workspaceHistoryId,proto3" json:"workspace_history_id,omitempty"` + WorkspaceName string `protobuf:"bytes,2,opt,name=workspace_name,json=workspaceName,proto3" json:"workspace_name,omitempty"` + ParameterValues []*proto.ParameterValue `protobuf:"bytes,3,rep,name=parameter_values,json=parameterValues,proto3" json:"parameter_values,omitempty"` + Metadata *proto.Provision_Metadata `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"` + State []byte `protobuf:"bytes,5,opt,name=state,proto3" json:"state,omitempty"` } func (x *AcquiredJob_WorkspaceProvision) Reset() { @@ -621,6 +622,13 @@ func (x *AcquiredJob_WorkspaceProvision) GetParameterValues() []*proto.Parameter return nil } +func (x *AcquiredJob_WorkspaceProvision) GetMetadata() *proto.Provision_Metadata { + if x != nil { + return x.Metadata + } + return nil +} + func (x *AcquiredJob_WorkspaceProvision) GetState() []byte { if x != nil { return x.State @@ -632,6 +640,8 @@ type AcquiredJob_ProjectImport struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + Metadata *proto.Provision_Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` } func (x *AcquiredJob_ProjectImport) Reset() { @@ -666,6 +676,13 @@ func (*AcquiredJob_ProjectImport) Descriptor() ([]byte, []int) { return file_provisionerd_proto_provisionerd_proto_rawDescGZIP(), []int{1, 1} } +func (x *AcquiredJob_ProjectImport) GetMetadata() *proto.Provision_Metadata { + if x != nil { + return x.Metadata + } + return nil +} + type CompletedJob_WorkspaceProvision struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -785,7 +802,7 @@ var file_provisionerd_proto_provisionerd_proto_rawDesc = []byte{ 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x1a, 0x26, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x07, 0x0a, - 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0xd2, 0x04, 0x0a, 0x0b, 0x41, 0x63, 0x71, 0x75, 0x69, + 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0xcc, 0x05, 0x0a, 0x0b, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, @@ -808,7 +825,7 @@ var file_provisionerd_proto_provisionerd_proto_rawDesc = []byte{ 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6d, - 0x70, 0x6f, 0x72, 0x74, 0x1a, 0xcb, 0x01, 0x0a, 0x12, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, + 0x70, 0x6f, 0x72, 0x74, 0x1a, 0x88, 0x02, 0x0a, 0x12, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x30, 0x0a, 0x14, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x68, 0x69, 0x73, 0x74, 0x6f, 0x72, 0x79, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x73, @@ -819,94 +836,101 @@ var file_provisionerd_proto_provisionerd_proto_rawDesc = []byte{ 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 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, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x1a, 0x0f, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x70, - 0x6f, 0x72, 0x74, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3b, 0x0a, 0x0c, 0x43, - 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x15, 0x0a, 0x06, 0x6a, - 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, - 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x22, 0xd3, 0x03, 0x0a, 0x0c, 0x43, 0x6f, 0x6d, - 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, - 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, - 0x12, 0x60, 0x0a, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, - 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x12, - 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x12, 0x51, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x6d, - 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, - 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6d, - 0x70, 0x6f, 0x72, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, - 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x1a, 0x5f, 0x0a, 0x12, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 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, 0x8d, 0x01, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x6a, 0x65, - 0x63, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x3e, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, - 0x74, 0x5f, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 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, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x52, - 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x12, 0x3c, 0x0a, 0x0e, 0x73, 0x74, 0x6f, 0x70, - 0x5f, 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, 0x0d, 0x73, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x9a, - 0x01, 0x0a, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x2f, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x4c, 0x6f, 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, - 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, - 0x18, 0x02, 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, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, - 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, - 0x64, 0x41, 0x74, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x04, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x9b, 0x01, 0x0a, 0x10, - 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, - 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, - 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x49, - 0x0a, 0x11, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x63, 0x68, 0x65, - 0x6d, 0x61, 0x73, 0x18, 0x03, 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, 0x22, 0x5b, 0x0a, 0x11, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, - 0x0a, 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x73, 0x18, 0x01, 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, 0x2a, 0x34, 0x0a, 0x09, 0x4c, 0x6f, 0x67, 0x53, 0x6f, 0x75, - 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, 0x12, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, - 0x45, 0x52, 0x5f, 0x44, 0x41, 0x45, 0x4d, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x50, - 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x45, 0x52, 0x10, 0x01, 0x32, 0x9d, 0x02, 0x0a, - 0x11, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x44, 0x61, 0x65, 0x6d, - 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x0a, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x4a, 0x6f, 0x62, - 0x12, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, - 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x4a, 0x6f, 0x62, - 0x12, 0x4c, 0x0a, 0x09, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x1e, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x64, - 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, - 0x0a, 0x09, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x4a, 0x6f, 0x62, 0x12, 0x1a, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, - 0x6c, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3e, 0x0a, 0x0b, - 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x1a, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, - 0x65, 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x2b, 0x5a, 0x29, - 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, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, - 0x33, + 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x08, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 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, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, + 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x1a, + 0x4c, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, + 0x12, 0x3b, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 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, 0x4d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x06, 0x0a, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3b, 0x0a, 0x0c, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, + 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, + 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, + 0x6f, 0x72, 0x22, 0xd3, 0x03, 0x0a, 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, + 0x4a, 0x6f, 0x62, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x60, 0x0a, 0x13, 0x77, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, + 0x4a, 0x6f, 0x62, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x51, 0x0a, 0x0e, + 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, + 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x48, 0x00, + 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x1a, + 0x5f, 0x0a, 0x12, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 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, 0x8d, 0x01, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x70, 0x6f, + 0x72, 0x74, 0x12, 0x3e, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x6f, + 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 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, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x12, 0x3c, 0x0a, 0x0e, 0x73, 0x74, 0x6f, 0x70, 0x5f, 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, 0x0d, 0x73, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, + 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x9a, 0x01, 0x0a, 0x03, 0x4c, 0x6f, 0x67, + 0x12, 0x2f, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, + 0x4c, 0x6f, 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x02, 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, 0x1d, + 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, + 0x28, 0x03, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x16, 0x0a, + 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, + 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x9b, 0x01, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, + 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, + 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, + 0x64, 0x12, 0x25, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x4c, + 0x6f, 0x67, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x49, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x61, + 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, 0x03, 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, 0x22, 0x5b, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x10, 0x70, 0x61, 0x72, 0x61, + 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 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, + 0x2a, 0x34, 0x0a, 0x09, 0x4c, 0x6f, 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, + 0x12, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x45, + 0x4d, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, + 0x4f, 0x4e, 0x45, 0x52, 0x10, 0x01, 0x32, 0x9d, 0x02, 0x0a, 0x11, 0x50, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x0a, + 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x13, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, + 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x41, + 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x4c, 0x0a, 0x09, 0x55, 0x70, + 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, + 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x09, 0x43, 0x61, 0x6e, 0x63, + 0x65, 0x6c, 0x4a, 0x6f, 0x62, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x4a, 0x6f, + 0x62, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3e, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, + 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, 0x6f, + 0x62, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x2b, 0x5a, 0x29, 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, 0x64, 0x2f, 0x70, 0x72, + 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -939,7 +963,8 @@ var file_provisionerd_proto_provisionerd_proto_goTypes = []interface{}{ (proto.LogLevel)(0), // 12: provisioner.LogLevel (*proto.ParameterSchema)(nil), // 13: provisioner.ParameterSchema (*proto.ParameterValue)(nil), // 14: provisioner.ParameterValue - (*proto.Resource)(nil), // 15: provisioner.Resource + (*proto.Provision_Metadata)(nil), // 15: provisioner.Provision.Metadata + (*proto.Resource)(nil), // 16: provisioner.Resource } var file_provisionerd_proto_provisionerd_proto_depIdxs = []int32{ 8, // 0: provisionerd.AcquiredJob.workspace_provision:type_name -> provisionerd.AcquiredJob.WorkspaceProvision @@ -952,22 +977,24 @@ var file_provisionerd_proto_provisionerd_proto_depIdxs = []int32{ 13, // 7: provisionerd.UpdateJobRequest.parameter_schemas:type_name -> provisioner.ParameterSchema 14, // 8: provisionerd.UpdateJobResponse.parameter_values:type_name -> provisioner.ParameterValue 14, // 9: provisionerd.AcquiredJob.WorkspaceProvision.parameter_values:type_name -> provisioner.ParameterValue - 15, // 10: provisionerd.CompletedJob.WorkspaceProvision.resources:type_name -> provisioner.Resource - 15, // 11: provisionerd.CompletedJob.ProjectImport.start_resources:type_name -> provisioner.Resource - 15, // 12: provisionerd.CompletedJob.ProjectImport.stop_resources:type_name -> provisioner.Resource - 1, // 13: provisionerd.ProvisionerDaemon.AcquireJob:input_type -> provisionerd.Empty - 6, // 14: provisionerd.ProvisionerDaemon.UpdateJob:input_type -> provisionerd.UpdateJobRequest - 3, // 15: provisionerd.ProvisionerDaemon.CancelJob:input_type -> provisionerd.CancelledJob - 4, // 16: provisionerd.ProvisionerDaemon.CompleteJob:input_type -> provisionerd.CompletedJob - 2, // 17: provisionerd.ProvisionerDaemon.AcquireJob:output_type -> provisionerd.AcquiredJob - 7, // 18: provisionerd.ProvisionerDaemon.UpdateJob:output_type -> provisionerd.UpdateJobResponse - 1, // 19: provisionerd.ProvisionerDaemon.CancelJob:output_type -> provisionerd.Empty - 1, // 20: provisionerd.ProvisionerDaemon.CompleteJob:output_type -> provisionerd.Empty - 17, // [17:21] is the sub-list for method output_type - 13, // [13:17] is the sub-list for method input_type - 13, // [13:13] is the sub-list for extension type_name - 13, // [13:13] is the sub-list for extension extendee - 0, // [0:13] is the sub-list for field type_name + 15, // 10: provisionerd.AcquiredJob.WorkspaceProvision.metadata:type_name -> provisioner.Provision.Metadata + 15, // 11: provisionerd.AcquiredJob.ProjectImport.metadata:type_name -> provisioner.Provision.Metadata + 16, // 12: provisionerd.CompletedJob.WorkspaceProvision.resources:type_name -> provisioner.Resource + 16, // 13: provisionerd.CompletedJob.ProjectImport.start_resources:type_name -> provisioner.Resource + 16, // 14: provisionerd.CompletedJob.ProjectImport.stop_resources:type_name -> provisioner.Resource + 1, // 15: provisionerd.ProvisionerDaemon.AcquireJob:input_type -> provisionerd.Empty + 6, // 16: provisionerd.ProvisionerDaemon.UpdateJob:input_type -> provisionerd.UpdateJobRequest + 3, // 17: provisionerd.ProvisionerDaemon.CancelJob:input_type -> provisionerd.CancelledJob + 4, // 18: provisionerd.ProvisionerDaemon.CompleteJob:input_type -> provisionerd.CompletedJob + 2, // 19: provisionerd.ProvisionerDaemon.AcquireJob:output_type -> provisionerd.AcquiredJob + 7, // 20: provisionerd.ProvisionerDaemon.UpdateJob:output_type -> provisionerd.UpdateJobResponse + 1, // 21: provisionerd.ProvisionerDaemon.CancelJob:output_type -> provisionerd.Empty + 1, // 22: provisionerd.ProvisionerDaemon.CompleteJob:output_type -> provisionerd.Empty + 19, // [19:23] is the sub-list for method output_type + 15, // [15:19] is the sub-list for method input_type + 15, // [15:15] is the sub-list for extension type_name + 15, // [15:15] is the sub-list for extension extendee + 0, // [0:15] is the sub-list for field type_name } func init() { file_provisionerd_proto_provisionerd_proto_init() } diff --git a/provisionerd/proto/provisionerd.proto b/provisionerd/proto/provisionerd.proto index 64a37bd3e05ef..17bd5ffe01a1c 100644 --- a/provisionerd/proto/provisionerd.proto +++ b/provisionerd/proto/provisionerd.proto @@ -15,9 +15,11 @@ message AcquiredJob { string workspace_history_id = 1; string workspace_name = 2; repeated provisioner.ParameterValue parameter_values = 3; - bytes state = 4; + provisioner.Provision.Metadata metadata = 4; + bytes state = 5; } message ProjectImport { + provisioner.Provision.Metadata metadata = 1; } string job_id = 1; int64 created_at = 2; diff --git a/provisionerd/provisionerd.go b/provisionerd/provisionerd.go index b8449a38fbb05..dc84207ec3048 100644 --- a/provisionerd/provisionerd.go +++ b/provisionerd/provisionerd.go @@ -19,8 +19,6 @@ import ( "golang.org/x/xerrors" "cdr.dev/slog" - "github.com/coder/coder/coderd/parameter" - "github.com/coder/coder/database" "github.com/coder/coder/provisionerd/proto" sdkproto "github.com/coder/coder/provisionersdk/proto" "github.com/coder/retry" @@ -368,52 +366,28 @@ func (p *provisionerDaemon) runProjectImport(ctx context.Context, provisioner sd valueByName[parameterValue.Name] = parameterValue } for _, parameterSchema := range parameterSchemas { - if parameterSchema.Name == parameter.CoderWorkspaceTransition { - // Hardcode the workspace transition variable. We'll - // make it do stuff later! - continue - } _, ok := valueByName[parameterSchema.Name] if !ok { p.cancelActiveJobf("%s: %s", missingParameterErrorText, parameterSchema.Name) return } } - // Checks if the schema has defined a workspace transition variable. - // If not, we don't need to check for resources provisioned in a stopped state. - hasWorkspaceTransition := false - for _, parameterSchema := range parameterSchemas { - if parameterSchema.Name != parameter.CoderWorkspaceTransition { - continue - } - hasWorkspaceTransition = true - break - } - startParameters := updateResponse.ParameterValues - if hasWorkspaceTransition { - startParameters = append(updateResponse.ParameterValues, &sdkproto.ParameterValue{ - DestinationScheme: sdkproto.ParameterDestination_PROVISIONER_VARIABLE, - Name: parameter.CoderWorkspaceTransition, - Value: string(database.WorkspaceTransitionStart), - }) - } - startResources, err := p.runProjectImportProvision(ctx, provisioner, job, startParameters) + startResources, err := p.runProjectImportProvision(ctx, provisioner, job, updateResponse.ParameterValues, &sdkproto.Provision_Metadata{ + CoderUrl: job.GetProjectImport().Metadata.CoderUrl, + WorkspaceTransition: sdkproto.WorkspaceTransition_START, + }) if err != nil { p.cancelActiveJobf("project import provision for start: %s", err) return } - stopResources := startResources - if hasWorkspaceTransition { - stopResources, err = p.runProjectImportProvision(ctx, provisioner, job, append(updateResponse.ParameterValues, &sdkproto.ParameterValue{ - DestinationScheme: sdkproto.ParameterDestination_PROVISIONER_VARIABLE, - Name: "coder_workspace_transition", - Value: string(database.WorkspaceTransitionStop), - })) - if err != nil { - p.cancelActiveJobf("project import provision for start: %s", err) - return - } + stopResources, err := p.runProjectImportProvision(ctx, provisioner, job, updateResponse.ParameterValues, &sdkproto.Provision_Metadata{ + CoderUrl: job.GetProjectImport().Metadata.CoderUrl, + WorkspaceTransition: sdkproto.WorkspaceTransition_STOP, + }) + if err != nil { + p.cancelActiveJobf("project import provision for start: %s", err) + return } _, err = p.client.CompleteJob(ctx, &proto.CompletedJob{ @@ -479,11 +453,12 @@ func (p *provisionerDaemon) runProjectImportParse(ctx context.Context, provision // Performs a dry-run provision when importing a project. // This is used to detect resources that would be provisioned // for a workspace in various states. -func (p *provisionerDaemon) runProjectImportProvision(ctx context.Context, provisioner sdkproto.DRPCProvisionerClient, job *proto.AcquiredJob, values []*sdkproto.ParameterValue) ([]*sdkproto.Resource, error) { +func (p *provisionerDaemon) runProjectImportProvision(ctx context.Context, provisioner sdkproto.DRPCProvisionerClient, job *proto.AcquiredJob, values []*sdkproto.ParameterValue, metadata *sdkproto.Provision_Metadata) ([]*sdkproto.Resource, error) { stream, err := provisioner.Provision(ctx, &sdkproto.Provision_Request{ Directory: p.opts.WorkDirectory, ParameterValues: values, DryRun: true, + Metadata: metadata, }) if err != nil { return nil, xerrors.Errorf("provision: %w", err) @@ -533,6 +508,7 @@ func (p *provisionerDaemon) runWorkspaceProvision(ctx context.Context, provision stream, err := provisioner.Provision(ctx, &sdkproto.Provision_Request{ Directory: p.opts.WorkDirectory, ParameterValues: job.GetWorkspaceProvision().ParameterValues, + Metadata: job.GetWorkspaceProvision().Metadata, State: job.GetWorkspaceProvision().State, }) if err != nil { diff --git a/provisionerd/provisionerd_test.go b/provisionerd/provisionerd_test.go index 817ee460cdd11..3a53ad6d9ec96 100644 --- a/provisionerd/provisionerd_test.go +++ b/provisionerd/provisionerd_test.go @@ -21,7 +21,6 @@ import ( "cdr.dev/slog" "cdr.dev/slog/sloggers/slogtest" - "github.com/coder/coder/coderd/parameter" "github.com/coder/coder/provisionerd" "github.com/coder/coder/provisionerd/proto" "github.com/coder/coder/provisionersdk" @@ -97,7 +96,9 @@ func TestProvisionerd(t *testing.T) { "test.txt": "content", }), Type: &proto.AcquiredJob_ProjectImport_{ - ProjectImport: &proto.AcquiredJob_ProjectImport{}, + ProjectImport: &proto.AcquiredJob_ProjectImport{ + Metadata: &sdkproto.Provision_Metadata{}, + }, }, }, nil }, @@ -136,7 +137,9 @@ func TestProvisionerd(t *testing.T) { "../../../etc/passwd": "content", }), Type: &proto.AcquiredJob_ProjectImport_{ - ProjectImport: &proto.AcquiredJob_ProjectImport{}, + ProjectImport: &proto.AcquiredJob_ProjectImport{ + Metadata: &sdkproto.Provision_Metadata{}, + }, }, }, nil }, @@ -166,7 +169,9 @@ func TestProvisionerd(t *testing.T) { "test.txt": "content", }), Type: &proto.AcquiredJob_ProjectImport_{ - ProjectImport: &proto.AcquiredJob_ProjectImport{}, + ProjectImport: &proto.AcquiredJob_ProjectImport{ + Metadata: &sdkproto.Provision_Metadata{}, + }, }, }, nil }, @@ -214,7 +219,9 @@ func TestProvisionerd(t *testing.T) { "test.txt": "content", }), Type: &proto.AcquiredJob_ProjectImport_{ - ProjectImport: &proto.AcquiredJob_ProjectImport{}, + ProjectImport: &proto.AcquiredJob_ProjectImport{ + Metadata: &sdkproto.Provision_Metadata{}, + }, }, }, nil }, @@ -248,11 +255,7 @@ func TestProvisionerd(t *testing.T) { err = stream.Send(&sdkproto.Parse_Response{ Type: &sdkproto.Parse_Response_Complete{ - Complete: &sdkproto.Parse_Complete{ - ParameterSchemas: []*sdkproto.ParameterSchema{{ - Name: parameter.CoderWorkspaceTransition, - }}, - }, + Complete: &sdkproto.Parse_Complete{}, }, }) require.NoError(t, err) @@ -314,7 +317,9 @@ func TestProvisionerd(t *testing.T) { "test.txt": "content", }), Type: &proto.AcquiredJob_WorkspaceProvision_{ - WorkspaceProvision: &proto.AcquiredJob_WorkspaceProvision{}, + WorkspaceProvision: &proto.AcquiredJob_WorkspaceProvision{ + Metadata: &sdkproto.Provision_Metadata{}, + }, }, }, nil }, diff --git a/provisionersdk/proto/provisioner.pb.go b/provisionersdk/proto/provisioner.pb.go index f468713d2adde..43d2c0fe44af8 100644 --- a/provisionersdk/proto/provisioner.pb.go +++ b/provisionersdk/proto/provisioner.pb.go @@ -76,6 +76,52 @@ func (LogLevel) EnumDescriptor() ([]byte, []int) { return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{0} } +type WorkspaceTransition int32 + +const ( + WorkspaceTransition_START WorkspaceTransition = 0 + WorkspaceTransition_STOP WorkspaceTransition = 1 +) + +// Enum value maps for WorkspaceTransition. +var ( + WorkspaceTransition_name = map[int32]string{ + 0: "START", + 1: "STOP", + } + WorkspaceTransition_value = map[string]int32{ + "START": 0, + "STOP": 1, + } +) + +func (x WorkspaceTransition) Enum() *WorkspaceTransition { + p := new(WorkspaceTransition) + *p = x + return p +} + +func (x WorkspaceTransition) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (WorkspaceTransition) Descriptor() protoreflect.EnumDescriptor { + return file_provisionersdk_proto_provisioner_proto_enumTypes[1].Descriptor() +} + +func (WorkspaceTransition) Type() protoreflect.EnumType { + return &file_provisionersdk_proto_provisioner_proto_enumTypes[1] +} + +func (x WorkspaceTransition) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use WorkspaceTransition.Descriptor instead. +func (WorkspaceTransition) EnumDescriptor() ([]byte, []int) { + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{1} +} + type ParameterSource_Scheme int32 const ( @@ -103,11 +149,11 @@ func (x ParameterSource_Scheme) String() string { } func (ParameterSource_Scheme) Descriptor() protoreflect.EnumDescriptor { - return file_provisionersdk_proto_provisioner_proto_enumTypes[1].Descriptor() + return file_provisionersdk_proto_provisioner_proto_enumTypes[2].Descriptor() } func (ParameterSource_Scheme) Type() protoreflect.EnumType { - return &file_provisionersdk_proto_provisioner_proto_enumTypes[1] + return &file_provisionersdk_proto_provisioner_proto_enumTypes[2] } func (x ParameterSource_Scheme) Number() protoreflect.EnumNumber { @@ -149,11 +195,11 @@ func (x ParameterDestination_Scheme) String() string { } func (ParameterDestination_Scheme) Descriptor() protoreflect.EnumDescriptor { - return file_provisionersdk_proto_provisioner_proto_enumTypes[2].Descriptor() + return file_provisionersdk_proto_provisioner_proto_enumTypes[3].Descriptor() } func (ParameterDestination_Scheme) Type() protoreflect.EnumType { - return &file_provisionersdk_proto_provisioner_proto_enumTypes[2] + return &file_provisionersdk_proto_provisioner_proto_enumTypes[3] } func (x ParameterDestination_Scheme) Number() protoreflect.EnumNumber { @@ -195,11 +241,11 @@ func (x ParameterSchema_TypeSystem) String() string { } func (ParameterSchema_TypeSystem) Descriptor() protoreflect.EnumDescriptor { - return file_provisionersdk_proto_provisioner_proto_enumTypes[3].Descriptor() + return file_provisionersdk_proto_provisioner_proto_enumTypes[4].Descriptor() } func (ParameterSchema_TypeSystem) Type() protoreflect.EnumType { - return &file_provisionersdk_proto_provisioner_proto_enumTypes[3] + return &file_provisionersdk_proto_provisioner_proto_enumTypes[4] } func (x ParameterSchema_TypeSystem) Number() protoreflect.EnumNumber { @@ -1032,21 +1078,77 @@ func (*Parse_Response_Log) isParse_Response_Type() {} func (*Parse_Response_Complete) isParse_Response_Type() {} +type Provision_Metadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + CoderUrl string `protobuf:"bytes,1,opt,name=coder_url,json=coderUrl,proto3" json:"coder_url,omitempty"` + WorkspaceTransition WorkspaceTransition `protobuf:"varint,2,opt,name=workspace_transition,json=workspaceTransition,proto3,enum=provisioner.WorkspaceTransition" json:"workspace_transition,omitempty"` +} + +func (x *Provision_Metadata) Reset() { + *x = Provision_Metadata{} + if protoimpl.UnsafeEnabled { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[14] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Provision_Metadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Provision_Metadata) ProtoMessage() {} + +func (x *Provision_Metadata) ProtoReflect() protoreflect.Message { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[14] + 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 Provision_Metadata.ProtoReflect.Descriptor instead. +func (*Provision_Metadata) Descriptor() ([]byte, []int) { + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{9, 0} +} + +func (x *Provision_Metadata) GetCoderUrl() string { + if x != nil { + return x.CoderUrl + } + return "" +} + +func (x *Provision_Metadata) GetWorkspaceTransition() WorkspaceTransition { + if x != nil { + return x.WorkspaceTransition + } + return WorkspaceTransition_START +} + type Provision_Request struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Directory string `protobuf:"bytes,1,opt,name=directory,proto3" json:"directory,omitempty"` - ParameterValues []*ParameterValue `protobuf:"bytes,2,rep,name=parameter_values,json=parameterValues,proto3" json:"parameter_values,omitempty"` - State []byte `protobuf:"bytes,3,opt,name=state,proto3" json:"state,omitempty"` - DryRun bool `protobuf:"varint,4,opt,name=dry_run,json=dryRun,proto3" json:"dry_run,omitempty"` + Directory string `protobuf:"bytes,1,opt,name=directory,proto3" json:"directory,omitempty"` + ParameterValues []*ParameterValue `protobuf:"bytes,2,rep,name=parameter_values,json=parameterValues,proto3" json:"parameter_values,omitempty"` + Metadata *Provision_Metadata `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"` + State []byte `protobuf:"bytes,4,opt,name=state,proto3" json:"state,omitempty"` + DryRun bool `protobuf:"varint,5,opt,name=dry_run,json=dryRun,proto3" json:"dry_run,omitempty"` } func (x *Provision_Request) Reset() { *x = Provision_Request{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[14] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1059,7 +1161,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[14] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1072,7 +1174,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{9, 0} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{9, 1} } func (x *Provision_Request) GetDirectory() string { @@ -1089,6 +1191,13 @@ func (x *Provision_Request) GetParameterValues() []*ParameterValue { return nil } +func (x *Provision_Request) GetMetadata() *Provision_Metadata { + if x != nil { + return x.Metadata + } + return nil +} + func (x *Provision_Request) GetState() []byte { if x != nil { return x.State @@ -1115,7 +1224,7 @@ type Provision_Complete struct { func (x *Provision_Complete) Reset() { *x = Provision_Complete{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[15] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1128,7 +1237,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[15] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1141,7 +1250,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{9, 1} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{9, 2} } func (x *Provision_Complete) GetState() []byte { @@ -1172,7 +1281,7 @@ type Provision_Response struct { func (x *Provision_Response) Reset() { *x = Provision_Response{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[16] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1185,7 +1294,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[16] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1198,7 +1307,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{9, 2} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{9, 3} } func (m *Provision_Response) GetType() isProvision_Response_Type { @@ -1361,48 +1470,63 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 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, + 0x79, 0x70, 0x65, 0x22, 0xb7, 0x04, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x1a, 0x7c, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1b, 0x0a, + 0x09, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x08, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x53, 0x0a, 0x14, 0x77, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x1a, + 0xdb, 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, 0x3b, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 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, 0x4d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, + 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, + 0x74, 0x61, 0x74, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x72, 0x79, 0x5f, 0x72, 0x75, 0x6e, 0x18, + 0x05, 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, 0x2a, 0x2a, + 0x0a, 0x13, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, + 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x00, + 0x12, 0x08, 0x0a, 0x04, 0x53, 0x54, 0x4f, 0x50, 0x10, 0x01, 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 ( @@ -1417,58 +1541,62 @@ func file_provisionersdk_proto_provisioner_proto_rawDescGZIP() []byte { return file_provisionersdk_proto_provisioner_proto_rawDescData } -var file_provisionersdk_proto_provisioner_proto_enumTypes = make([]protoimpl.EnumInfo, 4) -var file_provisionersdk_proto_provisioner_proto_msgTypes = make([]protoimpl.MessageInfo, 17) +var file_provisionersdk_proto_provisioner_proto_enumTypes = make([]protoimpl.EnumInfo, 5) +var file_provisionersdk_proto_provisioner_proto_msgTypes = make([]protoimpl.MessageInfo, 18) 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 - (*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 + (WorkspaceTransition)(0), // 1: provisioner.WorkspaceTransition + (ParameterSource_Scheme)(0), // 2: provisioner.ParameterSource.Scheme + (ParameterDestination_Scheme)(0), // 3: provisioner.ParameterDestination.Scheme + (ParameterSchema_TypeSystem)(0), // 4: provisioner.ParameterSchema.TypeSystem + (*ParameterSource)(nil), // 5: provisioner.ParameterSource + (*ParameterDestination)(nil), // 6: provisioner.ParameterDestination + (*ParameterValue)(nil), // 7: provisioner.ParameterValue + (*ParameterSchema)(nil), // 8: provisioner.ParameterSchema + (*Log)(nil), // 9: provisioner.Log + (*GoogleInstanceIdentityAuth)(nil), // 10: provisioner.GoogleInstanceIdentityAuth + (*Agent)(nil), // 11: provisioner.Agent + (*Resource)(nil), // 12: provisioner.Resource + (*Parse)(nil), // 13: provisioner.Parse + (*Provision)(nil), // 14: provisioner.Provision + nil, // 15: provisioner.Agent.EnvEntry + (*Parse_Request)(nil), // 16: provisioner.Parse.Request + (*Parse_Complete)(nil), // 17: provisioner.Parse.Complete + (*Parse_Response)(nil), // 18: provisioner.Parse.Response + (*Provision_Metadata)(nil), // 19: provisioner.Provision.Metadata + (*Provision_Request)(nil), // 20: provisioner.Provision.Request + (*Provision_Complete)(nil), // 21: provisioner.Provision.Complete + (*Provision_Response)(nil), // 22: provisioner.Provision.Response } var file_provisionersdk_proto_provisioner_proto_depIdxs = []int32{ - 1, // 0: provisioner.ParameterSource.scheme:type_name -> provisioner.ParameterSource.Scheme - 2, // 1: provisioner.ParameterDestination.scheme:type_name -> provisioner.ParameterDestination.Scheme - 2, // 2: provisioner.ParameterValue.destination_scheme:type_name -> provisioner.ParameterDestination.Scheme - 4, // 3: provisioner.ParameterSchema.default_source:type_name -> provisioner.ParameterSource - 5, // 4: provisioner.ParameterSchema.default_destination:type_name -> provisioner.ParameterDestination - 3, // 5: provisioner.ParameterSchema.validation_type_system:type_name -> provisioner.ParameterSchema.TypeSystem + 2, // 0: provisioner.ParameterSource.scheme:type_name -> provisioner.ParameterSource.Scheme + 3, // 1: provisioner.ParameterDestination.scheme:type_name -> provisioner.ParameterDestination.Scheme + 3, // 2: provisioner.ParameterValue.destination_scheme:type_name -> provisioner.ParameterDestination.Scheme + 5, // 3: provisioner.ParameterSchema.default_source:type_name -> provisioner.ParameterSource + 6, // 4: provisioner.ParameterSchema.default_destination:type_name -> provisioner.ParameterDestination + 4, // 5: provisioner.ParameterSchema.validation_type_system:type_name -> provisioner.ParameterSchema.TypeSystem 0, // 6: provisioner.Log.level:type_name -> provisioner.LogLevel - 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 + 15, // 7: provisioner.Agent.env:type_name -> provisioner.Agent.EnvEntry + 10, // 8: provisioner.Agent.google_instance_identity:type_name -> provisioner.GoogleInstanceIdentityAuth + 11, // 9: provisioner.Resource.agent:type_name -> provisioner.Agent + 8, // 10: provisioner.Parse.Complete.parameter_schemas:type_name -> provisioner.ParameterSchema + 9, // 11: provisioner.Parse.Response.log:type_name -> provisioner.Log + 17, // 12: provisioner.Parse.Response.complete:type_name -> provisioner.Parse.Complete + 1, // 13: provisioner.Provision.Metadata.workspace_transition:type_name -> provisioner.WorkspaceTransition + 7, // 14: provisioner.Provision.Request.parameter_values:type_name -> provisioner.ParameterValue + 19, // 15: provisioner.Provision.Request.metadata:type_name -> provisioner.Provision.Metadata + 12, // 16: provisioner.Provision.Complete.resources:type_name -> provisioner.Resource + 9, // 17: provisioner.Provision.Response.log:type_name -> provisioner.Log + 21, // 18: provisioner.Provision.Response.complete:type_name -> provisioner.Provision.Complete + 16, // 19: provisioner.Provisioner.Parse:input_type -> provisioner.Parse.Request + 20, // 20: provisioner.Provisioner.Provision:input_type -> provisioner.Provision.Request + 18, // 21: provisioner.Provisioner.Parse:output_type -> provisioner.Parse.Response + 22, // 22: provisioner.Provisioner.Provision:output_type -> provisioner.Provision.Response + 21, // [21:23] is the sub-list for method output_type + 19, // [19:21] is the sub-list for method input_type + 19, // [19:19] is the sub-list for extension type_name + 19, // [19:19] is the sub-list for extension extendee + 0, // [0:19] is the sub-list for field type_name } func init() { file_provisionersdk_proto_provisioner_proto_init() } @@ -1634,7 +1762,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Provision_Request); i { + switch v := v.(*Provision_Metadata); i { case 0: return &v.state case 1: @@ -1646,7 +1774,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Provision_Complete); i { + switch v := v.(*Provision_Request); i { case 0: return &v.state case 1: @@ -1658,6 +1786,18 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Provision_Complete); 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[17].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Provision_Response); i { case 0: return &v.state @@ -1678,7 +1818,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { (*Parse_Response_Log)(nil), (*Parse_Response_Complete)(nil), } - file_provisionersdk_proto_provisioner_proto_msgTypes[16].OneofWrappers = []interface{}{ + file_provisionersdk_proto_provisioner_proto_msgTypes[17].OneofWrappers = []interface{}{ (*Provision_Response_Log)(nil), (*Provision_Response_Complete)(nil), } @@ -1687,8 +1827,8 @@ func file_provisionersdk_proto_provisioner_proto_init() { File: protoimpl.DescBuilder{ GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_provisionersdk_proto_provisioner_proto_rawDesc, - NumEnums: 4, - NumMessages: 17, + NumEnums: 5, + NumMessages: 18, NumExtensions: 0, NumServices: 1, }, diff --git a/provisionersdk/proto/provisioner.proto b/provisionersdk/proto/provisioner.proto index f77d147c0e291..d4ecb7893ea1d 100644 --- a/provisionersdk/proto/provisioner.proto +++ b/provisionersdk/proto/provisioner.proto @@ -103,13 +103,23 @@ message Parse { } } +enum WorkspaceTransition { + START = 0; + STOP = 1; +} + // Provision consumes source-code from a directory to produce resources. message Provision { + message Metadata { + string coder_url = 1; + WorkspaceTransition workspace_transition = 2; + } message Request { string directory = 1; repeated ParameterValue parameter_values = 2; - bytes state = 3; - bool dry_run = 4; + Metadata metadata = 3; + bytes state = 4; + bool dry_run = 5; } message Complete { bytes state = 1; From c55793c5768e4d2361d39dd2fe3cab4502be3ac1 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sun, 27 Feb 2022 20:42:54 +0000 Subject: [PATCH 13/21] feat: Add graceful exits to provisionerd Terraform (or other provisioners) may need to cleanup state, or cancel actions before exit. This adds the ability to gracefully exit provisionerd. --- coderd/provisionerdaemons.go | 31 +- coderd/provisionerjobs.go | 10 +- provisioner/echo/serve.go | 4 + provisioner/terraform/provision.go | 67 +- provisioner/terraform/serve.go | 18 +- provisionerd/proto/provisionerd.pb.go | 437 ++++++++++---- provisionerd/proto/provisionerd.proto | 16 +- provisionerd/proto/provisionerd_drpc.pb.go | 24 +- provisionerd/provisionerd.go | 186 ++++-- provisionerd/provisionerd_test.go | 148 ++++- provisionersdk/proto/provisioner.pb.go | 637 +++++++++++--------- provisionersdk/proto/provisioner.proto | 7 +- provisionersdk/proto/provisioner_drpc.pb.go | 44 +- 13 files changed, 1092 insertions(+), 537 deletions(-) diff --git a/coderd/provisionerdaemons.go b/coderd/provisionerdaemons.go index d630ddf56c670..da0419e7798b1 100644 --- a/coderd/provisionerdaemons.go +++ b/coderd/provisionerdaemons.go @@ -404,8 +404,8 @@ func (server *provisionerdServer) UpdateJob(ctx context.Context, request *proto. return &proto.UpdateJobResponse{}, nil } -func (server *provisionerdServer) CancelJob(ctx context.Context, cancelJob *proto.CancelledJob) (*proto.Empty, error) { - jobID, err := uuid.Parse(cancelJob.JobId) +func (server *provisionerdServer) FailJob(ctx context.Context, failJob *proto.FailedJob) (*proto.Empty, error) { + jobID, err := uuid.Parse(failJob.JobId) if err != nil { return nil, xerrors.Errorf("parse job id: %w", err) } @@ -422,19 +422,34 @@ func (server *provisionerdServer) CancelJob(ctx context.Context, cancelJob *prot Time: database.Now(), Valid: true, }, - CancelledAt: sql.NullTime{ - Time: database.Now(), - Valid: true, - }, UpdatedAt: database.Now(), Error: sql.NullString{ - String: cancelJob.Error, - Valid: cancelJob.Error != "", + String: failJob.Error, + Valid: failJob.Error != "", }, }) if err != nil { return nil, xerrors.Errorf("update provisioner job: %w", err) } + switch jobType := failJob.Type.(type) { + case *proto.FailedJob_WorkspaceProvision_: + if jobType.WorkspaceProvision.State == nil { + break + } + var input workspaceProvisionJob + err = json.Unmarshal(job.Input, &input) + if err != nil { + return nil, xerrors.Errorf("unmarshal workspace provision input: %w", err) + } + err = server.Database.UpdateWorkspaceHistoryByID(ctx, database.UpdateWorkspaceHistoryByIDParams{ + ID: jobID, + UpdatedAt: database.Now(), + ProvisionerState: jobType.WorkspaceProvision.State, + }) + if err != nil { + return nil, xerrors.Errorf("update workspace history state: %w", err) + } + } return &proto.Empty{}, nil } diff --git a/coderd/provisionerjobs.go b/coderd/provisionerjobs.go index aab66b55e4a2f..8c343256f15ee 100644 --- a/coderd/provisionerjobs.go +++ b/coderd/provisionerjobs.go @@ -276,7 +276,11 @@ func convertProvisionerJob(provisionerJob database.ProvisionerJob) ProvisionerJo case !provisionerJob.StartedAt.Valid: job.Status = ProvisionerJobStatusPending case provisionerJob.CompletedAt.Valid: - job.Status = ProvisionerJobStatusSucceeded + if job.Error == "" { + job.Status = ProvisionerJobStatusSucceeded + } else { + job.Status = ProvisionerJobStatusFailed + } case database.Now().Sub(provisionerJob.UpdatedAt) > 30*time.Second: job.Status = ProvisionerJobStatusFailed job.Error = "Worker failed to update job in time." @@ -284,10 +288,6 @@ func convertProvisionerJob(provisionerJob database.ProvisionerJob) ProvisionerJo job.Status = ProvisionerJobStatusRunning } - if !provisionerJob.CancelledAt.Valid && job.Error != "" { - job.Status = ProvisionerJobStatusFailed - } - return job } diff --git a/provisioner/echo/serve.go b/provisioner/echo/serve.go index a0bb57dad1e82..0d2ac2e65d8cd 100644 --- a/provisioner/echo/serve.go +++ b/provisioner/echo/serve.go @@ -102,6 +102,10 @@ func (*echo) Provision(request *proto.Provision_Request, stream proto.DRPCProvis return stream.Context().Err() } +func (*echo) Shutdown(_ context.Context, _ *proto.Empty) (*proto.Empty, error) { + return &proto.Empty{}, nil +} + type Responses struct { Parse []*proto.Parse_Response Provision []*proto.Provision_Response diff --git a/provisioner/terraform/provision.go b/provisioner/terraform/provision.go index 37617f32479d2..8537ed516d0af 100644 --- a/provisioner/terraform/provision.go +++ b/provisioner/terraform/provision.go @@ -7,6 +7,7 @@ import ( "fmt" "io" "os" + "os/exec" "path/filepath" "reflect" "strings" @@ -253,25 +254,21 @@ func (t *terraform) runTerraformPlan(ctx context.Context, terraform *tfexec.Terr } func (t *terraform) runTerraformApply(ctx context.Context, terraform *tfexec.Terraform, request *proto.Provision_Request, stream proto.DRPCProvisioner_ProvisionStream, statefilePath string) error { - env := map[string]string{ - "CODER_URL": request.Metadata.CoderUrl, - "CODER_WORKSPACE_TRANSITION": strings.ToLower(request.Metadata.WorkspaceTransition.String()), + env := []string{ + "CODER_URL=" + request.Metadata.CoderUrl, + "CODER_WORKSPACE_TRANSITION=" + strings.ToLower(request.Metadata.WorkspaceTransition.String()), } - options := []tfexec.ApplyOption{tfexec.JSON(true)} + vars := []string{} for _, param := range request.ParameterValues { switch param.DestinationScheme { case proto.ParameterDestination_ENVIRONMENT_VARIABLE: - env[param.Name] = param.Value + env = append(env, fmt.Sprintf("%s=%s", param.Name, param.Value)) case proto.ParameterDestination_PROVISIONER_VARIABLE: - options = append(options, tfexec.Var(fmt.Sprintf("%s=%s", param.Name, param.Value))) + vars = append(vars, fmt.Sprintf("%s=%s", param.Name, param.Value)) default: return xerrors.Errorf("unsupported parameter type %q for %q", param.DestinationScheme, param.Name) } } - err := terraform.SetEnv(env) - if err != nil { - return xerrors.Errorf("apply environment variables: %w", err) - } reader, writer := io.Pipe() defer reader.Close() @@ -319,11 +316,24 @@ func (t *terraform) runTerraformApply(ctx context.Context, terraform *tfexec.Ter } }() - terraform.SetStdout(writer) - t.logger.Debug(ctx, "running apply", slog.F("options", options)) - err = terraform.Apply(ctx, options...) + t.logger.Debug(ctx, "running apply", slog.F("vars", len(vars)), slog.F("env", len(env))) + err := runApplyCommand(ctx, t.shutdownCtx, terraform.ExecPath(), terraform.WorkingDir(), writer, env, vars) if err != nil { - return xerrors.Errorf("apply terraform: %w", err) + errorMessage := err.Error() + // Terraform can fail and apply and still need to store it's state. + // In this case, we return Complete with an explicit error message. + statefileContent, err := os.ReadFile(statefilePath) + if err != nil { + return xerrors.Errorf("read file %q: %w", statefilePath, err) + } + return stream.Send(&proto.Provision_Response{ + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{ + State: statefileContent, + Error: errorMessage, + }, + }, + }) } t.logger.Debug(ctx, "ran apply") @@ -428,6 +438,35 @@ func (t *terraform) runTerraformApply(ctx context.Context, terraform *tfexec.Ter }) } +// This couldn't use terraform-exec, because it doesn't support cancellation, and there didn't appear +// to be a straight-forward way to add it. +func runApplyCommand(ctx, shutdownCtx context.Context, bin, dir string, stdout io.Writer, env, vars []string) error { + args := []string{ + "apply", + "-no-color", + "-auto-approve", + "-input=false", + "-json", + "-refresh=true", + } + for _, variable := range vars { + args = append(args, "-var", variable) + } + cmd := exec.CommandContext(ctx, bin, args...) + go func() { + select { + case <-ctx.Done(): + return + case <-shutdownCtx.Done(): + _ = cmd.Process.Signal(os.Kill) + } + }() + cmd.Stdout = stdout + cmd.Env = env + cmd.Dir = dir + return cmd.Run() +} + type terraformProvisionLog struct { Level string `json:"@level"` Message string `json:"@message"` diff --git a/provisioner/terraform/serve.go b/provisioner/terraform/serve.go index 20b46bd3d625a..ae1b84eebae33 100644 --- a/provisioner/terraform/serve.go +++ b/provisioner/terraform/serve.go @@ -10,6 +10,7 @@ import ( "cdr.dev/slog" "github.com/coder/coder/provisionersdk" + "github.com/coder/coder/provisionersdk/proto" ) var ( @@ -43,14 +44,25 @@ func Serve(ctx context.Context, options *ServeOptions) error { } options.BinaryPath = binaryPath } - + shutdownCtx, shutdownCancel := context.WithCancel(ctx) return provisionersdk.Serve(ctx, &terraform{ - binaryPath: options.BinaryPath, - logger: options.Logger, + binaryPath: options.BinaryPath, + logger: options.Logger, + shutdownCtx: shutdownCtx, + shutdownCancel: shutdownCancel, }, options.ServeOptions) } type terraform struct { binaryPath string logger slog.Logger + + shutdownCtx context.Context + shutdownCancel context.CancelFunc +} + +// Shutdown signals to begin graceful shutdown of any running operations. +func (t *terraform) Shutdown(ctx context.Context, _ *proto.Empty) (*proto.Empty, error) { + t.shutdownCancel() + return &proto.Empty{}, nil } diff --git a/provisionerd/proto/provisionerd.pb.go b/provisionerd/proto/provisionerd.pb.go index c1292c4a0eb69..8954b6a5ae16a 100644 --- a/provisionerd/proto/provisionerd.pb.go +++ b/provisionerd/proto/provisionerd.pb.go @@ -228,17 +228,21 @@ func (*AcquiredJob_WorkspaceProvision_) isAcquiredJob_Type() {} func (*AcquiredJob_ProjectImport_) isAcquiredJob_Type() {} -type CancelledJob struct { +type FailedJob struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"` Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` + // Types that are assignable to Type: + // *FailedJob_WorkspaceProvision_ + // *FailedJob_ProjectImport_ + Type isFailedJob_Type `protobuf_oneof:"type"` } -func (x *CancelledJob) Reset() { - *x = CancelledJob{} +func (x *FailedJob) Reset() { + *x = FailedJob{} if protoimpl.UnsafeEnabled { mi := &file_provisionerd_proto_provisionerd_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -246,13 +250,13 @@ func (x *CancelledJob) Reset() { } } -func (x *CancelledJob) String() string { +func (x *FailedJob) String() string { return protoimpl.X.MessageStringOf(x) } -func (*CancelledJob) ProtoMessage() {} +func (*FailedJob) ProtoMessage() {} -func (x *CancelledJob) ProtoReflect() protoreflect.Message { +func (x *FailedJob) ProtoReflect() protoreflect.Message { mi := &file_provisionerd_proto_provisionerd_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -264,25 +268,62 @@ func (x *CancelledJob) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use CancelledJob.ProtoReflect.Descriptor instead. -func (*CancelledJob) Descriptor() ([]byte, []int) { +// Deprecated: Use FailedJob.ProtoReflect.Descriptor instead. +func (*FailedJob) Descriptor() ([]byte, []int) { return file_provisionerd_proto_provisionerd_proto_rawDescGZIP(), []int{2} } -func (x *CancelledJob) GetJobId() string { +func (x *FailedJob) GetJobId() string { if x != nil { return x.JobId } return "" } -func (x *CancelledJob) GetError() string { +func (x *FailedJob) GetError() string { if x != nil { return x.Error } return "" } +func (m *FailedJob) GetType() isFailedJob_Type { + if m != nil { + return m.Type + } + return nil +} + +func (x *FailedJob) GetWorkspaceProvision() *FailedJob_WorkspaceProvision { + if x, ok := x.GetType().(*FailedJob_WorkspaceProvision_); ok { + return x.WorkspaceProvision + } + return nil +} + +func (x *FailedJob) GetProjectImport() *FailedJob_ProjectImport { + if x, ok := x.GetType().(*FailedJob_ProjectImport_); ok { + return x.ProjectImport + } + return nil +} + +type isFailedJob_Type interface { + isFailedJob_Type() +} + +type FailedJob_WorkspaceProvision_ struct { + WorkspaceProvision *FailedJob_WorkspaceProvision `protobuf:"bytes,3,opt,name=workspace_provision,json=workspaceProvision,proto3,oneof"` +} + +type FailedJob_ProjectImport_ struct { + ProjectImport *FailedJob_ProjectImport `protobuf:"bytes,4,opt,name=project_import,json=projectImport,proto3,oneof"` +} + +func (*FailedJob_WorkspaceProvision_) isFailedJob_Type() {} + +func (*FailedJob_ProjectImport_) isFailedJob_Type() {} + // CompletedJob is sent when the provisioner daemon completes a job. type CompletedJob struct { state protoimpl.MessageState @@ -683,6 +724,91 @@ func (x *AcquiredJob_ProjectImport) GetMetadata() *proto.Provision_Metadata { return nil } +type FailedJob_WorkspaceProvision struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + State []byte `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"` +} + +func (x *FailedJob_WorkspaceProvision) Reset() { + *x = FailedJob_WorkspaceProvision{} + if protoimpl.UnsafeEnabled { + mi := &file_provisionerd_proto_provisionerd_proto_msgTypes[9] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FailedJob_WorkspaceProvision) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FailedJob_WorkspaceProvision) ProtoMessage() {} + +func (x *FailedJob_WorkspaceProvision) ProtoReflect() protoreflect.Message { + mi := &file_provisionerd_proto_provisionerd_proto_msgTypes[9] + 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 FailedJob_WorkspaceProvision.ProtoReflect.Descriptor instead. +func (*FailedJob_WorkspaceProvision) Descriptor() ([]byte, []int) { + return file_provisionerd_proto_provisionerd_proto_rawDescGZIP(), []int{2, 0} +} + +func (x *FailedJob_WorkspaceProvision) GetState() []byte { + if x != nil { + return x.State + } + return nil +} + +type FailedJob_ProjectImport struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *FailedJob_ProjectImport) Reset() { + *x = FailedJob_ProjectImport{} + if protoimpl.UnsafeEnabled { + mi := &file_provisionerd_proto_provisionerd_proto_msgTypes[10] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *FailedJob_ProjectImport) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*FailedJob_ProjectImport) ProtoMessage() {} + +func (x *FailedJob_ProjectImport) ProtoReflect() protoreflect.Message { + mi := &file_provisionerd_proto_provisionerd_proto_msgTypes[10] + 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 FailedJob_ProjectImport.ProtoReflect.Descriptor instead. +func (*FailedJob_ProjectImport) Descriptor() ([]byte, []int) { + return file_provisionerd_proto_provisionerd_proto_rawDescGZIP(), []int{2, 1} +} + type CompletedJob_WorkspaceProvision struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -695,7 +821,7 @@ type CompletedJob_WorkspaceProvision struct { func (x *CompletedJob_WorkspaceProvision) Reset() { *x = CompletedJob_WorkspaceProvision{} if protoimpl.UnsafeEnabled { - mi := &file_provisionerd_proto_provisionerd_proto_msgTypes[9] + mi := &file_provisionerd_proto_provisionerd_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -708,7 +834,7 @@ func (x *CompletedJob_WorkspaceProvision) String() string { func (*CompletedJob_WorkspaceProvision) ProtoMessage() {} func (x *CompletedJob_WorkspaceProvision) ProtoReflect() protoreflect.Message { - mi := &file_provisionerd_proto_provisionerd_proto_msgTypes[9] + mi := &file_provisionerd_proto_provisionerd_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -750,7 +876,7 @@ type CompletedJob_ProjectImport struct { func (x *CompletedJob_ProjectImport) Reset() { *x = CompletedJob_ProjectImport{} if protoimpl.UnsafeEnabled { - mi := &file_provisionerd_proto_provisionerd_proto_msgTypes[10] + mi := &file_provisionerd_proto_provisionerd_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -763,7 +889,7 @@ func (x *CompletedJob_ProjectImport) String() string { func (*CompletedJob_ProjectImport) ProtoMessage() {} func (x *CompletedJob_ProjectImport) ProtoReflect() protoreflect.Message { - mi := &file_provisionerd_proto_provisionerd_proto_msgTypes[10] + mi := &file_provisionerd_proto_provisionerd_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -847,90 +973,105 @@ var file_provisionerd_proto_provisionerd_proto_rawDesc = []byte{ 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, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x42, 0x06, 0x0a, - 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x3b, 0x0a, 0x0c, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, - 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, - 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, - 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x22, 0xd3, 0x03, 0x0a, 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, + 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xac, 0x02, 0x0a, 0x09, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x60, 0x0a, 0x13, 0x77, 0x6f, - 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, - 0x4a, 0x6f, 0x62, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x51, 0x0a, 0x0e, - 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, - 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, + 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, + 0x12, 0x5d, 0x0a, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2a, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x46, 0x61, 0x69, + 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x12, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, + 0x4e, 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x6d, 0x70, 0x6f, 0x72, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x25, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x48, 0x00, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x1a, - 0x5f, 0x0a, 0x12, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, + 0x2a, 0x0a, 0x12, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 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, 0x8d, 0x01, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x70, 0x6f, - 0x72, 0x74, 0x12, 0x3e, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x72, 0x65, 0x73, 0x6f, - 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 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, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x73, 0x12, 0x3c, 0x0a, 0x0e, 0x73, 0x74, 0x6f, 0x70, 0x5f, 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, 0x0d, 0x73, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, - 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x9a, 0x01, 0x0a, 0x03, 0x4c, 0x6f, 0x67, - 0x12, 0x2f, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, - 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, - 0x4c, 0x6f, 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x02, 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, 0x1d, - 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, 0x20, 0x01, - 0x28, 0x03, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, 0x16, 0x0a, - 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, - 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x9b, 0x01, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, - 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, - 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, - 0x64, 0x12, 0x25, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, - 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x4c, - 0x6f, 0x67, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x49, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x61, - 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, 0x03, 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, 0x22, 0x5b, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x10, 0x70, 0x61, 0x72, 0x61, - 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 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, - 0x2a, 0x34, 0x0a, 0x09, 0x4c, 0x6f, 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x16, 0x0a, - 0x12, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x45, 0x52, 0x5f, 0x44, 0x41, 0x45, - 0x4d, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, - 0x4f, 0x4e, 0x45, 0x52, 0x10, 0x01, 0x32, 0x9d, 0x02, 0x0a, 0x11, 0x50, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x0a, - 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x13, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, - 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x41, - 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x4c, 0x0a, 0x09, 0x55, 0x70, - 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, - 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, - 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x3c, 0x0a, 0x09, 0x43, 0x61, 0x6e, 0x63, - 0x65, 0x6c, 0x4a, 0x6f, 0x62, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x6c, 0x65, 0x64, 0x4a, 0x6f, - 0x62, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3e, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, - 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, 0x6f, - 0x62, 0x1a, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, - 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x2b, 0x5a, 0x29, 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, 0x64, 0x2f, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x1a, 0x0f, 0x0a, 0x0d, 0x50, + 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x42, 0x06, 0x0a, 0x04, + 0x74, 0x79, 0x70, 0x65, 0x22, 0xd3, 0x03, 0x0a, 0x0c, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, + 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x60, 0x0a, 0x13, + 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x2d, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, + 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, + 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x48, 0x00, 0x52, 0x12, 0x77, 0x6f, 0x72, 0x6b, + 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x51, + 0x0a, 0x0e, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x5f, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, + 0x6f, 0x62, 0x2e, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, + 0x48, 0x00, 0x52, 0x0d, 0x70, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6d, 0x70, 0x6f, 0x72, + 0x74, 0x1a, 0x5f, 0x0a, 0x12, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x50, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 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, 0x8d, 0x01, 0x0a, 0x0d, 0x50, 0x72, 0x6f, 0x6a, 0x65, 0x63, 0x74, 0x49, 0x6d, + 0x70, 0x6f, 0x72, 0x74, 0x12, 0x3e, 0x0a, 0x0f, 0x73, 0x74, 0x61, 0x72, 0x74, 0x5f, 0x72, 0x65, + 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x01, 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, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x52, 0x65, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x73, 0x12, 0x3c, 0x0a, 0x0e, 0x73, 0x74, 0x6f, 0x70, 0x5f, 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, 0x0d, 0x73, 0x74, 0x6f, 0x70, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x73, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x9a, 0x01, 0x0a, 0x03, 0x4c, + 0x6f, 0x67, 0x12, 0x2f, 0x0a, 0x06, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x01, 0x20, 0x01, + 0x28, 0x0e, 0x32, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x64, 0x2e, 0x4c, 0x6f, 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x06, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x12, 0x2b, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x02, 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, 0x1d, 0x0a, 0x0a, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x5f, 0x61, 0x74, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x09, 0x63, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x41, 0x74, 0x12, + 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x9b, 0x01, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, + 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, + 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, + 0x62, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, + 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x49, 0x0a, 0x11, 0x70, 0x61, + 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, + 0x03, 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, 0x22, 0x5b, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, + 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x46, 0x0a, 0x10, 0x70, 0x61, + 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, + 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, 0x2a, 0x34, 0x0a, 0x09, 0x4c, 0x6f, 0x67, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, + 0x16, 0x0a, 0x12, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x45, 0x52, 0x5f, 0x44, + 0x41, 0x45, 0x4d, 0x4f, 0x4e, 0x10, 0x00, 0x12, 0x0f, 0x0a, 0x0b, 0x50, 0x52, 0x4f, 0x56, 0x49, + 0x53, 0x49, 0x4f, 0x4e, 0x45, 0x52, 0x10, 0x01, 0x32, 0x98, 0x02, 0x0a, 0x11, 0x50, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x44, 0x61, 0x65, 0x6d, 0x6f, 0x6e, 0x12, 0x3c, + 0x0a, 0x0a, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x13, 0x2e, 0x70, + 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, 0x70, 0x74, + 0x79, 0x1a, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, + 0x2e, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x12, 0x4c, 0x0a, 0x09, + 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x12, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, + 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, + 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x37, 0x0a, 0x07, 0x46, 0x61, + 0x69, 0x6c, 0x4a, 0x6f, 0x62, 0x12, 0x17, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x1a, 0x13, + 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x12, 0x3e, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x4a, + 0x6f, 0x62, 0x12, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x1a, 0x13, + 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x45, 0x6d, + 0x70, 0x74, 0x79, 0x42, 0x2b, 0x5a, 0x29, 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, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -946,55 +1087,59 @@ func file_provisionerd_proto_provisionerd_proto_rawDescGZIP() []byte { } var file_provisionerd_proto_provisionerd_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_provisionerd_proto_provisionerd_proto_msgTypes = make([]protoimpl.MessageInfo, 11) +var file_provisionerd_proto_provisionerd_proto_msgTypes = make([]protoimpl.MessageInfo, 13) var file_provisionerd_proto_provisionerd_proto_goTypes = []interface{}{ (LogSource)(0), // 0: provisionerd.LogSource (*Empty)(nil), // 1: provisionerd.Empty (*AcquiredJob)(nil), // 2: provisionerd.AcquiredJob - (*CancelledJob)(nil), // 3: provisionerd.CancelledJob + (*FailedJob)(nil), // 3: provisionerd.FailedJob (*CompletedJob)(nil), // 4: provisionerd.CompletedJob (*Log)(nil), // 5: provisionerd.Log (*UpdateJobRequest)(nil), // 6: provisionerd.UpdateJobRequest (*UpdateJobResponse)(nil), // 7: provisionerd.UpdateJobResponse (*AcquiredJob_WorkspaceProvision)(nil), // 8: provisionerd.AcquiredJob.WorkspaceProvision (*AcquiredJob_ProjectImport)(nil), // 9: provisionerd.AcquiredJob.ProjectImport - (*CompletedJob_WorkspaceProvision)(nil), // 10: provisionerd.CompletedJob.WorkspaceProvision - (*CompletedJob_ProjectImport)(nil), // 11: provisionerd.CompletedJob.ProjectImport - (proto.LogLevel)(0), // 12: provisioner.LogLevel - (*proto.ParameterSchema)(nil), // 13: provisioner.ParameterSchema - (*proto.ParameterValue)(nil), // 14: provisioner.ParameterValue - (*proto.Provision_Metadata)(nil), // 15: provisioner.Provision.Metadata - (*proto.Resource)(nil), // 16: provisioner.Resource + (*FailedJob_WorkspaceProvision)(nil), // 10: provisionerd.FailedJob.WorkspaceProvision + (*FailedJob_ProjectImport)(nil), // 11: provisionerd.FailedJob.ProjectImport + (*CompletedJob_WorkspaceProvision)(nil), // 12: provisionerd.CompletedJob.WorkspaceProvision + (*CompletedJob_ProjectImport)(nil), // 13: provisionerd.CompletedJob.ProjectImport + (proto.LogLevel)(0), // 14: provisioner.LogLevel + (*proto.ParameterSchema)(nil), // 15: provisioner.ParameterSchema + (*proto.ParameterValue)(nil), // 16: provisioner.ParameterValue + (*proto.Provision_Metadata)(nil), // 17: provisioner.Provision.Metadata + (*proto.Resource)(nil), // 18: provisioner.Resource } var file_provisionerd_proto_provisionerd_proto_depIdxs = []int32{ 8, // 0: provisionerd.AcquiredJob.workspace_provision:type_name -> provisionerd.AcquiredJob.WorkspaceProvision 9, // 1: provisionerd.AcquiredJob.project_import:type_name -> provisionerd.AcquiredJob.ProjectImport - 10, // 2: provisionerd.CompletedJob.workspace_provision:type_name -> provisionerd.CompletedJob.WorkspaceProvision - 11, // 3: provisionerd.CompletedJob.project_import:type_name -> provisionerd.CompletedJob.ProjectImport - 0, // 4: provisionerd.Log.source:type_name -> provisionerd.LogSource - 12, // 5: provisionerd.Log.level:type_name -> provisioner.LogLevel - 5, // 6: provisionerd.UpdateJobRequest.logs:type_name -> provisionerd.Log - 13, // 7: provisionerd.UpdateJobRequest.parameter_schemas:type_name -> provisioner.ParameterSchema - 14, // 8: provisionerd.UpdateJobResponse.parameter_values:type_name -> provisioner.ParameterValue - 14, // 9: provisionerd.AcquiredJob.WorkspaceProvision.parameter_values:type_name -> provisioner.ParameterValue - 15, // 10: provisionerd.AcquiredJob.WorkspaceProvision.metadata:type_name -> provisioner.Provision.Metadata - 15, // 11: provisionerd.AcquiredJob.ProjectImport.metadata:type_name -> provisioner.Provision.Metadata - 16, // 12: provisionerd.CompletedJob.WorkspaceProvision.resources:type_name -> provisioner.Resource - 16, // 13: provisionerd.CompletedJob.ProjectImport.start_resources:type_name -> provisioner.Resource - 16, // 14: provisionerd.CompletedJob.ProjectImport.stop_resources:type_name -> provisioner.Resource - 1, // 15: provisionerd.ProvisionerDaemon.AcquireJob:input_type -> provisionerd.Empty - 6, // 16: provisionerd.ProvisionerDaemon.UpdateJob:input_type -> provisionerd.UpdateJobRequest - 3, // 17: provisionerd.ProvisionerDaemon.CancelJob:input_type -> provisionerd.CancelledJob - 4, // 18: provisionerd.ProvisionerDaemon.CompleteJob:input_type -> provisionerd.CompletedJob - 2, // 19: provisionerd.ProvisionerDaemon.AcquireJob:output_type -> provisionerd.AcquiredJob - 7, // 20: provisionerd.ProvisionerDaemon.UpdateJob:output_type -> provisionerd.UpdateJobResponse - 1, // 21: provisionerd.ProvisionerDaemon.CancelJob:output_type -> provisionerd.Empty - 1, // 22: provisionerd.ProvisionerDaemon.CompleteJob:output_type -> provisionerd.Empty - 19, // [19:23] is the sub-list for method output_type - 15, // [15:19] is the sub-list for method input_type - 15, // [15:15] is the sub-list for extension type_name - 15, // [15:15] is the sub-list for extension extendee - 0, // [0:15] is the sub-list for field type_name + 10, // 2: provisionerd.FailedJob.workspace_provision:type_name -> provisionerd.FailedJob.WorkspaceProvision + 11, // 3: provisionerd.FailedJob.project_import:type_name -> provisionerd.FailedJob.ProjectImport + 12, // 4: provisionerd.CompletedJob.workspace_provision:type_name -> provisionerd.CompletedJob.WorkspaceProvision + 13, // 5: provisionerd.CompletedJob.project_import:type_name -> provisionerd.CompletedJob.ProjectImport + 0, // 6: provisionerd.Log.source:type_name -> provisionerd.LogSource + 14, // 7: provisionerd.Log.level:type_name -> provisioner.LogLevel + 5, // 8: provisionerd.UpdateJobRequest.logs:type_name -> provisionerd.Log + 15, // 9: provisionerd.UpdateJobRequest.parameter_schemas:type_name -> provisioner.ParameterSchema + 16, // 10: provisionerd.UpdateJobResponse.parameter_values:type_name -> provisioner.ParameterValue + 16, // 11: provisionerd.AcquiredJob.WorkspaceProvision.parameter_values:type_name -> provisioner.ParameterValue + 17, // 12: provisionerd.AcquiredJob.WorkspaceProvision.metadata:type_name -> provisioner.Provision.Metadata + 17, // 13: provisionerd.AcquiredJob.ProjectImport.metadata:type_name -> provisioner.Provision.Metadata + 18, // 14: provisionerd.CompletedJob.WorkspaceProvision.resources:type_name -> provisioner.Resource + 18, // 15: provisionerd.CompletedJob.ProjectImport.start_resources:type_name -> provisioner.Resource + 18, // 16: provisionerd.CompletedJob.ProjectImport.stop_resources:type_name -> provisioner.Resource + 1, // 17: provisionerd.ProvisionerDaemon.AcquireJob:input_type -> provisionerd.Empty + 6, // 18: provisionerd.ProvisionerDaemon.UpdateJob:input_type -> provisionerd.UpdateJobRequest + 3, // 19: provisionerd.ProvisionerDaemon.FailJob:input_type -> provisionerd.FailedJob + 4, // 20: provisionerd.ProvisionerDaemon.CompleteJob:input_type -> provisionerd.CompletedJob + 2, // 21: provisionerd.ProvisionerDaemon.AcquireJob:output_type -> provisionerd.AcquiredJob + 7, // 22: provisionerd.ProvisionerDaemon.UpdateJob:output_type -> provisionerd.UpdateJobResponse + 1, // 23: provisionerd.ProvisionerDaemon.FailJob:output_type -> provisionerd.Empty + 1, // 24: provisionerd.ProvisionerDaemon.CompleteJob:output_type -> provisionerd.Empty + 21, // [21:25] is the sub-list for method output_type + 17, // [17:21] 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_provisionerd_proto_provisionerd_proto_init() } @@ -1028,7 +1173,7 @@ func file_provisionerd_proto_provisionerd_proto_init() { } } file_provisionerd_proto_provisionerd_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CancelledJob); i { + switch v := v.(*FailedJob); i { case 0: return &v.state case 1: @@ -1112,7 +1257,7 @@ func file_provisionerd_proto_provisionerd_proto_init() { } } file_provisionerd_proto_provisionerd_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*CompletedJob_WorkspaceProvision); i { + switch v := v.(*FailedJob_WorkspaceProvision); i { case 0: return &v.state case 1: @@ -1124,6 +1269,30 @@ func file_provisionerd_proto_provisionerd_proto_init() { } } file_provisionerd_proto_provisionerd_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*FailedJob_ProjectImport); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_provisionerd_proto_provisionerd_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*CompletedJob_WorkspaceProvision); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_provisionerd_proto_provisionerd_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*CompletedJob_ProjectImport); i { case 0: return &v.state @@ -1140,6 +1309,10 @@ func file_provisionerd_proto_provisionerd_proto_init() { (*AcquiredJob_WorkspaceProvision_)(nil), (*AcquiredJob_ProjectImport_)(nil), } + file_provisionerd_proto_provisionerd_proto_msgTypes[2].OneofWrappers = []interface{}{ + (*FailedJob_WorkspaceProvision_)(nil), + (*FailedJob_ProjectImport_)(nil), + } file_provisionerd_proto_provisionerd_proto_msgTypes[3].OneofWrappers = []interface{}{ (*CompletedJob_WorkspaceProvision_)(nil), (*CompletedJob_ProjectImport_)(nil), @@ -1150,7 +1323,7 @@ func file_provisionerd_proto_provisionerd_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_provisionerd_proto_provisionerd_proto_rawDesc, NumEnums: 1, - NumMessages: 11, + NumMessages: 13, NumExtensions: 0, NumServices: 1, }, diff --git a/provisionerd/proto/provisionerd.proto b/provisionerd/proto/provisionerd.proto index 17bd5ffe01a1c..55c546ef7676b 100644 --- a/provisionerd/proto/provisionerd.proto +++ b/provisionerd/proto/provisionerd.proto @@ -32,9 +32,18 @@ message AcquiredJob { } } -message CancelledJob { +message FailedJob { + message WorkspaceProvision { + bytes state = 1; + } + message ProjectImport{ + } string job_id = 1; string error = 2; + oneof type { + WorkspaceProvision workspace_provision = 3; + ProjectImport project_import = 4; + } } // CompletedJob is sent when the provisioner daemon completes a job. @@ -92,9 +101,8 @@ service ProvisionerDaemon { // is non-blocking. rpc UpdateJob(UpdateJobRequest) returns (UpdateJobResponse); - // CancelJob indicates a job has been cancelled with - // an error message. - rpc CancelJob(CancelledJob) returns (Empty); + // FailJob indicates a job has failed. + rpc FailJob(FailedJob) returns (Empty); // CompleteJob indicates a job has been completed. rpc CompleteJob(CompletedJob) returns (Empty); diff --git a/provisionerd/proto/provisionerd_drpc.pb.go b/provisionerd/proto/provisionerd_drpc.pb.go index 6e5a116239df3..646f855eabc70 100644 --- a/provisionerd/proto/provisionerd_drpc.pb.go +++ b/provisionerd/proto/provisionerd_drpc.pb.go @@ -40,7 +40,7 @@ type DRPCProvisionerDaemonClient interface { AcquireJob(ctx context.Context, in *Empty) (*AcquiredJob, error) UpdateJob(ctx context.Context, in *UpdateJobRequest) (*UpdateJobResponse, error) - CancelJob(ctx context.Context, in *CancelledJob) (*Empty, error) + FailJob(ctx context.Context, in *FailedJob) (*Empty, error) CompleteJob(ctx context.Context, in *CompletedJob) (*Empty, error) } @@ -72,9 +72,9 @@ func (c *drpcProvisionerDaemonClient) UpdateJob(ctx context.Context, in *UpdateJ return out, nil } -func (c *drpcProvisionerDaemonClient) CancelJob(ctx context.Context, in *CancelledJob) (*Empty, error) { +func (c *drpcProvisionerDaemonClient) FailJob(ctx context.Context, in *FailedJob) (*Empty, error) { out := new(Empty) - err := c.cc.Invoke(ctx, "/provisionerd.ProvisionerDaemon/CancelJob", drpcEncoding_File_provisionerd_proto_provisionerd_proto{}, in, out) + err := c.cc.Invoke(ctx, "/provisionerd.ProvisionerDaemon/FailJob", drpcEncoding_File_provisionerd_proto_provisionerd_proto{}, in, out) if err != nil { return nil, err } @@ -93,7 +93,7 @@ func (c *drpcProvisionerDaemonClient) CompleteJob(ctx context.Context, in *Compl type DRPCProvisionerDaemonServer interface { AcquireJob(context.Context, *Empty) (*AcquiredJob, error) UpdateJob(context.Context, *UpdateJobRequest) (*UpdateJobResponse, error) - CancelJob(context.Context, *CancelledJob) (*Empty, error) + FailJob(context.Context, *FailedJob) (*Empty, error) CompleteJob(context.Context, *CompletedJob) (*Empty, error) } @@ -107,7 +107,7 @@ func (s *DRPCProvisionerDaemonUnimplementedServer) UpdateJob(context.Context, *U return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) } -func (s *DRPCProvisionerDaemonUnimplementedServer) CancelJob(context.Context, *CancelledJob) (*Empty, error) { +func (s *DRPCProvisionerDaemonUnimplementedServer) FailJob(context.Context, *FailedJob) (*Empty, error) { return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) } @@ -140,14 +140,14 @@ func (DRPCProvisionerDaemonDescription) Method(n int) (string, drpc.Encoding, dr ) }, DRPCProvisionerDaemonServer.UpdateJob, true case 2: - return "/provisionerd.ProvisionerDaemon/CancelJob", drpcEncoding_File_provisionerd_proto_provisionerd_proto{}, + return "/provisionerd.ProvisionerDaemon/FailJob", drpcEncoding_File_provisionerd_proto_provisionerd_proto{}, func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { return srv.(DRPCProvisionerDaemonServer). - CancelJob( + FailJob( ctx, - in1.(*CancelledJob), + in1.(*FailedJob), ) - }, DRPCProvisionerDaemonServer.CancelJob, true + }, DRPCProvisionerDaemonServer.FailJob, true case 3: return "/provisionerd.ProvisionerDaemon/CompleteJob", drpcEncoding_File_provisionerd_proto_provisionerd_proto{}, func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { @@ -198,16 +198,16 @@ func (x *drpcProvisionerDaemon_UpdateJobStream) SendAndClose(m *UpdateJobRespons return x.CloseSend() } -type DRPCProvisionerDaemon_CancelJobStream interface { +type DRPCProvisionerDaemon_FailJobStream interface { drpc.Stream SendAndClose(*Empty) error } -type drpcProvisionerDaemon_CancelJobStream struct { +type drpcProvisionerDaemon_FailJobStream struct { drpc.Stream } -func (x *drpcProvisionerDaemon_CancelJobStream) SendAndClose(m *Empty) error { +func (x *drpcProvisionerDaemon_FailJobStream) SendAndClose(m *Empty) error { if err := x.MsgSend(m, drpcEncoding_File_provisionerd_proto_provisionerd_proto{}); err != nil { return err } diff --git a/provisionerd/provisionerd.go b/provisionerd/provisionerd.go index dc84207ec3048..e7f2bd691a694 100644 --- a/provisionerd/provisionerd.go +++ b/provisionerd/provisionerd.go @@ -52,7 +52,7 @@ type Options struct { } // New creates and starts a provisioner daemon. -func New(clientDialer Dialer, opts *Options) io.Closer { +func New(clientDialer Dialer, opts *Options) *Server { if opts.PollInterval == 0 { opts.PollInterval = 5 * time.Second } @@ -60,15 +60,17 @@ func New(clientDialer Dialer, opts *Options) io.Closer { opts.UpdateInterval = 5 * time.Second } ctx, ctxCancel := context.WithCancel(context.Background()) - daemon := &provisionerDaemon{ + daemon := &Server{ clientDialer: clientDialer, opts: opts, closeCancel: ctxCancel, closed: make(chan struct{}), - jobRunning: make(chan struct{}), - jobCancelled: *atomic.NewBool(true), + shutdown: make(chan struct{}), + + jobRunning: make(chan struct{}), + jobFailed: *atomic.NewBool(true), } // Start off with a closed channel so // isRunningJob() returns properly. @@ -77,7 +79,7 @@ func New(clientDialer Dialer, opts *Options) io.Closer { return daemon } -type provisionerDaemon struct { +type Server struct { opts *Options clientDialer Dialer @@ -89,16 +91,19 @@ type provisionerDaemon struct { closed chan struct{} closeError error - // Locked when acquiring or canceling a job. - jobMutex sync.Mutex - jobID string - jobRunning chan struct{} - jobCancelled atomic.Bool - jobCancel context.CancelFunc + shutdownMutex sync.Mutex + shutdown chan struct{} + + // Locked when acquiring or failing a job. + jobMutex sync.Mutex + jobID string + jobRunning chan struct{} + jobFailed atomic.Bool + jobCancel context.CancelFunc } // Connect establishes a connection to coderd. -func (p *provisionerDaemon) connect(ctx context.Context) { +func (p *Server) connect(ctx context.Context) { var err error // An exponential back-off occurs when the connection is failing to dial. // This is to prevent server spam in case of a coderd outage. @@ -161,7 +166,7 @@ func (p *provisionerDaemon) connect(ctx context.Context) { }() } -func (p *provisionerDaemon) isRunningJob() bool { +func (p *Server) isRunningJob() bool { select { case <-p.jobRunning: return false @@ -171,7 +176,7 @@ func (p *provisionerDaemon) isRunningJob() bool { } // Locks a job in the database, and runs it! -func (p *provisionerDaemon) acquireJob(ctx context.Context) { +func (p *Server) acquireJob(ctx context.Context) { p.jobMutex.Lock() defer p.jobMutex.Unlock() if p.isClosed() { @@ -181,6 +186,10 @@ func (p *provisionerDaemon) acquireJob(ctx context.Context) { p.opts.Logger.Debug(context.Background(), "skipping acquire; job is already running") return } + if p.isShutdown() { + p.opts.Logger.Debug(context.Background(), "skipping acquire; provisionerd is shutting down...") + return + } var err error job, err := p.client.AcquireJob(ctx, &proto.Empty{}) if err != nil { @@ -199,7 +208,7 @@ func (p *provisionerDaemon) acquireJob(ctx context.Context) { } ctx, p.jobCancel = context.WithCancel(ctx) p.jobRunning = make(chan struct{}) - p.jobCancelled.Store(false) + p.jobFailed.Store(false) p.jobID = job.JobId p.opts.Logger.Info(context.Background(), "acquired job", @@ -211,7 +220,7 @@ func (p *provisionerDaemon) acquireJob(ctx context.Context) { go p.runJob(ctx, job) } -func (p *provisionerDaemon) runJob(ctx context.Context, job *proto.AcquiredJob) { +func (p *Server) runJob(ctx context.Context, job *proto.AcquiredJob) { go func() { ticker := time.NewTicker(p.opts.UpdateInterval) defer ticker.Stop() @@ -225,7 +234,7 @@ func (p *provisionerDaemon) runJob(ctx context.Context, job *proto.AcquiredJob) JobId: job.JobId, }) if err != nil { - p.cancelActiveJobf("send periodic update: %s", err) + p.failActiveJobf("send periodic update: %s", err) return } } @@ -252,13 +261,13 @@ func (p *provisionerDaemon) runJob(ctx context.Context, job *proto.AcquiredJob) // It's safe to cast this ProvisionerType. This data is coming directly from coderd. provisioner, hasProvisioner := p.opts.Provisioners[job.Provisioner] if !hasProvisioner { - p.cancelActiveJobf("provisioner %q not registered", job.Provisioner) + p.failActiveJobf("provisioner %q not registered", job.Provisioner) return } err := os.MkdirAll(p.opts.WorkDirectory, 0700) if err != nil { - p.cancelActiveJobf("create work directory %q: %s", p.opts.WorkDirectory, err) + p.failActiveJobf("create work directory %q: %s", p.opts.WorkDirectory, err) return } @@ -270,13 +279,13 @@ func (p *provisionerDaemon) runJob(ctx context.Context, job *proto.AcquiredJob) break } if err != nil { - p.cancelActiveJobf("read project source archive: %s", err) + p.failActiveJobf("read project source archive: %s", err) return } // #nosec path := filepath.Join(p.opts.WorkDirectory, header.Name) if !strings.HasPrefix(path, filepath.Clean(p.opts.WorkDirectory)) { - p.cancelActiveJobf("tar attempts to target relative upper directory") + p.failActiveJobf("tar attempts to target relative upper directory") return } mode := header.FileInfo().Mode() @@ -287,14 +296,14 @@ func (p *provisionerDaemon) runJob(ctx context.Context, job *proto.AcquiredJob) case tar.TypeDir: err = os.MkdirAll(path, mode) if err != nil { - p.cancelActiveJobf("mkdir %q: %s", path, err) + p.failActiveJobf("mkdir %q: %s", path, err) return } p.opts.Logger.Debug(context.Background(), "extracted directory", slog.F("path", path)) case tar.TypeReg: file, err := os.OpenFile(path, os.O_CREATE|os.O_RDWR, mode) if err != nil { - p.cancelActiveJobf("create file %q (mode %s): %s", path, mode, err) + p.failActiveJobf("create file %q (mode %s): %s", path, mode, err) return } // Max file size of 10MB. @@ -304,12 +313,12 @@ func (p *provisionerDaemon) runJob(ctx context.Context, job *proto.AcquiredJob) } if err != nil { _ = file.Close() - p.cancelActiveJobf("copy file %q: %s", path, err) + p.failActiveJobf("copy file %q: %s", path, err) return } err = file.Close() if err != nil { - p.cancelActiveJobf("close file %q: %s", path, err) + p.failActiveJobf("close file %q: %s", path, err) return } p.opts.Logger.Debug(context.Background(), "extracted file", @@ -334,21 +343,21 @@ func (p *provisionerDaemon) runJob(ctx context.Context, job *proto.AcquiredJob) p.runWorkspaceProvision(ctx, provisioner, job) default: - p.cancelActiveJobf("unknown job type %q; ensure your provisioner daemon is up-to-date", reflect.TypeOf(job.Type).String()) + p.failActiveJobf("unknown job type %q; ensure your provisioner daemon is up-to-date", reflect.TypeOf(job.Type).String()) return } // Ensure the job is still running to output. - // It's possible the job was canceled. + // It's possible the job has failed. if p.isRunningJob() { p.opts.Logger.Info(context.Background(), "completed job", slog.F("id", job.JobId)) } } -func (p *provisionerDaemon) runProjectImport(ctx context.Context, provisioner sdkproto.DRPCProvisionerClient, job *proto.AcquiredJob) { +func (p *Server) runProjectImport(ctx context.Context, provisioner sdkproto.DRPCProvisionerClient, job *proto.AcquiredJob) { parameterSchemas, err := p.runProjectImportParse(ctx, provisioner, job) if err != nil { - p.cancelActiveJobf("run parse: %s", err) + p.failActiveJobf("run parse: %s", err) return } @@ -357,7 +366,7 @@ func (p *provisionerDaemon) runProjectImport(ctx context.Context, provisioner sd ParameterSchemas: parameterSchemas, }) if err != nil { - p.cancelActiveJobf("update job: %s", err) + p.failActiveJobf("update job: %s", err) return } @@ -368,7 +377,7 @@ func (p *provisionerDaemon) runProjectImport(ctx context.Context, provisioner sd for _, parameterSchema := range parameterSchemas { _, ok := valueByName[parameterSchema.Name] if !ok { - p.cancelActiveJobf("%s: %s", missingParameterErrorText, parameterSchema.Name) + p.failActiveJobf("%s: %s", missingParameterErrorText, parameterSchema.Name) return } } @@ -378,7 +387,7 @@ func (p *provisionerDaemon) runProjectImport(ctx context.Context, provisioner sd WorkspaceTransition: sdkproto.WorkspaceTransition_START, }) if err != nil { - p.cancelActiveJobf("project import provision for start: %s", err) + p.failActiveJobf("project import provision for start: %s", err) return } stopResources, err := p.runProjectImportProvision(ctx, provisioner, job, updateResponse.ParameterValues, &sdkproto.Provision_Metadata{ @@ -386,7 +395,7 @@ func (p *provisionerDaemon) runProjectImport(ctx context.Context, provisioner sd WorkspaceTransition: sdkproto.WorkspaceTransition_STOP, }) if err != nil { - p.cancelActiveJobf("project import provision for start: %s", err) + p.failActiveJobf("project import provision for start: %s", err) return } @@ -400,13 +409,13 @@ func (p *provisionerDaemon) runProjectImport(ctx context.Context, provisioner sd }, }) if err != nil { - p.cancelActiveJobf("complete job: %s", err) + p.failActiveJobf("complete job: %s", err) return } } // Parses parameter schemas from source. -func (p *provisionerDaemon) runProjectImportParse(ctx context.Context, provisioner sdkproto.DRPCProvisionerClient, job *proto.AcquiredJob) ([]*sdkproto.ParameterSchema, error) { +func (p *Server) runProjectImportParse(ctx context.Context, provisioner sdkproto.DRPCProvisionerClient, job *proto.AcquiredJob) ([]*sdkproto.ParameterSchema, error) { stream, err := provisioner.Parse(ctx, &sdkproto.Parse_Request{ Directory: p.opts.WorkDirectory, }) @@ -453,7 +462,7 @@ func (p *provisionerDaemon) runProjectImportParse(ctx context.Context, provision // Performs a dry-run provision when importing a project. // This is used to detect resources that would be provisioned // for a workspace in various states. -func (p *provisionerDaemon) runProjectImportProvision(ctx context.Context, provisioner sdkproto.DRPCProvisionerClient, job *proto.AcquiredJob, values []*sdkproto.ParameterValue, metadata *sdkproto.Provision_Metadata) ([]*sdkproto.Resource, error) { +func (p *Server) runProjectImportProvision(ctx context.Context, provisioner sdkproto.DRPCProvisionerClient, job *proto.AcquiredJob, values []*sdkproto.ParameterValue, metadata *sdkproto.Provision_Metadata) ([]*sdkproto.Resource, error) { stream, err := provisioner.Provision(ctx, &sdkproto.Provision_Request{ Directory: p.opts.WorkDirectory, ParameterValues: values, @@ -504,7 +513,7 @@ func (p *provisionerDaemon) runProjectImportProvision(ctx context.Context, provi } } -func (p *provisionerDaemon) runWorkspaceProvision(ctx context.Context, provisioner sdkproto.DRPCProvisionerClient, job *proto.AcquiredJob) { +func (p *Server) runWorkspaceProvision(ctx context.Context, provisioner sdkproto.DRPCProvisionerClient, job *proto.AcquiredJob) { stream, err := provisioner.Provision(ctx, &sdkproto.Provision_Request{ Directory: p.opts.WorkDirectory, ParameterValues: job.GetWorkspaceProvision().ParameterValues, @@ -512,7 +521,7 @@ func (p *provisionerDaemon) runWorkspaceProvision(ctx context.Context, provision State: job.GetWorkspaceProvision().State, }) if err != nil { - p.cancelActiveJobf("provision: %s", err) + p.failActiveJobf("provision: %s", err) return } defer stream.Close() @@ -520,7 +529,7 @@ func (p *provisionerDaemon) runWorkspaceProvision(ctx context.Context, provision for { msg, err := stream.Recv() if err != nil { - p.cancelActiveJobf("recv workspace provision: %s", err) + p.failActiveJobf("recv workspace provision: %s", err) return } switch msgType := msg.Type.(type) { @@ -541,10 +550,26 @@ func (p *provisionerDaemon) runWorkspaceProvision(ctx context.Context, provision }}, }) if err != nil { - p.cancelActiveJobf("send job update: %s", err) + p.failActiveJobf("send job update: %s", err) return } case *sdkproto.Provision_Response_Complete: + if msgType.Complete.Error != "" { + p.opts.Logger.Info(context.Background(), "provision failed; updating state", + slog.F("state_length", len(msgType.Complete.State)), + ) + + p.failActiveJob(&proto.FailedJob{ + Error: msgType.Complete.Error, + Type: &proto.FailedJob_WorkspaceProvision_{ + WorkspaceProvision: &proto.FailedJob_WorkspaceProvision{ + State: msgType.Complete.State, + }, + }, + }) + return + } + p.opts.Logger.Info(context.Background(), "provision successful; marking job as complete", slog.F("resource_count", len(msgType.Complete.Resources)), slog.F("resources", msgType.Complete.Resources), @@ -563,53 +588,56 @@ func (p *provisionerDaemon) runWorkspaceProvision(ctx context.Context, provision }, }) if err != nil { - p.cancelActiveJobf("complete job: %s", err) + p.failActiveJobf("complete job: %s", err) return } // Return so we stop looping! return default: - p.cancelActiveJobf("invalid message type %q received from provisioner", + p.failActiveJobf("invalid message type %q received from provisioner", reflect.TypeOf(msg.Type).String()) return } } } -func (p *provisionerDaemon) cancelActiveJobf(format string, args ...interface{}) { +func (p *Server) failActiveJobf(format string, args ...interface{}) { + p.failActiveJob(&proto.FailedJob{ + Error: fmt.Sprintf(format, args...), + }) +} + +func (p *Server) failActiveJob(failedJob *proto.FailedJob) { p.jobMutex.Lock() defer p.jobMutex.Unlock() - errMsg := fmt.Sprintf(format, args...) if !p.isRunningJob() { if p.isClosed() { return } - p.opts.Logger.Info(context.Background(), "skipping job cancel; none running", slog.F("error_message", errMsg)) + p.opts.Logger.Info(context.Background(), "skipping job fail; none running", slog.F("error_message", failedJob.Error)) return } - if p.jobCancelled.Load() { - p.opts.Logger.Warn(context.Background(), "job has already been canceled", slog.F("error_messsage", errMsg)) + if p.jobFailed.Load() { + p.opts.Logger.Warn(context.Background(), "job has already been marked as failed", slog.F("error_messsage", failedJob.Error)) return } - p.jobCancelled.Store(true) + p.jobFailed.Store(true) p.jobCancel() - p.opts.Logger.Info(context.Background(), "canceling running job", - slog.F("error_message", errMsg), + p.opts.Logger.Info(context.Background(), "failing running job", + slog.F("error_message", failedJob.Error), slog.F("job_id", p.jobID), ) - _, err := p.client.CancelJob(context.Background(), &proto.CancelledJob{ - JobId: p.jobID, - Error: fmt.Sprintf("provisioner daemon: %s", errMsg), - }) + failedJob.JobId = p.jobID + _, err := p.client.FailJob(context.Background(), failedJob) if err != nil { - p.opts.Logger.Warn(context.Background(), "failed to notify of cancel; job is no longer running", slog.Error(err)) + p.opts.Logger.Warn(context.Background(), "failed to notify of error; job is no longer running", slog.Error(err)) return } - p.opts.Logger.Debug(context.Background(), "canceled running job") + p.opts.Logger.Debug(context.Background(), "marked running job as failed") } // isClosed returns whether the API is closed or not. -func (p *provisionerDaemon) isClosed() bool { +func (p *Server) isClosed() bool { select { case <-p.closed: return true @@ -618,13 +646,49 @@ func (p *provisionerDaemon) isClosed() bool { } } -// Close ends the provisioner. It will mark any running jobs as canceled. -func (p *provisionerDaemon) Close() error { +// isShutdown returns whether the API is shutdown or not. +func (p *Server) isShutdown() bool { + select { + case <-p.shutdown: + return true + default: + return false + } +} + +// Shutdown triggers a graceful exit of each registered provisioner. +// It exits when an active job stops. +func (p *Server) Shutdown(ctx context.Context) error { + p.shutdownMutex.Lock() + defer p.shutdownMutex.Unlock() + if !p.isRunningJob() { + return nil + } + p.opts.Logger.Info(ctx, "attempting graceful shutdown") + close(p.shutdown) + for id, provisioner := range p.opts.Provisioners { + _, err := provisioner.Shutdown(ctx, &sdkproto.Empty{}) + if err != nil { + return xerrors.Errorf("shutdown %q: %w", id, err) + } + } + select { + case <-ctx.Done(): + p.opts.Logger.Warn(ctx, "graceful shutdown failed", slog.Error(ctx.Err())) + return ctx.Err() + case <-p.jobRunning: + p.opts.Logger.Info(ctx, "gracefully shutdown") + return nil + } +} + +// Close ends the provisioner. It will mark any running jobs as failed. +func (p *Server) Close() error { return p.closeWithError(nil) } // closeWithError closes the provisioner; subsequent reads/writes will return the error err. -func (p *provisionerDaemon) closeWithError(err error) error { +func (p *Server) closeWithError(err error) error { p.closeMutex.Lock() defer p.closeMutex.Unlock() if p.isClosed() { @@ -637,7 +701,7 @@ func (p *provisionerDaemon) closeWithError(err error) error { if err != nil { errMsg = err.Error() } - p.cancelActiveJobf(errMsg) + p.failActiveJobf(errMsg) <-p.jobRunning p.closeCancel() diff --git a/provisionerd/provisionerd_test.go b/provisionerd/provisionerd_test.go index 3a53ad6d9ec96..1e482ddefd623 100644 --- a/provisionerd/provisionerd_test.go +++ b/provisionerd/provisionerd_test.go @@ -103,7 +103,7 @@ func TestProvisionerd(t *testing.T) { }, nil }, updateJob: noopUpdateJob, - cancelJob: func(ctx context.Context, job *proto.CancelledJob) (*proto.Empty, error) { + failJob: func(ctx context.Context, job *proto.FailedJob) (*proto.Empty, error) { close(completeChan) return &proto.Empty{}, nil }, @@ -144,7 +144,7 @@ func TestProvisionerd(t *testing.T) { }, nil }, updateJob: noopUpdateJob, - cancelJob: func(ctx context.Context, job *proto.CancelledJob) (*proto.Empty, error) { + failJob: func(ctx context.Context, job *proto.FailedJob) (*proto.Empty, error) { close(completeChan) return &proto.Empty{}, nil }, @@ -179,7 +179,7 @@ func TestProvisionerd(t *testing.T) { close(completeChan) return &proto.UpdateJobResponse{}, nil }, - cancelJob: func(ctx context.Context, job *proto.CancelledJob) (*proto.Empty, error) { + failJob: func(ctx context.Context, job *proto.FailedJob) (*proto.Empty, error) { return &proto.Empty{}, nil }, }), nil @@ -362,6 +362,129 @@ func TestProvisionerd(t *testing.T) { require.True(t, didComplete.Load()) require.NoError(t, closer.Close()) }) + + t.Run("WorkspaceProvisionFailComplete", func(t *testing.T) { + t.Parallel() + var ( + didFail atomic.Bool + didAcquireJob atomic.Bool + ) + completeChan := make(chan struct{}) + closer := createProvisionerd(t, func(ctx context.Context) (proto.DRPCProvisionerDaemonClient, error) { + return createProvisionerDaemonClient(t, provisionerDaemonTestServer{ + acquireJob: func(ctx context.Context, _ *proto.Empty) (*proto.AcquiredJob, error) { + if didAcquireJob.Load() { + close(completeChan) + return &proto.AcquiredJob{}, nil + } + didAcquireJob.Store(true) + return &proto.AcquiredJob{ + JobId: "test", + Provisioner: "someprovisioner", + ProjectSourceArchive: createTar(t, map[string]string{ + "test.txt": "content", + }), + Type: &proto.AcquiredJob_WorkspaceProvision_{ + WorkspaceProvision: &proto.AcquiredJob_WorkspaceProvision{ + Metadata: &sdkproto.Provision_Metadata{}, + }, + }, + }, nil + }, + failJob: func(ctx context.Context, job *proto.FailedJob) (*proto.Empty, error) { + didFail.Store(true) + return &proto.Empty{}, nil + }, + }), nil + }, provisionerd.Provisioners{ + "someprovisioner": createProvisionerClient(t, provisionerTestServer{ + provision: func(request *sdkproto.Provision_Request, stream sdkproto.DRPCProvisioner_ProvisionStream) error { + err := stream.Send(&sdkproto.Provision_Response{ + Type: &sdkproto.Provision_Response_Complete{ + Complete: &sdkproto.Provision_Complete{ + Error: "some error", + }, + }, + }) + require.NoError(t, err) + return nil + }, + }), + }) + <-completeChan + require.True(t, didFail.Load()) + require.NoError(t, closer.Close()) + }) + + t.Run("Shutdown", func(t *testing.T) { + t.Parallel() + updateChan := make(chan struct{}) + completeChan := make(chan struct{}) + shutdownCtx, shutdownCtxCancel := context.WithCancel(context.Background()) + defer shutdownCtxCancel() + server := createProvisionerd(t, func(ctx context.Context) (proto.DRPCProvisionerDaemonClient, error) { + return createProvisionerDaemonClient(t, provisionerDaemonTestServer{ + acquireJob: func(ctx context.Context, _ *proto.Empty) (*proto.AcquiredJob, error) { + return &proto.AcquiredJob{ + JobId: "test", + Provisioner: "someprovisioner", + ProjectSourceArchive: createTar(t, map[string]string{ + "test.txt": "content", + }), + Type: &proto.AcquiredJob_WorkspaceProvision_{ + WorkspaceProvision: &proto.AcquiredJob_WorkspaceProvision{ + Metadata: &sdkproto.Provision_Metadata{}, + }, + }, + }, nil + }, + updateJob: func(ctx context.Context, update *proto.UpdateJobRequest) (*proto.UpdateJobResponse, error) { + if len(update.Logs) > 0 { + // Close on a log so we know when the job is in progress! + close(updateChan) + } + return &proto.UpdateJobResponse{}, nil + }, + failJob: func(ctx context.Context, job *proto.FailedJob) (*proto.Empty, error) { + close(completeChan) + return &proto.Empty{}, nil + }, + }), nil + }, provisionerd.Provisioners{ + "someprovisioner": createProvisionerClient(t, provisionerTestServer{ + shutdown: func(_ context.Context, _ *sdkproto.Empty) (*sdkproto.Empty, error) { + shutdownCtxCancel() + return &sdkproto.Empty{}, nil + }, + provision: func(request *sdkproto.Provision_Request, stream sdkproto.DRPCProvisioner_ProvisionStream) error { + err := stream.Send(&sdkproto.Provision_Response{ + Type: &sdkproto.Provision_Response_Log{ + Log: &sdkproto.Log{ + Level: sdkproto.LogLevel_DEBUG, + Output: "in progress", + }, + }, + }) + require.NoError(t, err) + <-shutdownCtx.Done() + err = stream.Send(&sdkproto.Provision_Response{ + Type: &sdkproto.Provision_Response_Complete{ + Complete: &sdkproto.Provision_Complete{ + Error: "some error", + }, + }, + }) + require.NoError(t, err) + return nil + }, + }), + }) + <-updateChan + err := server.Shutdown(context.Background()) + require.NoError(t, err) + <-completeChan + require.NoError(t, server.Close()) + }) } // Creates an in-memory tar of the files provided. @@ -385,8 +508,8 @@ func createTar(t *testing.T, files map[string]string) []byte { } // Creates a provisionerd implementation with the provided dialer and provisioners. -func createProvisionerd(t *testing.T, dialer provisionerd.Dialer, provisioners provisionerd.Provisioners) io.Closer { - closer := provisionerd.New(dialer, &provisionerd.Options{ +func createProvisionerd(t *testing.T, dialer provisionerd.Dialer, provisioners provisionerd.Provisioners) *provisionerd.Server { + server := provisionerd.New(dialer, &provisionerd.Options{ Logger: slogtest.Make(t, nil).Named("provisionerd").Leveled(slog.LevelDebug), PollInterval: 50 * time.Millisecond, UpdateInterval: 50 * time.Millisecond, @@ -394,9 +517,9 @@ func createProvisionerd(t *testing.T, dialer provisionerd.Dialer, provisioners p WorkDirectory: t.TempDir(), }) t.Cleanup(func() { - _ = closer.Close() + _ = server.Close() }) - return closer + return server } // Creates a provisionerd protobuf client that's connected @@ -440,10 +563,15 @@ func createProvisionerClient(t *testing.T, server provisionerTestServer) sdkprot } type provisionerTestServer struct { + shutdown func(_ context.Context, _ *sdkproto.Empty) (*sdkproto.Empty, error) parse func(request *sdkproto.Parse_Request, stream sdkproto.DRPCProvisioner_ParseStream) error provision func(request *sdkproto.Provision_Request, stream sdkproto.DRPCProvisioner_ProvisionStream) error } +func (p *provisionerTestServer) Shutdown(ctx context.Context, empty *sdkproto.Empty) (*sdkproto.Empty, error) { + return p.shutdown(ctx, empty) +} + func (p *provisionerTestServer) Parse(request *sdkproto.Parse_Request, stream sdkproto.DRPCProvisioner_ParseStream) error { return p.parse(request, stream) } @@ -457,7 +585,7 @@ func (p *provisionerTestServer) Provision(request *sdkproto.Provision_Request, s type provisionerDaemonTestServer struct { acquireJob func(ctx context.Context, _ *proto.Empty) (*proto.AcquiredJob, error) updateJob func(ctx context.Context, update *proto.UpdateJobRequest) (*proto.UpdateJobResponse, error) - cancelJob func(ctx context.Context, job *proto.CancelledJob) (*proto.Empty, error) + failJob func(ctx context.Context, job *proto.FailedJob) (*proto.Empty, error) completeJob func(ctx context.Context, job *proto.CompletedJob) (*proto.Empty, error) } @@ -469,8 +597,8 @@ func (p *provisionerDaemonTestServer) UpdateJob(ctx context.Context, update *pro return p.updateJob(ctx, update) } -func (p *provisionerDaemonTestServer) CancelJob(ctx context.Context, job *proto.CancelledJob) (*proto.Empty, error) { - return p.cancelJob(ctx, job) +func (p *provisionerDaemonTestServer) FailJob(ctx context.Context, job *proto.FailedJob) (*proto.Empty, error) { + return p.failJob(ctx, job) } func (p *provisionerDaemonTestServer) CompleteJob(ctx context.Context, job *proto.CompletedJob) (*proto.Empty, error) { diff --git a/provisionersdk/proto/provisioner.pb.go b/provisionersdk/proto/provisioner.pb.go index 43d2c0fe44af8..d6bbf1727c96f 100644 --- a/provisionersdk/proto/provisioner.pb.go +++ b/provisionersdk/proto/provisioner.pb.go @@ -162,7 +162,7 @@ func (x ParameterSource_Scheme) Number() protoreflect.EnumNumber { // Deprecated: Use ParameterSource_Scheme.Descriptor instead. func (ParameterSource_Scheme) EnumDescriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{0, 0} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{1, 0} } type ParameterDestination_Scheme int32 @@ -208,7 +208,7 @@ func (x ParameterDestination_Scheme) Number() protoreflect.EnumNumber { // Deprecated: Use ParameterDestination_Scheme.Descriptor instead. func (ParameterDestination_Scheme) EnumDescriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{1, 0} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{2, 0} } type ParameterSchema_TypeSystem int32 @@ -254,7 +254,46 @@ func (x ParameterSchema_TypeSystem) Number() protoreflect.EnumNumber { // Deprecated: Use ParameterSchema_TypeSystem.Descriptor instead. func (ParameterSchema_TypeSystem) EnumDescriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{3, 0} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{4, 0} +} + +// Empty indicates a successful request/response. +type Empty struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *Empty) Reset() { + *x = Empty{} + if protoimpl.UnsafeEnabled { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Empty) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Empty) ProtoMessage() {} + +func (x *Empty) ProtoReflect() protoreflect.Message { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[0] + 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 Empty.ProtoReflect.Descriptor instead. +func (*Empty) Descriptor() ([]byte, []int) { + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{0} } // ParameterSource represents the source location for a parameter to get it's value from. @@ -270,7 +309,7 @@ type ParameterSource struct { func (x *ParameterSource) Reset() { *x = ParameterSource{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[0] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -283,7 +322,7 @@ func (x *ParameterSource) String() string { func (*ParameterSource) ProtoMessage() {} func (x *ParameterSource) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[0] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -296,7 +335,7 @@ func (x *ParameterSource) ProtoReflect() protoreflect.Message { // Deprecated: Use ParameterSource.ProtoReflect.Descriptor instead. func (*ParameterSource) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{0} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{1} } func (x *ParameterSource) GetScheme() ParameterSource_Scheme { @@ -325,7 +364,7 @@ type ParameterDestination struct { func (x *ParameterDestination) Reset() { *x = ParameterDestination{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[1] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -338,7 +377,7 @@ func (x *ParameterDestination) String() string { func (*ParameterDestination) ProtoMessage() {} func (x *ParameterDestination) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[1] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -351,7 +390,7 @@ func (x *ParameterDestination) ProtoReflect() protoreflect.Message { // Deprecated: Use ParameterDestination.ProtoReflect.Descriptor instead. func (*ParameterDestination) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{1} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{2} } func (x *ParameterDestination) GetScheme() ParameterDestination_Scheme { @@ -375,7 +414,7 @@ type ParameterValue struct { func (x *ParameterValue) Reset() { *x = ParameterValue{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[2] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -388,7 +427,7 @@ func (x *ParameterValue) String() string { func (*ParameterValue) ProtoMessage() {} func (x *ParameterValue) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[2] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -401,7 +440,7 @@ func (x *ParameterValue) ProtoReflect() protoreflect.Message { // Deprecated: Use ParameterValue.ProtoReflect.Descriptor instead. func (*ParameterValue) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{2} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{3} } func (x *ParameterValue) GetDestinationScheme() ParameterDestination_Scheme { @@ -447,7 +486,7 @@ type ParameterSchema struct { func (x *ParameterSchema) Reset() { *x = ParameterSchema{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[3] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -460,7 +499,7 @@ func (x *ParameterSchema) String() string { func (*ParameterSchema) ProtoMessage() {} func (x *ParameterSchema) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[3] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -473,7 +512,7 @@ func (x *ParameterSchema) ProtoReflect() protoreflect.Message { // Deprecated: Use ParameterSchema.ProtoReflect.Descriptor instead. func (*ParameterSchema) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{3} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{4} } func (x *ParameterSchema) GetName() string { @@ -566,7 +605,7 @@ type Log struct { func (x *Log) Reset() { *x = Log{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[4] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -579,7 +618,7 @@ func (x *Log) String() string { func (*Log) ProtoMessage() {} func (x *Log) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[4] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -592,7 +631,7 @@ func (x *Log) ProtoReflect() protoreflect.Message { // Deprecated: Use Log.ProtoReflect.Descriptor instead. func (*Log) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{4} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{5} } func (x *Log) GetLevel() LogLevel { @@ -620,7 +659,7 @@ type GoogleInstanceIdentityAuth struct { func (x *GoogleInstanceIdentityAuth) Reset() { *x = GoogleInstanceIdentityAuth{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[5] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -633,7 +672,7 @@ func (x *GoogleInstanceIdentityAuth) String() string { func (*GoogleInstanceIdentityAuth) ProtoMessage() {} func (x *GoogleInstanceIdentityAuth) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[5] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -646,7 +685,7 @@ func (x *GoogleInstanceIdentityAuth) ProtoReflect() protoreflect.Message { // Deprecated: Use GoogleInstanceIdentityAuth.ProtoReflect.Descriptor instead. func (*GoogleInstanceIdentityAuth) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{5} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{6} } func (x *GoogleInstanceIdentityAuth) GetInstanceId() string { @@ -674,7 +713,7 @@ type Agent struct { func (x *Agent) Reset() { *x = Agent{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[6] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -687,7 +726,7 @@ func (x *Agent) String() string { func (*Agent) ProtoMessage() {} func (x *Agent) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[6] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -700,7 +739,7 @@ func (x *Agent) ProtoReflect() protoreflect.Message { // Deprecated: Use Agent.ProtoReflect.Descriptor instead. func (*Agent) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{6} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{7} } func (x *Agent) GetId() string { @@ -776,7 +815,7 @@ type Resource struct { func (x *Resource) Reset() { *x = Resource{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[7] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -789,7 +828,7 @@ func (x *Resource) String() string { func (*Resource) ProtoMessage() {} func (x *Resource) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[7] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -802,7 +841,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{7} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{8} } func (x *Resource) GetName() string { @@ -836,7 +875,7 @@ type Parse struct { func (x *Parse) Reset() { *x = Parse{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[8] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -849,7 +888,7 @@ func (x *Parse) String() string { func (*Parse) ProtoMessage() {} func (x *Parse) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[8] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -862,7 +901,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{8} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{9} } // Provision consumes source-code from a directory to produce resources. @@ -875,7 +914,7 @@ type Provision struct { func (x *Provision) Reset() { *x = Provision{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[9] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -888,7 +927,7 @@ func (x *Provision) String() string { func (*Provision) ProtoMessage() {} func (x *Provision) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[9] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -901,7 +940,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{9} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{10} } type Parse_Request struct { @@ -915,7 +954,7 @@ type Parse_Request struct { func (x *Parse_Request) Reset() { *x = Parse_Request{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[11] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -928,7 +967,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[11] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -941,7 +980,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{8, 0} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{9, 0} } func (x *Parse_Request) GetDirectory() string { @@ -962,7 +1001,7 @@ type Parse_Complete struct { func (x *Parse_Complete) Reset() { *x = Parse_Complete{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[12] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -975,7 +1014,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[12] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -988,7 +1027,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{8, 1} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{9, 1} } func (x *Parse_Complete) GetParameterSchemas() []*ParameterSchema { @@ -1012,7 +1051,7 @@ type Parse_Response struct { func (x *Parse_Response) Reset() { *x = Parse_Response{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[13] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1025,7 +1064,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[13] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1038,7 +1077,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{8, 2} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{9, 2} } func (m *Parse_Response) GetType() isParse_Response_Type { @@ -1090,7 +1129,7 @@ type Provision_Metadata struct { func (x *Provision_Metadata) Reset() { *x = Provision_Metadata{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[14] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1103,7 +1142,7 @@ func (x *Provision_Metadata) String() string { func (*Provision_Metadata) ProtoMessage() {} func (x *Provision_Metadata) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[14] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1116,7 +1155,7 @@ func (x *Provision_Metadata) ProtoReflect() protoreflect.Message { // Deprecated: Use Provision_Metadata.ProtoReflect.Descriptor instead. func (*Provision_Metadata) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{9, 0} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{10, 0} } func (x *Provision_Metadata) GetCoderUrl() string { @@ -1148,7 +1187,7 @@ type Provision_Request struct { func (x *Provision_Request) Reset() { *x = Provision_Request{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[15] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1161,7 +1200,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[15] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1174,7 +1213,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{9, 1} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{10, 1} } func (x *Provision_Request) GetDirectory() string { @@ -1218,13 +1257,14 @@ type Provision_Complete struct { unknownFields protoimpl.UnknownFields State []byte `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"` - Resources []*Resource `protobuf:"bytes,2,rep,name=resources,proto3" json:"resources,omitempty"` + Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` + Resources []*Resource `protobuf:"bytes,3,rep,name=resources,proto3" json:"resources,omitempty"` } func (x *Provision_Complete) Reset() { *x = Provision_Complete{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[16] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1237,7 +1277,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[16] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1250,7 +1290,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{9, 2} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{10, 2} } func (x *Provision_Complete) GetState() []byte { @@ -1260,6 +1300,13 @@ func (x *Provision_Complete) GetState() []byte { return nil } +func (x *Provision_Complete) GetError() string { + if x != nil { + return x.Error + } + return "" +} + func (x *Provision_Complete) GetResources() []*Resource { if x != nil { return x.Resources @@ -1281,7 +1328,7 @@ type Provision_Response struct { func (x *Provision_Response) Reset() { *x = Provision_Response{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[17] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1294,7 +1341,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[17] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1307,7 +1354,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{9, 3} + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{10, 3} } func (m *Provision_Response) GetType() isProvision_Response_Type { @@ -1353,180 +1400,185 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 0x0a, 0x26, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x22, 0x78, 0x0a, 0x0f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, - 0x65, 0x72, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, - 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x52, 0x06, 0x73, - 0x63, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x12, 0x0a, 0x06, 0x53, - 0x63, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x41, 0x54, 0x41, 0x10, 0x00, 0x22, - 0x96, 0x01, 0x0a, 0x14, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x44, 0x65, 0x73, - 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x40, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, - 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, - 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x63, 0x68, 0x65, - 0x6d, 0x65, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x22, 0x3c, 0x0a, 0x06, 0x53, 0x63, - 0x68, 0x65, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x14, 0x45, 0x4e, 0x56, 0x49, 0x52, 0x4f, 0x4e, 0x4d, - 0x45, 0x4e, 0x54, 0x5f, 0x56, 0x41, 0x52, 0x49, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x18, - 0x0a, 0x14, 0x50, 0x52, 0x4f, 0x56, 0x49, 0x53, 0x49, 0x4f, 0x4e, 0x45, 0x52, 0x5f, 0x56, 0x41, - 0x52, 0x49, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x01, 0x22, 0x93, 0x01, 0x0a, 0x0e, 0x50, 0x61, 0x72, - 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x64, - 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, - 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x44, - 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, - 0x65, 0x52, 0x11, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, - 0x68, 0x65, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x8d, - 0x05, 0x0a, 0x0f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, - 0x6d, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, - 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, - 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x43, 0x0a, 0x0e, 0x64, 0x65, 0x66, 0x61, - 0x75, 0x6c, 0x74, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 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, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x0d, - 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x32, 0x0a, - 0x15, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x5f, - 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x61, 0x6c, - 0x6c, 0x6f, 0x77, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, - 0x65, 0x12, 0x52, 0x0a, 0x13, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x64, 0x65, 0x73, - 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x22, 0x07, 0x0a, 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x78, + 0x0a, 0x0f, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x6f, 0x75, 0x72, 0x63, + 0x65, 0x12, 0x3b, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x23, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, + 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x52, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x22, 0x12, 0x0a, 0x06, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x08, + 0x0a, 0x04, 0x44, 0x41, 0x54, 0x41, 0x10, 0x00, 0x22, 0x96, 0x01, 0x0a, 0x14, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x52, 0x12, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3c, 0x0a, 0x1a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x6f, - 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x18, 0x61, 0x6c, 0x6c, 0x6f, 0x77, - 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, - 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, 0x72, 0x65, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, - 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x72, 0x65, - 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x5d, 0x0a, 0x16, - 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, - 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 0x2e, 0x70, + 0x6e, 0x12, 0x40, 0x0a, 0x06, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x52, 0x06, 0x73, 0x63, 0x68, + 0x65, 0x6d, 0x65, 0x22, 0x3c, 0x0a, 0x06, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x18, 0x0a, + 0x14, 0x45, 0x4e, 0x56, 0x49, 0x52, 0x4f, 0x4e, 0x4d, 0x45, 0x4e, 0x54, 0x5f, 0x56, 0x41, 0x52, + 0x49, 0x41, 0x42, 0x4c, 0x45, 0x10, 0x00, 0x12, 0x18, 0x0a, 0x14, 0x50, 0x52, 0x4f, 0x56, 0x49, + 0x53, 0x49, 0x4f, 0x4e, 0x45, 0x52, 0x5f, 0x56, 0x41, 0x52, 0x49, 0x41, 0x42, 0x4c, 0x45, 0x10, + 0x01, 0x22, 0x93, 0x01, 0x0a, 0x0e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x12, 0x57, 0x0a, 0x12, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x28, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x52, 0x11, 0x64, 0x65, 0x73, 0x74, + 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x65, 0x12, 0x12, 0x0a, + 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x8d, 0x05, 0x0a, 0x0f, 0x50, 0x61, 0x72, 0x61, + 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, + 0x6e, 0x12, 0x43, 0x0a, 0x0e, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x73, 0x6f, 0x75, + 0x72, 0x63, 0x65, 0x18, 0x03, 0x20, 0x01, 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, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x52, 0x0d, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6c, 0x74, + 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, + 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x13, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x4f, 0x76, 0x65, 0x72, + 0x72, 0x69, 0x64, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x52, 0x0a, 0x13, 0x64, 0x65, + 0x66, 0x61, 0x75, 0x6c, 0x74, 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x44, + 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x12, 0x64, 0x65, 0x66, 0x61, + 0x75, 0x6c, 0x74, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x3c, + 0x0a, 0x1a, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x5f, 0x6f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, 0x65, + 0x5f, 0x64, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x18, 0x61, 0x6c, 0x6c, 0x6f, 0x77, 0x4f, 0x76, 0x65, 0x72, 0x72, 0x69, 0x64, + 0x65, 0x44, 0x65, 0x73, 0x74, 0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x27, 0x0a, 0x0f, + 0x72, 0x65, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, + 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0e, 0x72, 0x65, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x5d, 0x0a, 0x16, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, + 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x27, 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, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x14, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x79, 0x70, 0x65, 0x53, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x12, 0x32, 0x0a, 0x15, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, + 0x01, 0x28, 0x09, 0x52, 0x13, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, + 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x76, 0x61, 0x6c, 0x69, + 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x0a, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, + 0x72, 0x6f, 0x72, 0x12, 0x31, 0x0a, 0x14, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, + 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x13, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, + 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1f, 0x0a, 0x0a, 0x54, 0x79, 0x70, 0x65, 0x53, 0x79, + 0x73, 0x74, 0x65, 0x6d, 0x12, 0x08, 0x0a, 0x04, 0x4e, 0x6f, 0x6e, 0x65, 0x10, 0x00, 0x12, 0x07, + 0x0a, 0x03, 0x48, 0x43, 0x4c, 0x10, 0x01, 0x22, 0x4a, 0x0a, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x2b, + 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 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, 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, 0xcd, 0x04, 0x0a, + 0x09, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0x7c, 0x0a, 0x08, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1b, 0x0a, 0x09, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x5f, + 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x63, 0x6f, 0x64, 0x65, 0x72, + 0x55, 0x72, 0x6c, 0x12, 0x53, 0x0a, 0x14, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x0e, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, + 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, + 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, + 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x1a, 0xdb, 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, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x2e, 0x54, 0x79, 0x70, 0x65, 0x53, - 0x79, 0x73, 0x74, 0x65, 0x6d, 0x52, 0x14, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, - 0x6e, 0x54, 0x79, 0x70, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x32, 0x0a, 0x15, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x5f, - 0x74, 0x79, 0x70, 0x65, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x76, 0x61, 0x6c, 0x69, - 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, - 0x29, 0x0a, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x65, 0x72, - 0x72, 0x6f, 0x72, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x76, 0x61, 0x6c, 0x69, 0x64, - 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x31, 0x0a, 0x14, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, - 0x74, 0x69, 0x6f, 0x6e, 0x43, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0x1f, 0x0a, - 0x0a, 0x54, 0x79, 0x70, 0x65, 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x08, 0x0a, 0x04, 0x4e, - 0x6f, 0x6e, 0x65, 0x10, 0x00, 0x12, 0x07, 0x0a, 0x03, 0x48, 0x43, 0x4c, 0x10, 0x01, 0x22, 0x4a, - 0x0a, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x2b, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, - 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, 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, 0xb7, 0x04, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x1a, 0x7c, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x1b, 0x0a, - 0x09, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x55, 0x72, 0x6c, 0x12, 0x53, 0x0a, 0x14, 0x77, 0x6f, - 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, - 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x1a, - 0xdb, 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, 0x3b, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 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, 0x4d, 0x65, 0x74, 0x61, - 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, - 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, - 0x74, 0x61, 0x74, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x72, 0x79, 0x5f, 0x72, 0x75, 0x6e, 0x18, - 0x05, 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, 0x2a, 0x2a, - 0x0a, 0x13, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, - 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x00, - 0x12, 0x08, 0x0a, 0x04, 0x53, 0x54, 0x4f, 0x50, 0x10, 0x01, 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, + 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, 0x3b, 0x0a, 0x08, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x03, 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, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, + 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x17, 0x0a, + 0x07, 0x64, 0x72, 0x79, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, + 0x64, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x1a, 0x6b, 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, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, 0x33, + 0x0a, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x18, 0x03, 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, 0x2a, 0x2a, 0x0a, + 0x13, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, + 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x00, 0x12, + 0x08, 0x0a, 0x04, 0x53, 0x54, 0x4f, 0x50, 0x10, 0x01, 0x32, 0xd5, 0x01, 0x0a, 0x0b, 0x50, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x08, 0x53, 0x68, 0x75, + 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 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 ( @@ -1542,58 +1594,61 @@ func file_provisionersdk_proto_provisioner_proto_rawDescGZIP() []byte { } var file_provisionersdk_proto_provisioner_proto_enumTypes = make([]protoimpl.EnumInfo, 5) -var file_provisionersdk_proto_provisioner_proto_msgTypes = make([]protoimpl.MessageInfo, 18) +var file_provisionersdk_proto_provisioner_proto_msgTypes = make([]protoimpl.MessageInfo, 19) var file_provisionersdk_proto_provisioner_proto_goTypes = []interface{}{ (LogLevel)(0), // 0: provisioner.LogLevel (WorkspaceTransition)(0), // 1: provisioner.WorkspaceTransition (ParameterSource_Scheme)(0), // 2: provisioner.ParameterSource.Scheme (ParameterDestination_Scheme)(0), // 3: provisioner.ParameterDestination.Scheme (ParameterSchema_TypeSystem)(0), // 4: provisioner.ParameterSchema.TypeSystem - (*ParameterSource)(nil), // 5: provisioner.ParameterSource - (*ParameterDestination)(nil), // 6: provisioner.ParameterDestination - (*ParameterValue)(nil), // 7: provisioner.ParameterValue - (*ParameterSchema)(nil), // 8: provisioner.ParameterSchema - (*Log)(nil), // 9: provisioner.Log - (*GoogleInstanceIdentityAuth)(nil), // 10: provisioner.GoogleInstanceIdentityAuth - (*Agent)(nil), // 11: provisioner.Agent - (*Resource)(nil), // 12: provisioner.Resource - (*Parse)(nil), // 13: provisioner.Parse - (*Provision)(nil), // 14: provisioner.Provision - nil, // 15: provisioner.Agent.EnvEntry - (*Parse_Request)(nil), // 16: provisioner.Parse.Request - (*Parse_Complete)(nil), // 17: provisioner.Parse.Complete - (*Parse_Response)(nil), // 18: provisioner.Parse.Response - (*Provision_Metadata)(nil), // 19: provisioner.Provision.Metadata - (*Provision_Request)(nil), // 20: provisioner.Provision.Request - (*Provision_Complete)(nil), // 21: provisioner.Provision.Complete - (*Provision_Response)(nil), // 22: provisioner.Provision.Response + (*Empty)(nil), // 5: provisioner.Empty + (*ParameterSource)(nil), // 6: provisioner.ParameterSource + (*ParameterDestination)(nil), // 7: provisioner.ParameterDestination + (*ParameterValue)(nil), // 8: provisioner.ParameterValue + (*ParameterSchema)(nil), // 9: provisioner.ParameterSchema + (*Log)(nil), // 10: provisioner.Log + (*GoogleInstanceIdentityAuth)(nil), // 11: provisioner.GoogleInstanceIdentityAuth + (*Agent)(nil), // 12: provisioner.Agent + (*Resource)(nil), // 13: provisioner.Resource + (*Parse)(nil), // 14: provisioner.Parse + (*Provision)(nil), // 15: provisioner.Provision + nil, // 16: provisioner.Agent.EnvEntry + (*Parse_Request)(nil), // 17: provisioner.Parse.Request + (*Parse_Complete)(nil), // 18: provisioner.Parse.Complete + (*Parse_Response)(nil), // 19: provisioner.Parse.Response + (*Provision_Metadata)(nil), // 20: provisioner.Provision.Metadata + (*Provision_Request)(nil), // 21: provisioner.Provision.Request + (*Provision_Complete)(nil), // 22: provisioner.Provision.Complete + (*Provision_Response)(nil), // 23: provisioner.Provision.Response } var file_provisionersdk_proto_provisioner_proto_depIdxs = []int32{ 2, // 0: provisioner.ParameterSource.scheme:type_name -> provisioner.ParameterSource.Scheme 3, // 1: provisioner.ParameterDestination.scheme:type_name -> provisioner.ParameterDestination.Scheme 3, // 2: provisioner.ParameterValue.destination_scheme:type_name -> provisioner.ParameterDestination.Scheme - 5, // 3: provisioner.ParameterSchema.default_source:type_name -> provisioner.ParameterSource - 6, // 4: provisioner.ParameterSchema.default_destination:type_name -> provisioner.ParameterDestination + 6, // 3: provisioner.ParameterSchema.default_source:type_name -> provisioner.ParameterSource + 7, // 4: provisioner.ParameterSchema.default_destination:type_name -> provisioner.ParameterDestination 4, // 5: provisioner.ParameterSchema.validation_type_system:type_name -> provisioner.ParameterSchema.TypeSystem 0, // 6: provisioner.Log.level:type_name -> provisioner.LogLevel - 15, // 7: provisioner.Agent.env:type_name -> provisioner.Agent.EnvEntry - 10, // 8: provisioner.Agent.google_instance_identity:type_name -> provisioner.GoogleInstanceIdentityAuth - 11, // 9: provisioner.Resource.agent:type_name -> provisioner.Agent - 8, // 10: provisioner.Parse.Complete.parameter_schemas:type_name -> provisioner.ParameterSchema - 9, // 11: provisioner.Parse.Response.log:type_name -> provisioner.Log - 17, // 12: provisioner.Parse.Response.complete:type_name -> provisioner.Parse.Complete + 16, // 7: provisioner.Agent.env:type_name -> provisioner.Agent.EnvEntry + 11, // 8: provisioner.Agent.google_instance_identity:type_name -> provisioner.GoogleInstanceIdentityAuth + 12, // 9: provisioner.Resource.agent:type_name -> provisioner.Agent + 9, // 10: provisioner.Parse.Complete.parameter_schemas:type_name -> provisioner.ParameterSchema + 10, // 11: provisioner.Parse.Response.log:type_name -> provisioner.Log + 18, // 12: provisioner.Parse.Response.complete:type_name -> provisioner.Parse.Complete 1, // 13: provisioner.Provision.Metadata.workspace_transition:type_name -> provisioner.WorkspaceTransition - 7, // 14: provisioner.Provision.Request.parameter_values:type_name -> provisioner.ParameterValue - 19, // 15: provisioner.Provision.Request.metadata:type_name -> provisioner.Provision.Metadata - 12, // 16: provisioner.Provision.Complete.resources:type_name -> provisioner.Resource - 9, // 17: provisioner.Provision.Response.log:type_name -> provisioner.Log - 21, // 18: provisioner.Provision.Response.complete:type_name -> provisioner.Provision.Complete - 16, // 19: provisioner.Provisioner.Parse:input_type -> provisioner.Parse.Request - 20, // 20: provisioner.Provisioner.Provision:input_type -> provisioner.Provision.Request - 18, // 21: provisioner.Provisioner.Parse:output_type -> provisioner.Parse.Response - 22, // 22: provisioner.Provisioner.Provision:output_type -> provisioner.Provision.Response - 21, // [21:23] is the sub-list for method output_type - 19, // [19:21] is the sub-list for method input_type + 8, // 14: provisioner.Provision.Request.parameter_values:type_name -> provisioner.ParameterValue + 20, // 15: provisioner.Provision.Request.metadata:type_name -> provisioner.Provision.Metadata + 13, // 16: provisioner.Provision.Complete.resources:type_name -> provisioner.Resource + 10, // 17: provisioner.Provision.Response.log:type_name -> provisioner.Log + 22, // 18: provisioner.Provision.Response.complete:type_name -> provisioner.Provision.Complete + 5, // 19: provisioner.Provisioner.Shutdown:input_type -> provisioner.Empty + 17, // 20: provisioner.Provisioner.Parse:input_type -> provisioner.Parse.Request + 21, // 21: provisioner.Provisioner.Provision:input_type -> provisioner.Provision.Request + 5, // 22: provisioner.Provisioner.Shutdown:output_type -> provisioner.Empty + 19, // 23: provisioner.Provisioner.Parse:output_type -> provisioner.Parse.Response + 23, // 24: provisioner.Provisioner.Provision:output_type -> provisioner.Provision.Response + 22, // [22:25] is the sub-list for method output_type + 19, // [19:22] is the sub-list for method input_type 19, // [19:19] is the sub-list for extension type_name 19, // [19:19] is the sub-list for extension extendee 0, // [0:19] is the sub-list for field type_name @@ -1606,7 +1661,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } if !protoimpl.UnsafeEnabled { file_provisionersdk_proto_provisioner_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ParameterSource); i { + switch v := v.(*Empty); i { case 0: return &v.state case 1: @@ -1618,7 +1673,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ParameterDestination); i { + switch v := v.(*ParameterSource); i { case 0: return &v.state case 1: @@ -1630,7 +1685,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ParameterValue); i { + switch v := v.(*ParameterDestination); i { case 0: return &v.state case 1: @@ -1642,7 +1697,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ParameterSchema); i { + switch v := v.(*ParameterValue); i { case 0: return &v.state case 1: @@ -1654,7 +1709,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Log); i { + switch v := v.(*ParameterSchema); i { case 0: return &v.state case 1: @@ -1666,7 +1721,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.(*GoogleInstanceIdentityAuth); i { + switch v := v.(*Log); i { case 0: return &v.state case 1: @@ -1678,7 +1733,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.(*Agent); i { + switch v := v.(*GoogleInstanceIdentityAuth); i { case 0: return &v.state case 1: @@ -1690,7 +1745,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.(*Resource); i { + switch v := v.(*Agent); i { case 0: return &v.state case 1: @@ -1702,7 +1757,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); i { + switch v := v.(*Resource); i { case 0: return &v.state case 1: @@ -1714,6 +1769,18 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Parse); 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[10].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Provision); i { case 0: return &v.state @@ -1725,7 +1792,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[12].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Parse_Request); i { case 0: return &v.state @@ -1737,7 +1804,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[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Parse_Complete); i { case 0: return &v.state @@ -1749,7 +1816,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[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Parse_Response); i { case 0: return &v.state @@ -1761,7 +1828,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[14].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_Metadata); i { case 0: return &v.state @@ -1773,7 +1840,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[15].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_Request); i { case 0: return &v.state @@ -1785,7 +1852,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Provision_Complete); i { case 0: return &v.state @@ -1797,7 +1864,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { return nil } } - file_provisionersdk_proto_provisioner_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + file_provisionersdk_proto_provisioner_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Provision_Response); i { case 0: return &v.state @@ -1810,15 +1877,15 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } } - file_provisionersdk_proto_provisioner_proto_msgTypes[6].OneofWrappers = []interface{}{ + file_provisionersdk_proto_provisioner_proto_msgTypes[7].OneofWrappers = []interface{}{ (*Agent_Token)(nil), (*Agent_GoogleInstanceIdentity)(nil), } - file_provisionersdk_proto_provisioner_proto_msgTypes[13].OneofWrappers = []interface{}{ + file_provisionersdk_proto_provisioner_proto_msgTypes[14].OneofWrappers = []interface{}{ (*Parse_Response_Log)(nil), (*Parse_Response_Complete)(nil), } - file_provisionersdk_proto_provisioner_proto_msgTypes[17].OneofWrappers = []interface{}{ + file_provisionersdk_proto_provisioner_proto_msgTypes[18].OneofWrappers = []interface{}{ (*Provision_Response_Log)(nil), (*Provision_Response_Complete)(nil), } @@ -1828,7 +1895,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_provisionersdk_proto_provisioner_proto_rawDesc, NumEnums: 5, - NumMessages: 18, + NumMessages: 19, NumExtensions: 0, NumServices: 1, }, diff --git a/provisionersdk/proto/provisioner.proto b/provisionersdk/proto/provisioner.proto index d4ecb7893ea1d..4a1c28b36a4f9 100644 --- a/provisionersdk/proto/provisioner.proto +++ b/provisionersdk/proto/provisioner.proto @@ -4,6 +4,9 @@ option go_package = "github.com/coder/coder/provisionersdk/proto"; package provisioner; +// Empty indicates a successful request/response. +message Empty {} + // ParameterSource represents the source location for a parameter to get it's value from. message ParameterSource { enum Scheme { @@ -123,7 +126,8 @@ message Provision { } message Complete { bytes state = 1; - repeated Resource resources = 2; + string error = 2; + repeated Resource resources = 3; } message Response { oneof type { @@ -134,6 +138,7 @@ message Provision { } service Provisioner { + rpc Shutdown(Empty) returns (Empty); rpc Parse(Parse.Request) returns (stream Parse.Response); rpc Provision(Provision.Request) returns (stream Provision.Response); } diff --git a/provisionersdk/proto/provisioner_drpc.pb.go b/provisionersdk/proto/provisioner_drpc.pb.go index cff7c3b2814f1..8eaa9e1c93182 100644 --- a/provisionersdk/proto/provisioner_drpc.pb.go +++ b/provisionersdk/proto/provisioner_drpc.pb.go @@ -38,6 +38,7 @@ func (drpcEncoding_File_provisionersdk_proto_provisioner_proto) JSONUnmarshal(bu type DRPCProvisionerClient interface { DRPCConn() drpc.Conn + Shutdown(ctx context.Context, in *Empty) (*Empty, error) Parse(ctx context.Context, in *Parse_Request) (DRPCProvisioner_ParseClient, error) Provision(ctx context.Context, in *Provision_Request) (DRPCProvisioner_ProvisionClient, error) } @@ -52,6 +53,15 @@ func NewDRPCProvisionerClient(cc drpc.Conn) DRPCProvisionerClient { func (c *drpcProvisionerClient) DRPCConn() drpc.Conn { return c.cc } +func (c *drpcProvisionerClient) Shutdown(ctx context.Context, in *Empty) (*Empty, error) { + out := new(Empty) + err := c.cc.Invoke(ctx, "/provisioner.Provisioner/Shutdown", drpcEncoding_File_provisionersdk_proto_provisioner_proto{}, in, out) + if err != nil { + return nil, err + } + return out, nil +} + func (c *drpcProvisionerClient) Parse(ctx context.Context, in *Parse_Request) (DRPCProvisioner_ParseClient, error) { stream, err := c.cc.NewStream(ctx, "/provisioner.Provisioner/Parse", drpcEncoding_File_provisionersdk_proto_provisioner_proto{}) if err != nil { @@ -125,12 +135,17 @@ func (x *drpcProvisioner_ProvisionClient) RecvMsg(m *Provision_Response) error { } type DRPCProvisionerServer interface { + Shutdown(context.Context, *Empty) (*Empty, error) Parse(*Parse_Request, DRPCProvisioner_ParseStream) error Provision(*Provision_Request, DRPCProvisioner_ProvisionStream) error } type DRPCProvisionerUnimplementedServer struct{} +func (s *DRPCProvisionerUnimplementedServer) Shutdown(context.Context, *Empty) (*Empty, error) { + return nil, drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) +} + func (s *DRPCProvisionerUnimplementedServer) Parse(*Parse_Request, DRPCProvisioner_ParseStream) error { return drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) } @@ -141,11 +156,20 @@ func (s *DRPCProvisionerUnimplementedServer) Provision(*Provision_Request, DRPCP type DRPCProvisionerDescription struct{} -func (DRPCProvisionerDescription) NumMethods() int { return 2 } +func (DRPCProvisionerDescription) NumMethods() int { return 3 } func (DRPCProvisionerDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, interface{}, bool) { switch n { case 0: + return "/provisioner.Provisioner/Shutdown", drpcEncoding_File_provisionersdk_proto_provisioner_proto{}, + func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { + return srv.(DRPCProvisionerServer). + Shutdown( + ctx, + in1.(*Empty), + ) + }, DRPCProvisionerServer.Shutdown, true + case 1: return "/provisioner.Provisioner/Parse", drpcEncoding_File_provisionersdk_proto_provisioner_proto{}, func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { return nil, srv.(DRPCProvisionerServer). @@ -154,7 +178,7 @@ func (DRPCProvisionerDescription) Method(n int) (string, drpc.Encoding, drpc.Rec &drpcProvisioner_ParseStream{in2.(drpc.Stream)}, ) }, DRPCProvisionerServer.Parse, true - case 1: + case 2: return "/provisioner.Provisioner/Provision", drpcEncoding_File_provisionersdk_proto_provisioner_proto{}, func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { return nil, srv.(DRPCProvisionerServer). @@ -172,6 +196,22 @@ func DRPCRegisterProvisioner(mux drpc.Mux, impl DRPCProvisionerServer) error { return mux.Register(impl, DRPCProvisionerDescription{}) } +type DRPCProvisioner_ShutdownStream interface { + drpc.Stream + SendAndClose(*Empty) error +} + +type drpcProvisioner_ShutdownStream struct { + drpc.Stream +} + +func (x *drpcProvisioner_ShutdownStream) SendAndClose(m *Empty) error { + if err := x.MsgSend(m, drpcEncoding_File_provisionersdk_proto_provisioner_proto{}); err != nil { + return err + } + return x.CloseSend() +} + type DRPCProvisioner_ParseStream interface { drpc.Stream Send(*Parse_Response) error From dac812d7c21612a2d909b91e924d89ab75d96088 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Sun, 27 Feb 2022 22:01:42 +0000 Subject: [PATCH 14/21] Fix cancel error check --- coderd/provisionerdaemons.go | 1 + provisioner/terraform/serve.go | 2 +- provisionerd/provisionerd_test.go | 4 +--- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/coderd/provisionerdaemons.go b/coderd/provisionerdaemons.go index da0419e7798b1..21c7e220ca853 100644 --- a/coderd/provisionerdaemons.go +++ b/coderd/provisionerdaemons.go @@ -449,6 +449,7 @@ func (server *provisionerdServer) FailJob(ctx context.Context, failJob *proto.Fa if err != nil { return nil, xerrors.Errorf("update workspace history state: %w", err) } + case *proto.FailedJob_ProjectImport_: } return &proto.Empty{}, nil } diff --git a/provisioner/terraform/serve.go b/provisioner/terraform/serve.go index ae1b84eebae33..453e1957c96ff 100644 --- a/provisioner/terraform/serve.go +++ b/provisioner/terraform/serve.go @@ -62,7 +62,7 @@ type terraform struct { } // Shutdown signals to begin graceful shutdown of any running operations. -func (t *terraform) Shutdown(ctx context.Context, _ *proto.Empty) (*proto.Empty, error) { +func (t *terraform) Shutdown(_ context.Context, _ *proto.Empty) (*proto.Empty, error) { t.shutdownCancel() return &proto.Empty{}, nil } diff --git a/provisionerd/provisionerd_test.go b/provisionerd/provisionerd_test.go index 1e482ddefd623..dea91d9fedc2d 100644 --- a/provisionerd/provisionerd_test.go +++ b/provisionerd/provisionerd_test.go @@ -399,15 +399,13 @@ func TestProvisionerd(t *testing.T) { }, provisionerd.Provisioners{ "someprovisioner": createProvisionerClient(t, provisionerTestServer{ provision: func(request *sdkproto.Provision_Request, stream sdkproto.DRPCProvisioner_ProvisionStream) error { - err := stream.Send(&sdkproto.Provision_Response{ + return stream.Send(&sdkproto.Provision_Response{ Type: &sdkproto.Provision_Response_Complete{ Complete: &sdkproto.Provision_Complete{ Error: "some error", }, }, }) - require.NoError(t, err) - return nil }, }), }) From bc7d95ff08b1e71356767e7eacc75e6a57adb10b Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 28 Feb 2022 02:59:31 +0000 Subject: [PATCH 15/21] feat: Add destroy to workspace provision job This enables the full flow of create/update/delete. --- coderd/provisionerdaemons.go | 2 ++ provisioner/terraform/provision.go | 7 ++-- provisionersdk/proto/provisioner.pb.go | 50 ++++++++++++++------------ provisionersdk/proto/provisioner.proto | 1 + 4 files changed, 35 insertions(+), 25 deletions(-) diff --git a/coderd/provisionerdaemons.go b/coderd/provisionerdaemons.go index 21c7e220ca853..d30b876b99547 100644 --- a/coderd/provisionerdaemons.go +++ b/coderd/provisionerdaemons.go @@ -693,6 +693,8 @@ func convertWorkspaceTransition(transition database.WorkspaceTransition) (sdkpro return sdkproto.WorkspaceTransition_START, nil case database.WorkspaceTransitionStop: return sdkproto.WorkspaceTransition_STOP, nil + case database.WorkspaceTransitionDelete: + return sdkproto.WorkspaceTransition_DESTROY, nil default: return 0, xerrors.Errorf("unrecognized transition: %q", transition) } diff --git a/provisioner/terraform/provision.go b/provisioner/terraform/provision.go index 8537ed516d0af..61335b91120ba 100644 --- a/provisioner/terraform/provision.go +++ b/provisioner/terraform/provision.go @@ -317,7 +317,7 @@ func (t *terraform) runTerraformApply(ctx context.Context, terraform *tfexec.Ter }() t.logger.Debug(ctx, "running apply", slog.F("vars", len(vars)), slog.F("env", len(env))) - err := runApplyCommand(ctx, t.shutdownCtx, terraform.ExecPath(), terraform.WorkingDir(), writer, env, vars) + err := runApplyCommand(ctx, t.shutdownCtx, request.Metadata.WorkspaceTransition, terraform.ExecPath(), terraform.WorkingDir(), writer, env, vars) if err != nil { errorMessage := err.Error() // Terraform can fail and apply and still need to store it's state. @@ -440,7 +440,7 @@ func (t *terraform) runTerraformApply(ctx context.Context, terraform *tfexec.Ter // This couldn't use terraform-exec, because it doesn't support cancellation, and there didn't appear // to be a straight-forward way to add it. -func runApplyCommand(ctx, shutdownCtx context.Context, bin, dir string, stdout io.Writer, env, vars []string) error { +func runApplyCommand(ctx, shutdownCtx context.Context, transition proto.WorkspaceTransition, bin, dir string, stdout io.Writer, env, vars []string) error { args := []string{ "apply", "-no-color", @@ -449,6 +449,9 @@ func runApplyCommand(ctx, shutdownCtx context.Context, bin, dir string, stdout i "-json", "-refresh=true", } + if transition == proto.WorkspaceTransition_DESTROY { + args = append(args, "-destroy") + } for _, variable := range vars { args = append(args, "-var", variable) } diff --git a/provisionersdk/proto/provisioner.pb.go b/provisionersdk/proto/provisioner.pb.go index d6bbf1727c96f..dfe499b6ba685 100644 --- a/provisionersdk/proto/provisioner.pb.go +++ b/provisionersdk/proto/provisioner.pb.go @@ -79,8 +79,9 @@ func (LogLevel) EnumDescriptor() ([]byte, []int) { type WorkspaceTransition int32 const ( - WorkspaceTransition_START WorkspaceTransition = 0 - WorkspaceTransition_STOP WorkspaceTransition = 1 + WorkspaceTransition_START WorkspaceTransition = 0 + WorkspaceTransition_STOP WorkspaceTransition = 1 + WorkspaceTransition_DESTROY WorkspaceTransition = 2 ) // Enum value maps for WorkspaceTransition. @@ -88,10 +89,12 @@ var ( WorkspaceTransition_name = map[int32]string{ 0: "START", 1: "STOP", + 2: "DESTROY", } WorkspaceTransition_value = map[string]int32{ - "START": 0, - "STOP": 1, + "START": 0, + "STOP": 1, + "DESTROY": 2, } ) @@ -1558,27 +1561,28 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 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, 0x2a, 0x2a, 0x0a, + 0x10, 0x03, 0x12, 0x09, 0x0a, 0x05, 0x45, 0x52, 0x52, 0x4f, 0x52, 0x10, 0x04, 0x2a, 0x37, 0x0a, 0x13, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x54, 0x72, 0x61, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x09, 0x0a, 0x05, 0x53, 0x54, 0x41, 0x52, 0x54, 0x10, 0x00, 0x12, - 0x08, 0x0a, 0x04, 0x53, 0x54, 0x4f, 0x50, 0x10, 0x01, 0x32, 0xd5, 0x01, 0x0a, 0x0b, 0x50, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x08, 0x53, 0x68, 0x75, - 0x74, 0x64, 0x6f, 0x77, 0x6e, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 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, + 0x08, 0x0a, 0x04, 0x53, 0x54, 0x4f, 0x50, 0x10, 0x01, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x53, + 0x54, 0x52, 0x4f, 0x59, 0x10, 0x02, 0x32, 0xd5, 0x01, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x12, 0x32, 0x0a, 0x08, 0x53, 0x68, 0x75, 0x74, 0x64, 0x6f, + 0x77, 0x6e, 0x12, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x1a, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 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 ( diff --git a/provisionersdk/proto/provisioner.proto b/provisionersdk/proto/provisioner.proto index 4a1c28b36a4f9..4ba3f2279a242 100644 --- a/provisionersdk/proto/provisioner.proto +++ b/provisionersdk/proto/provisioner.proto @@ -109,6 +109,7 @@ message Parse { enum WorkspaceTransition { START = 0; STOP = 1; + DESTROY = 2; } // Provision consumes source-code from a directory to produce resources. From 0d3de1870c6dda29bc0ba36aad6fd01a8e4b68c5 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 28 Feb 2022 03:28:43 +0000 Subject: [PATCH 16/21] Add test values --- Makefile | 2 +- coderd/cmd/root.go | 7 ++++++- provisioner/terraform/provision.go | 3 ++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index f3e1bfc8b0317..fdff105a2982f 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ GOARCH=$(shell go env GOARCH) bin/coder: mkdir -p bin - GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o bin/coder-$(GOOS)-$(GOARCH) cmd/coder/main.go + CGO_ENABLED=0 GOOS=$(GOOS) GOARCH=$(GOARCH) go build -o bin/coder-$(GOOS)-$(GOARCH) cmd/coder/main.go .PHONY: bin/coder bin/coderd: diff --git a/coderd/cmd/root.go b/coderd/cmd/root.go index 162390898aa77..9687ad7ad9573 100644 --- a/coderd/cmd/root.go +++ b/coderd/cmd/root.go @@ -37,8 +37,13 @@ func Root() *cobra.Command { Scheme: "http", Host: address, } + realAccessURL, err := url.Parse("https://v2--kyle.master.cdr.dev/") + if err != nil { + return xerrors.Errorf("parse real access url: %s", err) + } + handler, closeCoderd := coderd.New(&coderd.Options{ - AccessURL: accessURL, + AccessURL: realAccessURL, Logger: logger, Database: databasefake.New(), Pubsub: database.NewPubsubInMemory(), diff --git a/provisioner/terraform/provision.go b/provisioner/terraform/provision.go index 61335b91120ba..4e8eb5864d7ce 100644 --- a/provisioner/terraform/provision.go +++ b/provisioner/terraform/provision.go @@ -196,9 +196,10 @@ func (t *terraform) runTerraformPlan(ctx context.Context, terraform *tfexec.Terr } switch authTypeValue { case "google-instance-identity": + instanceID, _ := block["instance_id"].ConstantValue.(string) agent.Auth = &proto.Agent_GoogleInstanceIdentity{ GoogleInstanceIdentity: &proto.GoogleInstanceIdentityAuth{ - InstanceId: block["instance_id"].ConstantValue.(string), + InstanceId: instanceID, }, } default: From 3f99334ed2acb73634940a49614d4bea51e27689 Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 28 Feb 2022 05:40:25 +0000 Subject: [PATCH 17/21] Fix plan resource parsing --- .vscode/settings.json | 1 + cli/projectcreate.go | 15 +++--- cli/projects.go | 3 ++ coderd/projectimport.go | 6 ++- coderd/provisionerjobs.go | 18 ++++++- provisioner/terraform/provision.go | 65 ++++++++++++++++++------- provisioner/terraform/provision_test.go | 9 ++-- 7 files changed, 84 insertions(+), 33 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 32e7a2ddf4e34..f3feca422fdd5 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -62,6 +62,7 @@ "stretchr", "tcpip", "tfexec", + "tfjson", "tfstate", "unconvert", "webrtc", diff --git a/cli/projectcreate.go b/cli/projectcreate.go index a1e5027c26715..454833299514b 100644 --- a/cli/projectcreate.go +++ b/cli/projectcreate.go @@ -71,13 +71,6 @@ func projectCreate() *cobra.Command { if err != nil { return err } - project, err := client.CreateProject(cmd.Context(), organization.Name, coderd.CreateProjectRequest{ - Name: name, - VersionImportJobID: job.ID, - }) - if err != nil { - return err - } _, err = prompt(cmd, &promptui.Prompt{ Label: "Create project?", @@ -91,6 +84,14 @@ func projectCreate() *cobra.Command { return err } + project, err := client.CreateProject(cmd.Context(), organization.Name, coderd.CreateProjectRequest{ + Name: name, + VersionImportJobID: job.ID, + }) + if err != nil { + return err + } + _, _ = fmt.Fprintf(cmd.OutOrStdout(), "%s The %s project has been created!\n", caret, color.HiCyanString(project.Name)) _, err = prompt(cmd, &promptui.Prompt{ Label: "Create a new workspace?", diff --git a/cli/projects.go b/cli/projects.go index 0f04dc05cd259..9519e4f238313 100644 --- a/cli/projects.go +++ b/cli/projects.go @@ -78,6 +78,9 @@ func displayProjectImportInfo(cmd *cobra.Command, parameterSchemas []coderd.Para if resource.Transition == database.WorkspaceTransitionStop { transition = color.HiRedString("stop") } + if resource.AgentID != nil { + transition += " with agent" + } _, _ = fmt.Fprintf(cmd.OutOrStdout(), " %s %s on %s\n\n", color.HiCyanString(resource.Type), color.HiCyanString(resource.Name), transition) } return nil diff --git a/coderd/projectimport.go b/coderd/projectimport.go index 5ece718c99a90..1ace4764219b3 100644 --- a/coderd/projectimport.go +++ b/coderd/projectimport.go @@ -177,6 +177,10 @@ func (api *api) projectImportJobResourcesByID(rw http.ResponseWriter, r *http.Re if resources == nil { resources = []database.ProvisionerJobResource{} } + apiResources := make([]ProvisionerJobResource, 0) + for _, resource := range resources { + apiResources = append(apiResources, convertProvisionerJobResource(resource)) + } render.Status(r, http.StatusOK) - render.JSON(rw, r, resources) + render.JSON(rw, r, apiResources) } diff --git a/coderd/provisionerjobs.go b/coderd/provisionerjobs.go index 8c343256f15ee..e8ac236900b0c 100644 --- a/coderd/provisionerjobs.go +++ b/coderd/provisionerjobs.go @@ -61,9 +61,10 @@ type ProvisionerJobResource struct { ID uuid.UUID `json:"id"` CreatedAt time.Time `json:"created_at"` JobID uuid.UUID `json:"job_id"` - Transition database.WorkspaceTransition `json:"workspace_transition"` + Transition database.WorkspaceTransition `json:"transition"` Type string `json:"type"` Name string `json:"name"` + AgentID *uuid.UUID `json:"agent_id,omitempty"` } type ProvisionerJobAgent struct { @@ -291,6 +292,21 @@ func convertProvisionerJob(provisionerJob database.ProvisionerJob) ProvisionerJo return job } +func convertProvisionerJobResource(resource database.ProvisionerJobResource) ProvisionerJobResource { + apiResource := ProvisionerJobResource{ + ID: resource.ID, + CreatedAt: resource.CreatedAt, + JobID: resource.JobID, + Transition: resource.Transition, + Type: resource.Type, + Name: resource.Name, + } + if resource.AgentID.Valid { + apiResource.AgentID = &resource.AgentID.UUID + } + return apiResource +} + func provisionerJobLogsChannel(jobID uuid.UUID) string { return fmt.Sprintf("provisioner-log-logs:%s", jobID) } diff --git a/provisioner/terraform/provision.go b/provisioner/terraform/provision.go index 4e8eb5864d7ce..8cf03f581d5c6 100644 --- a/provisioner/terraform/provision.go +++ b/provisioner/terraform/provision.go @@ -13,6 +13,7 @@ import ( "strings" "github.com/hashicorp/terraform-exec/tfexec" + tfjson "github.com/hashicorp/terraform-json" "github.com/mitchellh/mapstructure" "golang.org/x/xerrors" @@ -75,10 +76,13 @@ 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{ - "CODER_URL": request.Metadata.CoderUrl, - "CODER_WORKSPACE_TRANSITION": strings.ToLower(request.Metadata.WorkspaceTransition.String()), + env := map[string]string{} + for _, envEntry := range os.Environ() { + parts := strings.SplitN(envEntry, "=", 2) + env[parts[0]] = parts[1] } + env["CODER_URL"] = request.Metadata.CoderUrl + env["CODER_WORKSPACE_TRANSITION"] = strings.ToLower(request.Metadata.WorkspaceTransition.String()) planfilePath := filepath.Join(request.Directory, "terraform.tfplan") options := []tfexec.PlanOption{tfexec.JSON(true), tfexec.Out(planfilePath)} for _, param := range request.ParameterValues { @@ -159,9 +163,31 @@ func (t *terraform) runTerraformPlan(ctx context.Context, terraform *tfexec.Terr _ = reader.Close() <-closeChan + // Maps resource dependencies to expression references. + // This is *required* for a plan, because "DependsOn" + // does not propagate. + resourceDependencies := map[string][]string{} + for _, resource := range plan.Config.RootModule.Resources { + if resource.Expressions == nil { + resource.Expressions = map[string]*tfjson.Expression{} + } + // Count expression is separated for logical reasons, + // but it's simpler syntactically for us to combine here. + if resource.CountExpression != nil { + resource.Expressions["count"] = resource.CountExpression + } + for _, expression := range resource.Expressions { + dependencies, exists := resourceDependencies[resource.Address] + if !exists { + dependencies = []string{} + } + dependencies = append(dependencies, expression.References...) + resourceDependencies[resource.Address] = dependencies + } + } + 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 { @@ -209,31 +235,33 @@ func (t *terraform) runTerraformPlan(ctx context.Context, terraform *tfexec.Terr } } - resourceKey := strings.Join([]string{resource.Type, resource.Name}, ".") - agents[resourceKey] = agent - agentDepends[resourceKey] = resource.DependsOn + agents[resource.Address] = agent } - for _, resource := range plan.Config.RootModule.Resources { + for _, resource := range plan.PlannedValues.RootModule.Resources { if resource.Type == "coder_agent" { continue } + // The resource address on planned values can include the indexed + // value like "[0]", but the config doesn't have these, and we don't + // care which index the resource is. + resourceAddress := fmt.Sprintf("%s.%s", resource.Type, resource.Name) var agent *proto.Agent // Associate resources that depend on an agent. - for _, dep := range resource.DependsOn { + for _, dependency := range resourceDependencies[resourceAddress] { var has bool - agent, has = agents[dep] + agent, has = agents[dependency] 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}, ".") { + for agentAddress := range agents { + for _, depend := range resourceDependencies[agentAddress] { + if depend != resource.Address { continue } - agent = agents[agentKey] + agent = agents[agentAddress] break } } @@ -255,10 +283,11 @@ func (t *terraform) runTerraformPlan(ctx context.Context, terraform *tfexec.Terr } func (t *terraform) runTerraformApply(ctx context.Context, terraform *tfexec.Terraform, request *proto.Provision_Request, stream proto.DRPCProvisioner_ProvisionStream, statefilePath string) error { - env := []string{ - "CODER_URL=" + request.Metadata.CoderUrl, - "CODER_WORKSPACE_TRANSITION=" + strings.ToLower(request.Metadata.WorkspaceTransition.String()), - } + env := os.Environ() + env = append(env, + "CODER_URL="+request.Metadata.CoderUrl, + "CODER_WORKSPACE_TRANSITION="+strings.ToLower(request.Metadata.WorkspaceTransition.String()), + ) vars := []string{} for _, param := range request.ParameterValues { switch param.DestinationScheme { diff --git a/provisioner/terraform/provision_test.go b/provisioner/terraform/provision_test.go index edaf1aff0c1cf..d1c34fe3d56ba 100644 --- a/provisioner/terraform/provision_test.go +++ b/provisioner/terraform/provision_test.go @@ -235,11 +235,10 @@ provider "coder" { Files: map[string]string{ "main.tf": provider + ` resource "coder_agent" "A" { + count = 1 } resource "null_resource" "A" { - depends_on = [ - coder_agent.A - ] + count = length(coder_agent.A) }`, }, Request: &proto.Provision_Request{ @@ -266,9 +265,7 @@ provider "coder" { Files: map[string]string{ "main.tf": provider + ` resource "coder_agent" "A" { - depends_on = [ - null_resource.A - ] + count = length(null_resource.A) auth { type = "google-instance-identity" instance_id = "an-instance" From 74d8ae4aadae0f743d787755316fae322b47a3ce Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 28 Feb 2022 14:51:15 +0000 Subject: [PATCH 18/21] Rename workspace agent to auth --- cli/workspaceagent.go | 14 ++++++++++++++ cli/workspaces.go | 1 + .../{workspaceagent.go => workspaceagentauth.go} | 0 ...aceagent_test.go => workspaceagentauth_test.go} | 0 4 files changed, 15 insertions(+) create mode 100644 cli/workspaceagent.go rename coderd/{workspaceagent.go => workspaceagentauth.go} (100%) rename coderd/{workspaceagent_test.go => workspaceagentauth_test.go} (100%) diff --git a/cli/workspaceagent.go b/cli/workspaceagent.go new file mode 100644 index 0000000000000..8dc305e498aa8 --- /dev/null +++ b/cli/workspaceagent.go @@ -0,0 +1,14 @@ +package cli + +import ( + "github.com/spf13/cobra" +) + +func workspaceAgent() *cobra.Command { + return &cobra.Command{ + Use: "agent", + RunE: func(cmd *cobra.Command, args []string) error { + return nil + }, + } +} diff --git a/cli/workspaces.go b/cli/workspaces.go index d405f00cea88b..b470fc7df1c60 100644 --- a/cli/workspaces.go +++ b/cli/workspaces.go @@ -6,6 +6,7 @@ func workspaces() *cobra.Command { cmd := &cobra.Command{ Use: "workspaces", } + cmd.AddCommand(workspaceAgent()) cmd.AddCommand(workspaceCreate()) return cmd diff --git a/coderd/workspaceagent.go b/coderd/workspaceagentauth.go similarity index 100% rename from coderd/workspaceagent.go rename to coderd/workspaceagentauth.go diff --git a/coderd/workspaceagent_test.go b/coderd/workspaceagentauth_test.go similarity index 100% rename from coderd/workspaceagent_test.go rename to coderd/workspaceagentauth_test.go From e4b51dc03c4982c47ae59e91b1a9190bd4cdb37c Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 28 Feb 2022 17:04:22 +0000 Subject: [PATCH 19/21] Add database functions for authenticating the agent --- agent/agent.go | 9 ++ coderd/workspaceagent.go | 153 ++++++++++++++++++++++++++ database/databasefake/databasefake.go | 29 +++++ database/querier.go | 2 + database/query.sql | 18 +++ database/query.sql.go | 55 +++++++++ go.mod | 2 +- httpmw/workspaceagent.go | 64 +++++++++++ httpmw/workspaceagent_test.go | 73 ++++++++++++ 9 files changed, 404 insertions(+), 1 deletion(-) create mode 100644 coderd/workspaceagent.go create mode 100644 httpmw/workspaceagent.go create mode 100644 httpmw/workspaceagent_test.go diff --git a/agent/agent.go b/agent/agent.go index 285efe3dc9836..723a8430609c5 100644 --- a/agent/agent.go +++ b/agent/agent.go @@ -25,6 +25,7 @@ import ( "golang.org/x/xerrors" ) +// DialSSH creates an SSH DataChannel on the connection provided. func DialSSH(conn *peer.Conn) (net.Conn, error) { channel, err := conn.Dial(context.Background(), "ssh", &peer.ChannelOptions{ Protocol: "ssh", @@ -35,6 +36,7 @@ func DialSSH(conn *peer.Conn) (net.Conn, error) { return channel.NetConn(), nil } +// DialSSHClient wraps the DialSSH function with a Go SSH client. func DialSSHClient(conn *peer.Conn) (*gossh.Client, error) { netConn, err := DialSSH(conn) if err != nil { @@ -59,6 +61,13 @@ type Options struct { Logger slog.Logger } +// Dialer to return the peerbroker.Listener, but that hinges on +// a proper authentication token. If it fails to dial for that +// reason, we should check the API error and renegotiate a new +// authentication method. +// +// This also needs to update it's own metadata and such. + type Dialer func(ctx context.Context) (*peerbroker.Listener, error) func New(dialer Dialer, options *Options) io.Closer { diff --git a/coderd/workspaceagent.go b/coderd/workspaceagent.go new file mode 100644 index 0000000000000..9ea51dbc17570 --- /dev/null +++ b/coderd/workspaceagent.go @@ -0,0 +1,153 @@ +package coderd + +import ( + "database/sql" + "fmt" + "io" + "net/http" + "time" + + "github.com/hashicorp/yamux" + "nhooyr.io/websocket" + + "cdr.dev/slog" + "github.com/coder/coder/database" + "github.com/coder/coder/httpapi" + "github.com/coder/coder/httpmw" + "github.com/coder/coder/peerbroker" + "github.com/coder/coder/peerbroker/proto" + "github.com/coder/coder/provisionersdk" +) + +type AgentResourceMetadata struct { + MemoryTotal uint64 `json:"memory_total"` + DiskTotal uint64 `json:"disk_total"` + CPUCores uint64 `json:"cpu_cores"` + CPUModel string `json:"cpu_model"` + CPUMhz float64 `json:"cpu_mhz"` +} + +type AgentInstanceMetadata struct { + JailOrchestrator string `json:"jail_orchestrator"` + OperatingSystem string `json:"operating_system"` + Platform string `json:"platform"` + PlatformFamily string `json:"platform_family"` + KernelVersion string `json:"kernel_version"` + KernelArchitecture string `json:"kernel_architecture"` + Cloud string `json:"cloud"` + Jail string `json:"jail"` + VNC bool `json:"vnc"` +} + +func (api *api) workspaceAgentUpdate() { + +} + +func (api *api) workspaceAgentConnectByResource(rw http.ResponseWriter, r *http.Request) { + api.websocketWaitGroup.Add(1) + defer api.websocketWaitGroup.Done() + + agent := httpmw.WorkspaceAgent(r) + if !agent.UpdatedAt.Valid { + httpapi.Write(rw, http.StatusPreconditionRequired, httpapi.Response{ + Message: "Agent hasn't connected yet!", + }) + return + } + + conn, err := websocket.Accept(rw, r, &websocket.AcceptOptions{ + CompressionMode: websocket.CompressionDisabled, + }) + if err != nil { + httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{ + Message: fmt.Sprintf("accept websocket: %s", err), + }) + return + } + defer func() { + _ = conn.Close(websocket.StatusNormalClosure, "") + }() + config := yamux.DefaultConfig() + config.LogOutput = io.Discard + session, err := yamux.Server(websocket.NetConn(r.Context(), conn, websocket.MessageBinary), config) + if err != nil { + _ = conn.Close(websocket.StatusAbnormalClosure, err.Error()) + return + } + err = peerbroker.ProxyListen(r.Context(), session, peerbroker.ProxyOptions{ + ChannelID: resource.WorkspaceAgentID.UUID.String(), + Logger: api.Logger.Named("peerbroker-proxy-dial"), + Pubsub: api.Pubsub, + }) + if err != nil { + _ = conn.Close(websocket.StatusInternalError, fmt.Sprintf("serve: %s", err)) + return + } +} + +func (api *api) workspaceAgentServe(rw http.ResponseWriter, r *http.Request) { + api.websocketWaitGroup.Add(1) + defer api.websocketWaitGroup.Done() + + workspaceAgent := httpmw.WorkspaceAgent(r) + conn, err := websocket.Accept(rw, r, &websocket.AcceptOptions{ + CompressionMode: websocket.CompressionDisabled, + }) + if err != nil { + httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{ + Message: fmt.Sprintf("accept websocket: %s", err), + }) + return + } + defer func() { + _ = conn.Close(websocket.StatusNormalClosure, "") + }() + config := yamux.DefaultConfig() + config.LogOutput = io.Discard + session, err := yamux.Server(websocket.NetConn(r.Context(), conn, websocket.MessageBinary), config) + if err != nil { + _ = conn.Close(websocket.StatusAbnormalClosure, err.Error()) + return + } + closer, err := peerbroker.ProxyDial(proto.NewDRPCPeerBrokerClient(provisionersdk.Conn(session)), peerbroker.ProxyOptions{ + ChannelID: workspaceAgent.ID.String(), + Pubsub: api.Pubsub, + Logger: api.Logger.Named("peerbroker-proxy-listen"), + }) + if err != nil { + _ = conn.Close(websocket.StatusAbnormalClosure, err.Error()) + return + } + + err = api.Database.UpdateWorkspaceAgentByID(r.Context(), database.UpdateWorkspaceAgentByIDParams{ + ID: workspaceAgent.ID, + UpdatedAt: sql.NullTime{ + Time: database.Now(), + Valid: true, + }, + }) + if err != nil { + _ = conn.Close(websocket.StatusAbnormalClosure, err.Error()) + return + } + defer closer.Close() + ticker := time.NewTicker(5 * time.Second) + for { + select { + case <-ticker.C: + err = api.Database.UpdateWorkspaceAgentByID(r.Context(), database.UpdateWorkspaceAgentByIDParams{ + ID: workspaceAgent.ID, + UpdatedAt: sql.NullTime{ + Time: database.Now(), + Valid: true, + }, + }) + if err != nil { + api.Logger.Error(r.Context(), "update workspace agent by id", slog.Error(err), slog.F("id", workspaceAgent.ID.String())) + return + } + case <-r.Context().Done(): + return + } + } +} diff --git a/database/databasefake/databasefake.go b/database/databasefake/databasefake.go index 1e09a2a74f4f9..42f5690ef76ca 100644 --- a/database/databasefake/databasefake.go +++ b/database/databasefake/databasefake.go @@ -522,6 +522,18 @@ func (q *fakeQuerier) GetProvisionerJobAgentByInstanceID(_ context.Context, inst return database.ProvisionerJobAgent{}, sql.ErrNoRows } +func (q *fakeQuerier) GetProvisionerJobAgentByAuthToken(ctx context.Context, authToken uuid.UUID) (database.ProvisionerJobAgent, error) { + q.mutex.Lock() + defer q.mutex.Unlock() + + for _, agent := range q.provisionerJobAgent { + if agent.AuthToken.String() == authToken.String() { + return agent, nil + } + } + return database.ProvisionerJobAgent{}, sql.ErrNoRows +} + func (q *fakeQuerier) GetProvisionerJobAgentsByResourceIDs(_ context.Context, ids []uuid.UUID) ([]database.ProvisionerJobAgent, error) { q.mutex.Lock() defer q.mutex.Unlock() @@ -956,6 +968,23 @@ func (q *fakeQuerier) UpdateProvisionerDaemonByID(_ context.Context, arg databas return sql.ErrNoRows } +func (q *fakeQuerier) UpdateProvisionerJobAgentByID(ctx context.Context, arg database.UpdateProvisionerJobAgentByIDParams) error { + q.mutex.Lock() + defer q.mutex.Unlock() + + for index, agent := range q.provisionerJobAgent { + if arg.ID.String() != agent.ID.String() { + continue + } + agent.UpdatedAt = arg.UpdatedAt + agent.InstanceMetadata = arg.InstanceMetadata + agent.ResourceMetadata = arg.ResourceMetadata + q.provisionerJobAgent[index] = agent + return nil + } + return sql.ErrNoRows +} + func (q *fakeQuerier) UpdateProvisionerJobByID(_ context.Context, arg database.UpdateProvisionerJobByIDParams) error { q.mutex.Lock() defer q.mutex.Unlock() diff --git a/database/querier.go b/database/querier.go index faa24ac3a4970..9e1c4ed6c143f 100644 --- a/database/querier.go +++ b/database/querier.go @@ -26,6 +26,7 @@ type querier interface { GetProjectsByOrganizationIDs(ctx context.Context, ids []string) ([]Project, error) GetProvisionerDaemonByID(ctx context.Context, id uuid.UUID) (ProvisionerDaemon, error) GetProvisionerDaemons(ctx context.Context) ([]ProvisionerDaemon, error) + GetProvisionerJobAgentByAuthToken(ctx context.Context, authToken uuid.UUID) (ProvisionerJobAgent, error) GetProvisionerJobAgentByInstanceID(ctx context.Context, authInstanceID string) (ProvisionerJobAgent, error) GetProvisionerJobAgentsByResourceIDs(ctx context.Context, ids []uuid.UUID) ([]ProvisionerJobAgent, error) GetProvisionerJobByID(ctx context.Context, id uuid.UUID) (ProvisionerJob, error) @@ -62,6 +63,7 @@ type querier interface { InsertWorkspaceHistory(ctx context.Context, arg InsertWorkspaceHistoryParams) (WorkspaceHistory, error) UpdateAPIKeyByID(ctx context.Context, arg UpdateAPIKeyByIDParams) error UpdateProvisionerDaemonByID(ctx context.Context, arg UpdateProvisionerDaemonByIDParams) error + UpdateProvisionerJobAgentByID(ctx context.Context, arg UpdateProvisionerJobAgentByIDParams) error UpdateProvisionerJobByID(ctx context.Context, arg UpdateProvisionerJobByIDParams) error UpdateProvisionerJobWithCompleteByID(ctx context.Context, arg UpdateProvisionerJobWithCompleteByIDParams) error UpdateWorkspaceHistoryByID(ctx context.Context, arg UpdateWorkspaceHistoryByIDParams) error diff --git a/database/query.sql b/database/query.sql index eabea0c43d709..1b81b9d3dce9e 100644 --- a/database/query.sql +++ b/database/query.sql @@ -226,6 +226,14 @@ SELECT FROM provisioner_daemon; +-- name: GetProvisionerJobAgentByAuthToken :one +SELECT + * +FROM + provisioner_job_agent +WHERE + auth_token = $1; + -- name: GetProvisionerJobAgentByInstanceID :one SELECT * @@ -624,6 +632,16 @@ SET WHERE id = $1; +-- name: UpdateProvisionerJobAgentByID :exec +UPDATE + provisioner_job_agent +SET + updated_at = $2, + instance_metadata = $3, + resource_metadata = $4 +WHERE + id = $1; + -- name: UpdateProvisionerDaemonByID :exec UPDATE provisioner_daemon diff --git a/database/query.sql.go b/database/query.sql.go index c74ecbcbf94e5..962c799f6a1ed 100644 --- a/database/query.sql.go +++ b/database/query.sql.go @@ -617,6 +617,33 @@ func (q *sqlQuerier) GetProvisionerDaemons(ctx context.Context) ([]ProvisionerDa return items, nil } +const getProvisionerJobAgentByAuthToken = `-- name: GetProvisionerJobAgentByAuthToken :one +SELECT + id, created_at, updated_at, resource_id, auth_token, auth_instance_id, environment_variables, startup_script, instance_metadata, resource_metadata +FROM + provisioner_job_agent +WHERE + auth_token = $1 +` + +func (q *sqlQuerier) GetProvisionerJobAgentByAuthToken(ctx context.Context, authToken uuid.UUID) (ProvisionerJobAgent, error) { + row := q.db.QueryRowContext(ctx, getProvisionerJobAgentByAuthToken, authToken) + var i ProvisionerJobAgent + err := row.Scan( + &i.ID, + &i.CreatedAt, + &i.UpdatedAt, + &i.ResourceID, + &i.AuthToken, + &i.AuthInstanceID, + &i.EnvironmentVariables, + &i.StartupScript, + &i.InstanceMetadata, + &i.ResourceMetadata, + ) + return i, err +} + const getProvisionerJobAgentByInstanceID = `-- name: GetProvisionerJobAgentByInstanceID :one SELECT id, created_at, updated_at, resource_id, auth_token, auth_instance_id, environment_variables, startup_script, instance_metadata, resource_metadata @@ -2207,6 +2234,34 @@ func (q *sqlQuerier) UpdateProvisionerDaemonByID(ctx context.Context, arg Update return err } +const updateProvisionerJobAgentByID = `-- name: UpdateProvisionerJobAgentByID :exec +UPDATE + provisioner_job_agent +SET + updated_at = $2, + instance_metadata = $3, + resource_metadata = $4 +WHERE + id = $1 +` + +type UpdateProvisionerJobAgentByIDParams struct { + ID uuid.UUID `db:"id" json:"id"` + UpdatedAt sql.NullTime `db:"updated_at" json:"updated_at"` + InstanceMetadata pqtype.NullRawMessage `db:"instance_metadata" json:"instance_metadata"` + ResourceMetadata pqtype.NullRawMessage `db:"resource_metadata" json:"resource_metadata"` +} + +func (q *sqlQuerier) UpdateProvisionerJobAgentByID(ctx context.Context, arg UpdateProvisionerJobAgentByIDParams) error { + _, err := q.db.ExecContext(ctx, updateProvisionerJobAgentByID, + arg.ID, + arg.UpdatedAt, + arg.InstanceMetadata, + arg.ResourceMetadata, + ) + return err +} + const updateProvisionerJobByID = `-- name: UpdateProvisionerJobByID :exec UPDATE provisioner_job diff --git a/go.mod b/go.mod index 1180eba9f01cc..d41f89e52ea94 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-json v0.13.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 @@ -109,7 +110,6 @@ require ( 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 diff --git a/httpmw/workspaceagent.go b/httpmw/workspaceagent.go new file mode 100644 index 0000000000000..bce1cc92cab56 --- /dev/null +++ b/httpmw/workspaceagent.go @@ -0,0 +1,64 @@ +package httpmw + +import ( + "context" + "database/sql" + "errors" + "fmt" + "net/http" + + "github.com/coder/coder/database" + "github.com/coder/coder/httpapi" + "github.com/google/uuid" +) + +type workspaceAgentContextKey struct{} + +// WorkspaceAgent returns the workspace agent from the ExtractWorkspaceAgent handler. +func WorkspaceAgent(r *http.Request) database.ProvisionerJobAgent { + user, ok := r.Context().Value(workspaceAgentContextKey{}).(database.ProvisionerJobAgent) + if !ok { + panic("developer error: workspace agent middleware not provided") + } + return user +} + +// ExtractWorkspaceAgent requires authentication using a valid agent token. +func ExtractWorkspaceAgent(db database.Store) func(http.Handler) http.Handler { + return func(next http.Handler) http.Handler { + return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + cookie, err := r.Cookie(AuthCookie) + if err != nil { + httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{ + Message: fmt.Sprintf("%q cookie must be provided", AuthCookie), + }) + return + } + token, err := uuid.Parse(cookie.Value) + if err != nil { + httpapi.Write(rw, http.StatusBadRequest, httpapi.Response{ + Message: fmt.Sprintf("parse token: %s", err), + }) + return + } + workspaceAgent, err := db.GetProvisionerJobAgentByAuthToken(r.Context(), token) + if errors.Is(err, sql.ErrNoRows) { + if errors.Is(err, sql.ErrNoRows) { + httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{ + Message: "agent token is invalid", + }) + return + } + } + if err != nil { + httpapi.Write(rw, http.StatusInternalServerError, httpapi.Response{ + Message: fmt.Sprintf("get workspace agent: %s", err), + }) + return + } + + ctx := context.WithValue(r.Context(), workspaceAgentContextKey{}, workspaceAgent) + next.ServeHTTP(rw, r.WithContext(ctx)) + }) + } +} diff --git a/httpmw/workspaceagent_test.go b/httpmw/workspaceagent_test.go new file mode 100644 index 0000000000000..b36d74c9c23dc --- /dev/null +++ b/httpmw/workspaceagent_test.go @@ -0,0 +1,73 @@ +package httpmw_test + +import ( + "context" + "net/http" + "net/http/httptest" + "testing" + + "github.com/go-chi/chi/v5" + "github.com/google/uuid" + "github.com/stretchr/testify/require" + + "github.com/coder/coder/database" + "github.com/coder/coder/database/databasefake" + "github.com/coder/coder/httpmw" +) + +func TestWorkspaceAgent(t *testing.T) { + t.Parallel() + + setup := func(db database.Store) (*http.Request, uuid.UUID) { + token := uuid.New() + r := httptest.NewRequest("GET", "/", nil) + r.AddCookie(&http.Cookie{ + Name: httpmw.AuthCookie, + Value: token.String(), + }) + return r, token + } + + t.Run("None", func(t *testing.T) { + t.Parallel() + db := databasefake.New() + rtr := chi.NewRouter() + rtr.Use( + httpmw.ExtractWorkspaceAgent(db), + ) + rtr.Get("/", nil) + r, _ := setup(db) + rw := httptest.NewRecorder() + rtr.ServeHTTP(rw, r) + + res := rw.Result() + defer res.Body.Close() + require.Equal(t, http.StatusUnauthorized, res.StatusCode) + }) + + t.Run("Found", func(t *testing.T) { + t.Parallel() + db := databasefake.New() + rtr := chi.NewRouter() + rtr.Use( + httpmw.ExtractWorkspaceAgent(db), + ) + rtr.Get("/", func(rw http.ResponseWriter, r *http.Request) { + _ = httpmw.WorkspaceAgent(r) + rw.WriteHeader(http.StatusOK) + }) + r, token := setup(db) + _, err := db.InsertProvisionerJobAgent(context.Background(), database.InsertProvisionerJobAgentParams{ + ID: uuid.New(), + AuthToken: token, + }) + require.NoError(t, err) + require.NoError(t, err) + rw := httptest.NewRecorder() + rtr.ServeHTTP(rw, r) + + res := rw.Result() + defer res.Body.Close() + require.Equal(t, http.StatusOK, res.StatusCode) + }) +} From 07f21aa69308cee830785286d86e6007b64728cb Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 28 Feb 2022 17:30:46 +0000 Subject: [PATCH 20/21] Rename workspace agent to agent --- cli/{workspaceagent.go => agent.go} | 5 +- cli/root.go | 1 + cli/workspaces.go | 1 - coderd/{workspaceagent.go => agent.go} | 50 +++---------------- .../{workspaceagentauth.go => agentauth.go} | 8 +-- ...aceagentauth_test.go => agentauth_test.go} | 8 +-- coderd/coderd.go | 4 +- codersdk/{workspaceagent.go => agent.go} | 14 +++--- .../{workspaceagent_test.go => agent_test.go} | 4 +- httpmw/{workspaceagent.go => agent.go} | 21 ++++---- .../{workspaceagent_test.go => agent_test.go} | 8 +-- 11 files changed, 46 insertions(+), 78 deletions(-) rename cli/{workspaceagent.go => agent.go} (70%) rename coderd/{workspaceagent.go => agent.go} (71%) rename coderd/{workspaceagentauth.go => agentauth.go} (93%) rename coderd/{workspaceagentauth_test.go => agentauth_test.go} (92%) rename codersdk/{workspaceagent.go => agent.go} (56%) rename codersdk/{workspaceagent_test.go => agent_test.go} (78%) rename httpmw/{workspaceagent.go => agent.go} (63%) rename httpmw/{workspaceagent_test.go => agent_test.go} (91%) diff --git a/cli/workspaceagent.go b/cli/agent.go similarity index 70% rename from cli/workspaceagent.go rename to cli/agent.go index 8dc305e498aa8..5d0e9403ed4cc 100644 --- a/cli/workspaceagent.go +++ b/cli/agent.go @@ -4,9 +4,10 @@ import ( "github.com/spf13/cobra" ) -func workspaceAgent() *cobra.Command { +func agent() *cobra.Command { return &cobra.Command{ - Use: "agent", + Use: "agent", + Hidden: true, RunE: func(cmd *cobra.Command, args []string) error { return nil }, diff --git a/cli/root.go b/cli/root.go index 054d9d84f942b..69be6105ca3d0 100644 --- a/cli/root.go +++ b/cli/root.go @@ -64,6 +64,7 @@ func Root() *cobra.Command { `Additional help topics:`, header.Sprint("Additional help:"), ).Replace(cmd.UsageTemplate())) + cmd.AddCommand(agent()) cmd.AddCommand(login()) cmd.AddCommand(projects()) cmd.AddCommand(workspaces()) diff --git a/cli/workspaces.go b/cli/workspaces.go index b470fc7df1c60..d405f00cea88b 100644 --- a/cli/workspaces.go +++ b/cli/workspaces.go @@ -6,7 +6,6 @@ func workspaces() *cobra.Command { cmd := &cobra.Command{ Use: "workspaces", } - cmd.AddCommand(workspaceAgent()) cmd.AddCommand(workspaceCreate()) return cmd diff --git a/coderd/workspaceagent.go b/coderd/agent.go similarity index 71% rename from coderd/workspaceagent.go rename to coderd/agent.go index 9ea51dbc17570..42dd82b9ea27b 100644 --- a/coderd/workspaceagent.go +++ b/coderd/agent.go @@ -1,17 +1,13 @@ package coderd import ( - "database/sql" "fmt" "io" "net/http" - "time" "github.com/hashicorp/yamux" "nhooyr.io/websocket" - "cdr.dev/slog" - "github.com/coder/coder/database" "github.com/coder/coder/httpapi" "github.com/coder/coder/httpmw" "github.com/coder/coder/peerbroker" @@ -39,15 +35,15 @@ type AgentInstanceMetadata struct { VNC bool `json:"vnc"` } -func (api *api) workspaceAgentUpdate() { +func (api *api) agentUpdate() { } -func (api *api) workspaceAgentConnectByResource(rw http.ResponseWriter, r *http.Request) { +func (api *api) agentConnectByResource(rw http.ResponseWriter, r *http.Request) { api.websocketWaitGroup.Add(1) defer api.websocketWaitGroup.Done() - agent := httpmw.WorkspaceAgent(r) + agent := httpmw.Agent(r) if !agent.UpdatedAt.Valid { httpapi.Write(rw, http.StatusPreconditionRequired, httpapi.Response{ Message: "Agent hasn't connected yet!", @@ -75,7 +71,7 @@ func (api *api) workspaceAgentConnectByResource(rw http.ResponseWriter, r *http. return } err = peerbroker.ProxyListen(r.Context(), session, peerbroker.ProxyOptions{ - ChannelID: resource.WorkspaceAgentID.UUID.String(), + ChannelID: agent.ID.String(), Logger: api.Logger.Named("peerbroker-proxy-dial"), Pubsub: api.Pubsub, }) @@ -85,11 +81,11 @@ func (api *api) workspaceAgentConnectByResource(rw http.ResponseWriter, r *http. } } -func (api *api) workspaceAgentServe(rw http.ResponseWriter, r *http.Request) { +func (api *api) agentServe(rw http.ResponseWriter, r *http.Request) { api.websocketWaitGroup.Add(1) defer api.websocketWaitGroup.Done() - workspaceAgent := httpmw.WorkspaceAgent(r) + agent := httpmw.Agent(r) conn, err := websocket.Accept(rw, r, &websocket.AcceptOptions{ CompressionMode: websocket.CompressionDisabled, }) @@ -110,7 +106,7 @@ func (api *api) workspaceAgentServe(rw http.ResponseWriter, r *http.Request) { return } closer, err := peerbroker.ProxyDial(proto.NewDRPCPeerBrokerClient(provisionersdk.Conn(session)), peerbroker.ProxyOptions{ - ChannelID: workspaceAgent.ID.String(), + ChannelID: agent.ID.String(), Pubsub: api.Pubsub, Logger: api.Logger.Named("peerbroker-proxy-listen"), }) @@ -118,36 +114,6 @@ func (api *api) workspaceAgentServe(rw http.ResponseWriter, r *http.Request) { _ = conn.Close(websocket.StatusAbnormalClosure, err.Error()) return } - - err = api.Database.UpdateWorkspaceAgentByID(r.Context(), database.UpdateWorkspaceAgentByIDParams{ - ID: workspaceAgent.ID, - UpdatedAt: sql.NullTime{ - Time: database.Now(), - Valid: true, - }, - }) - if err != nil { - _ = conn.Close(websocket.StatusAbnormalClosure, err.Error()) - return - } defer closer.Close() - ticker := time.NewTicker(5 * time.Second) - for { - select { - case <-ticker.C: - err = api.Database.UpdateWorkspaceAgentByID(r.Context(), database.UpdateWorkspaceAgentByIDParams{ - ID: workspaceAgent.ID, - UpdatedAt: sql.NullTime{ - Time: database.Now(), - Valid: true, - }, - }) - if err != nil { - api.Logger.Error(r.Context(), "update workspace agent by id", slog.Error(err), slog.F("id", workspaceAgent.ID.String())) - return - } - case <-r.Context().Done(): - return - } - } + <-r.Context().Done() } diff --git a/coderd/workspaceagentauth.go b/coderd/agentauth.go similarity index 93% rename from coderd/workspaceagentauth.go rename to coderd/agentauth.go index 2e45046fa3ff0..ed85d23b7bfa7 100644 --- a/coderd/workspaceagentauth.go +++ b/coderd/agentauth.go @@ -19,16 +19,16 @@ type GoogleInstanceIdentityToken struct { JSONWebToken string `json:"json_web_token" validate:"required"` } -// WorkspaceAgentAuthenticateResponse is returned when an instance ID +// AgentAuthResponse is returned when an instance ID // has been exchanged for a session token. -type WorkspaceAgentAuthenticateResponse struct { +type AgentAuthResponse struct { SessionToken string `json:"session_token"` } // Google Compute Engine supports instance identity verification: // https://cloud.google.com/compute/docs/instances/verifying-instance-identity // Using this, we can exchange a signed instance payload for an agent token. -func (api *api) postAuthenticateWorkspaceAgentUsingGoogleInstanceIdentity(rw http.ResponseWriter, r *http.Request) { +func (api *api) postAuthenticateAgentUsingGoogleInstanceIdentity(rw http.ResponseWriter, r *http.Request) { var req GoogleInstanceIdentityToken if !httpapi.Read(rw, r, &req) { return @@ -121,7 +121,7 @@ func (api *api) postAuthenticateWorkspaceAgentUsingGoogleInstanceIdentity(rw htt return } render.Status(r, http.StatusOK) - render.JSON(rw, r, WorkspaceAgentAuthenticateResponse{ + render.JSON(rw, r, AgentAuthResponse{ SessionToken: agent.AuthToken.String(), }) } diff --git a/coderd/workspaceagentauth_test.go b/coderd/agentauth_test.go similarity index 92% rename from coderd/workspaceagentauth_test.go rename to coderd/agentauth_test.go index c48dfc75af1d1..bdd45329c09fa 100644 --- a/coderd/workspaceagentauth_test.go +++ b/coderd/agentauth_test.go @@ -28,7 +28,7 @@ import ( "github.com/coder/coder/provisionersdk/proto" ) -func TestPostWorkspaceAgentAuthenticateGoogleInstanceIdentity(t *testing.T) { +func TestPostAgentAuthenticateGoogleInstanceIdentity(t *testing.T) { t.Parallel() t.Run("Expired", func(t *testing.T) { t.Parallel() @@ -38,7 +38,7 @@ func TestPostWorkspaceAgentAuthenticateGoogleInstanceIdentity(t *testing.T) { client := coderdtest.New(t, &coderdtest.Options{ GoogleTokenValidator: validator, }) - _, err := client.AuthenticateWorkspaceAgentUsingGoogleCloudIdentity(context.Background(), "", createMetadataClient(signedKey)) + _, err := client.AuthenticateAgentWithGoogleCloudIdentity(context.Background(), "", createMetadataClient(signedKey)) var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) require.Equal(t, http.StatusUnauthorized, apiErr.StatusCode()) @@ -52,7 +52,7 @@ func TestPostWorkspaceAgentAuthenticateGoogleInstanceIdentity(t *testing.T) { client := coderdtest.New(t, &coderdtest.Options{ GoogleTokenValidator: validator, }) - _, err := client.AuthenticateWorkspaceAgentUsingGoogleCloudIdentity(context.Background(), "", createMetadataClient(signedKey)) + _, err := client.AuthenticateAgentWithGoogleCloudIdentity(context.Background(), "", createMetadataClient(signedKey)) var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) require.Equal(t, http.StatusNotFound, apiErr.StatusCode()) @@ -98,7 +98,7 @@ func TestPostWorkspaceAgentAuthenticateGoogleInstanceIdentity(t *testing.T) { require.NoError(t, err) coderdtest.AwaitWorkspaceProvisionJob(t, client, user.Organization, firstHistory.ProvisionJobID) - _, err = client.AuthenticateWorkspaceAgentUsingGoogleCloudIdentity(context.Background(), "", createMetadataClient(signedKey)) + _, err = client.AuthenticateAgentWithGoogleCloudIdentity(context.Background(), "", createMetadataClient(signedKey)) require.NoError(t, err) }) } diff --git a/coderd/coderd.go b/coderd/coderd.go index 69a8432aa53bf..fceba13b24934 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -112,9 +112,9 @@ func New(options *Options) (http.Handler, func()) { }) }) - r.Route("/workspaceagent", func(r chi.Router) { + r.Route("/agent", func(r chi.Router) { r.Route("/authenticate", func(r chi.Router) { - r.Post("/google-instance-identity", api.postAuthenticateWorkspaceAgentUsingGoogleInstanceIdentity) + r.Post("/google-instance-identity", api.postAuthenticateAgentUsingGoogleInstanceIdentity) }) }) diff --git a/codersdk/workspaceagent.go b/codersdk/agent.go similarity index 56% rename from codersdk/workspaceagent.go rename to codersdk/agent.go index 7bfcab9202bfb..841481ca64e3f 100644 --- a/codersdk/workspaceagent.go +++ b/codersdk/agent.go @@ -12,11 +12,11 @@ import ( "github.com/coder/coder/coderd" ) -// AuthenticateWorkspaceAgentUsingGoogleCloudIdentity uses the Google Compute Engine Metadata API to +// AuthenticateAgentWithGoogleCloudIdentity uses the Google Compute Engine Metadata API to // fetch a signed JWT, and exchange it for a session token for a workspace agent. // // The requesting instance must be registered as a resource in the latest history for a workspace. -func (c *Client) AuthenticateWorkspaceAgentUsingGoogleCloudIdentity(ctx context.Context, serviceAccount string, gcpClient *metadata.Client) (coderd.WorkspaceAgentAuthenticateResponse, error) { +func (c *Client) AuthenticateAgentWithGoogleCloudIdentity(ctx context.Context, serviceAccount string, gcpClient *metadata.Client) (coderd.AgentAuthResponse, error) { if serviceAccount == "" { // This is the default name specified by Google. serviceAccount = "default" @@ -27,18 +27,18 @@ func (c *Client) AuthenticateWorkspaceAgentUsingGoogleCloudIdentity(ctx context. // "format=full" is required, otherwise the responding payload will be missing "instance_id". jwt, err := gcpClient.Get(fmt.Sprintf("instance/service-accounts/%s/identity?audience=coder&format=full", serviceAccount)) if err != nil { - return coderd.WorkspaceAgentAuthenticateResponse{}, xerrors.Errorf("get metadata identity: %w", err) + return coderd.AgentAuthResponse{}, xerrors.Errorf("get metadata identity: %w", err) } - res, err := c.request(ctx, http.MethodPost, "/api/v2/workspaceagent/authenticate/google-instance-identity", coderd.GoogleInstanceIdentityToken{ + res, err := c.request(ctx, http.MethodPost, "/api/v2/agent/authenticate/google-instance-identity", coderd.GoogleInstanceIdentityToken{ JSONWebToken: jwt, }) if err != nil { - return coderd.WorkspaceAgentAuthenticateResponse{}, err + return coderd.AgentAuthResponse{}, err } defer res.Body.Close() if res.StatusCode != http.StatusOK { - return coderd.WorkspaceAgentAuthenticateResponse{}, readBodyAsError(res) + return coderd.AgentAuthResponse{}, readBodyAsError(res) } - var resp coderd.WorkspaceAgentAuthenticateResponse + var resp coderd.AgentAuthResponse return resp, json.NewDecoder(res.Body).Decode(&resp) } diff --git a/codersdk/workspaceagent_test.go b/codersdk/agent_test.go similarity index 78% rename from codersdk/workspaceagent_test.go rename to codersdk/agent_test.go index 6c09f54e828ee..6ea25b41858d4 100644 --- a/codersdk/workspaceagent_test.go +++ b/codersdk/agent_test.go @@ -13,12 +13,12 @@ import ( "github.com/coder/coder/coderd/coderdtest" ) -func TestAuthenticateWorkspaceAgentUsingGoogleCloudIdentity(t *testing.T) { +func TestAuthenticateAgentUsingGoogleCloudIdentity(t *testing.T) { t.Parallel() t.Run("Error", func(t *testing.T) { t.Parallel() client := coderdtest.New(t, nil) - _, err := client.AuthenticateWorkspaceAgentUsingGoogleCloudIdentity(context.Background(), "", metadata.NewClient(&http.Client{ + _, err := client.AuthenticateAgentWithGoogleCloudIdentity(context.Background(), "", metadata.NewClient(&http.Client{ Transport: roundTripper(func(req *http.Request) (*http.Response, error) { return &http.Response{ StatusCode: http.StatusOK, diff --git a/httpmw/workspaceagent.go b/httpmw/agent.go similarity index 63% rename from httpmw/workspaceagent.go rename to httpmw/agent.go index bce1cc92cab56..2dd72acf31775 100644 --- a/httpmw/workspaceagent.go +++ b/httpmw/agent.go @@ -7,24 +7,25 @@ import ( "fmt" "net/http" + "github.com/google/uuid" + "github.com/coder/coder/database" "github.com/coder/coder/httpapi" - "github.com/google/uuid" ) -type workspaceAgentContextKey struct{} +type agentContextKey struct{} -// WorkspaceAgent returns the workspace agent from the ExtractWorkspaceAgent handler. -func WorkspaceAgent(r *http.Request) database.ProvisionerJobAgent { - user, ok := r.Context().Value(workspaceAgentContextKey{}).(database.ProvisionerJobAgent) +// Agent returns the workspace agent from the ExtractAgent handler. +func Agent(r *http.Request) database.ProvisionerJobAgent { + user, ok := r.Context().Value(agentContextKey{}).(database.ProvisionerJobAgent) if !ok { - panic("developer error: workspace agent middleware not provided") + panic("developer error: agent middleware not provided") } return user } -// ExtractWorkspaceAgent requires authentication using a valid agent token. -func ExtractWorkspaceAgent(db database.Store) func(http.Handler) http.Handler { +// ExtractAgent requires authentication using a valid agent token. +func ExtractAgent(db database.Store) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { cookie, err := r.Cookie(AuthCookie) @@ -41,7 +42,7 @@ func ExtractWorkspaceAgent(db database.Store) func(http.Handler) http.Handler { }) return } - workspaceAgent, err := db.GetProvisionerJobAgentByAuthToken(r.Context(), token) + agent, err := db.GetProvisionerJobAgentByAuthToken(r.Context(), token) if errors.Is(err, sql.ErrNoRows) { if errors.Is(err, sql.ErrNoRows) { httpapi.Write(rw, http.StatusUnauthorized, httpapi.Response{ @@ -57,7 +58,7 @@ func ExtractWorkspaceAgent(db database.Store) func(http.Handler) http.Handler { return } - ctx := context.WithValue(r.Context(), workspaceAgentContextKey{}, workspaceAgent) + ctx := context.WithValue(r.Context(), agentContextKey{}, agent) next.ServeHTTP(rw, r.WithContext(ctx)) }) } diff --git a/httpmw/workspaceagent_test.go b/httpmw/agent_test.go similarity index 91% rename from httpmw/workspaceagent_test.go rename to httpmw/agent_test.go index b36d74c9c23dc..d645d5aa842dd 100644 --- a/httpmw/workspaceagent_test.go +++ b/httpmw/agent_test.go @@ -15,7 +15,7 @@ import ( "github.com/coder/coder/httpmw" ) -func TestWorkspaceAgent(t *testing.T) { +func TestAgent(t *testing.T) { t.Parallel() setup := func(db database.Store) (*http.Request, uuid.UUID) { @@ -33,7 +33,7 @@ func TestWorkspaceAgent(t *testing.T) { db := databasefake.New() rtr := chi.NewRouter() rtr.Use( - httpmw.ExtractWorkspaceAgent(db), + httpmw.ExtractAgent(db), ) rtr.Get("/", nil) r, _ := setup(db) @@ -50,10 +50,10 @@ func TestWorkspaceAgent(t *testing.T) { db := databasefake.New() rtr := chi.NewRouter() rtr.Use( - httpmw.ExtractWorkspaceAgent(db), + httpmw.ExtractAgent(db), ) rtr.Get("/", func(rw http.ResponseWriter, r *http.Request) { - _ = httpmw.WorkspaceAgent(r) + _ = httpmw.Agent(r) rw.WriteHeader(http.StatusOK) }) r, token := setup(db) From 9114f6610d148f0f9df7be5faafb22596ff5567d Mon Sep 17 00:00:00 2001 From: Kyle Carberry Date: Mon, 28 Feb 2022 18:11:52 +0000 Subject: [PATCH 21/21] Cleanup routes --- coderd/coderd.go | 66 +++++++++---------- coderd/{agent.go => workspaceagent.go} | 16 ++--- .../{agentauth.go => workspaceagentauth.go} | 8 +-- ...uth_test.go => workspaceagentauth_test.go} | 8 +-- codersdk/projectimport.go | 14 ++-- codersdk/{agent.go => workspaceagent.go} | 14 ++-- .../{agent_test.go => workspaceagent_test.go} | 4 +- codersdk/workspaces.go | 12 ++-- httpmw/{agent.go => workspaceagent.go} | 14 ++-- .../{agent_test.go => workspaceagent_test.go} | 8 +-- 10 files changed, 80 insertions(+), 84 deletions(-) rename coderd/{agent.go => workspaceagent.go} (90%) rename coderd/{agentauth.go => workspaceagentauth.go} (93%) rename coderd/{agentauth_test.go => workspaceagentauth_test.go} (93%) rename codersdk/{agent.go => workspaceagent.go} (63%) rename codersdk/{agent_test.go => workspaceagent_test.go} (79%) rename httpmw/{agent.go => workspaceagent.go} (72%) rename httpmw/{agent_test.go => workspaceagent_test.go} (91%) diff --git a/coderd/coderd.go b/coderd/coderd.go index fceba13b24934..49b407d1ffdc0 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -60,6 +60,22 @@ func New(options *Options) (http.Handler, func()) { r.Post("/keys", api.postKeyForUser) }) }) + + r.Route("/project/import/{organization}", func(r chi.Router) { + r.Use( + httpmw.ExtractAPIKey(options.Database, nil), + httpmw.ExtractOrganizationParam(options.Database), + ) + r.Post("/", api.postProjectImportByOrganization) + r.Route("/{provisionerjob}", func(r chi.Router) { + r.Use(httpmw.ExtractProvisionerJobParam(options.Database)) + r.Get("/", api.provisionerJobByID) + r.Get("/schemas", api.projectImportJobSchemasByID) + r.Get("/parameters", api.projectImportJobParametersByID) + r.Get("/resources", api.projectImportJobResourcesByID) + r.Get("/logs", api.provisionerJobLogsByID) + }) + }) r.Route("/projects", func(r chi.Router) { r.Use( httpmw.ExtractAPIKey(options.Database, nil), @@ -89,8 +105,17 @@ func New(options *Options) (http.Handler, func()) { }) }) - // Listing operations specific to resources should go under - // their respective routes. eg. /orgs//workspaces + r.Route("/workspace/provision/{organization}", func(r chi.Router) { + r.Use( + httpmw.ExtractAPIKey(options.Database, nil), + httpmw.ExtractOrganizationParam(options.Database), + ) + r.Route("/{provisionerjob}", func(r chi.Router) { + r.Use(httpmw.ExtractProvisionerJobParam(options.Database)) + r.Get("/", api.provisionerJobByID) + r.Get("/logs", api.provisionerJobLogsByID) + }) + }) r.Route("/workspaces", func(r chi.Router) { r.Use(httpmw.ExtractAPIKey(options.Database, nil)) r.Get("/", api.workspaces) @@ -100,7 +125,7 @@ func New(options *Options) (http.Handler, func()) { r.Route("/{workspace}", func(r chi.Router) { r.Use(httpmw.ExtractWorkspaceParam(options.Database)) r.Get("/", api.workspaceByUser) - r.Route("/version", func(r chi.Router) { + r.Route("/history", func(r chi.Router) { r.Post("/", api.postWorkspaceHistoryByUser) r.Get("/", api.workspaceHistoryByUser) r.Route("/{workspacehistory}", func(r chi.Router) { @@ -113,8 +138,11 @@ func New(options *Options) (http.Handler, func()) { }) r.Route("/agent", func(r chi.Router) { - r.Route("/authenticate", func(r chi.Router) { - r.Post("/google-instance-identity", api.postAuthenticateAgentUsingGoogleInstanceIdentity) + r.Route("/auth", func(r chi.Router) { + r.Post("/google-instance-identity", api.postAuthWorkspaceAgentUsingGoogleInstanceIdentity) + }) + r.Route("/{agent}", func(r chi.Router) { + }) }) @@ -123,34 +151,6 @@ func New(options *Options) (http.Handler, func()) { r.Post("/", api.postUpload) }) - r.Route("/projectimport/{organization}", func(r chi.Router) { - r.Use( - httpmw.ExtractAPIKey(options.Database, nil), - httpmw.ExtractOrganizationParam(options.Database), - ) - r.Post("/", api.postProjectImportByOrganization) - r.Route("/{provisionerjob}", func(r chi.Router) { - r.Use(httpmw.ExtractProvisionerJobParam(options.Database)) - r.Get("/", api.provisionerJobByID) - r.Get("/schemas", api.projectImportJobSchemasByID) - r.Get("/parameters", api.projectImportJobParametersByID) - r.Get("/resources", api.projectImportJobResourcesByID) - r.Get("/logs", api.provisionerJobLogsByID) - }) - }) - - r.Route("/workspaceprovision/{organization}", func(r chi.Router) { - r.Use( - httpmw.ExtractAPIKey(options.Database, nil), - httpmw.ExtractOrganizationParam(options.Database), - ) - r.Route("/{provisionerjob}", func(r chi.Router) { - r.Use(httpmw.ExtractProvisionerJobParam(options.Database)) - r.Get("/", api.provisionerJobByID) - r.Get("/logs", api.provisionerJobLogsByID) - }) - }) - r.Route("/provisioners/daemons", func(r chi.Router) { r.Get("/", api.provisionerDaemons) r.Get("/serve", api.provisionerDaemonsServe) diff --git a/coderd/agent.go b/coderd/workspaceagent.go similarity index 90% rename from coderd/agent.go rename to coderd/workspaceagent.go index 42dd82b9ea27b..578b6ea7aced6 100644 --- a/coderd/agent.go +++ b/coderd/workspaceagent.go @@ -15,7 +15,7 @@ import ( "github.com/coder/coder/provisionersdk" ) -type AgentResourceMetadata struct { +type WorkspaceAgentResourceMetadata struct { MemoryTotal uint64 `json:"memory_total"` DiskTotal uint64 `json:"disk_total"` CPUCores uint64 `json:"cpu_cores"` @@ -23,7 +23,7 @@ type AgentResourceMetadata struct { CPUMhz float64 `json:"cpu_mhz"` } -type AgentInstanceMetadata struct { +type WorkspaceAgentInstanceMetadata struct { JailOrchestrator string `json:"jail_orchestrator"` OperatingSystem string `json:"operating_system"` Platform string `json:"platform"` @@ -35,15 +35,11 @@ type AgentInstanceMetadata struct { VNC bool `json:"vnc"` } -func (api *api) agentUpdate() { - -} - -func (api *api) agentConnectByResource(rw http.ResponseWriter, r *http.Request) { +func (api *api) workspaceAgentConnectByResource(rw http.ResponseWriter, r *http.Request) { api.websocketWaitGroup.Add(1) defer api.websocketWaitGroup.Done() - agent := httpmw.Agent(r) + agent := httpmw.WorkspaceAgent(r) if !agent.UpdatedAt.Valid { httpapi.Write(rw, http.StatusPreconditionRequired, httpapi.Response{ Message: "Agent hasn't connected yet!", @@ -81,11 +77,11 @@ func (api *api) agentConnectByResource(rw http.ResponseWriter, r *http.Request) } } -func (api *api) agentServe(rw http.ResponseWriter, r *http.Request) { +func (api *api) workspaceAgentServe(rw http.ResponseWriter, r *http.Request) { api.websocketWaitGroup.Add(1) defer api.websocketWaitGroup.Done() - agent := httpmw.Agent(r) + agent := httpmw.WorkspaceAgent(r) conn, err := websocket.Accept(rw, r, &websocket.AcceptOptions{ CompressionMode: websocket.CompressionDisabled, }) diff --git a/coderd/agentauth.go b/coderd/workspaceagentauth.go similarity index 93% rename from coderd/agentauth.go rename to coderd/workspaceagentauth.go index ed85d23b7bfa7..5f5246d91115a 100644 --- a/coderd/agentauth.go +++ b/coderd/workspaceagentauth.go @@ -19,16 +19,16 @@ type GoogleInstanceIdentityToken struct { JSONWebToken string `json:"json_web_token" validate:"required"` } -// AgentAuthResponse is returned when an instance ID +// WorkspaceAgentAuthResponse is returned when an instance ID // has been exchanged for a session token. -type AgentAuthResponse struct { +type WorkspaceAgentAuthResponse struct { SessionToken string `json:"session_token"` } // Google Compute Engine supports instance identity verification: // https://cloud.google.com/compute/docs/instances/verifying-instance-identity // Using this, we can exchange a signed instance payload for an agent token. -func (api *api) postAuthenticateAgentUsingGoogleInstanceIdentity(rw http.ResponseWriter, r *http.Request) { +func (api *api) postAuthWorkspaceAgentUsingGoogleInstanceIdentity(rw http.ResponseWriter, r *http.Request) { var req GoogleInstanceIdentityToken if !httpapi.Read(rw, r, &req) { return @@ -121,7 +121,7 @@ func (api *api) postAuthenticateAgentUsingGoogleInstanceIdentity(rw http.Respons return } render.Status(r, http.StatusOK) - render.JSON(rw, r, AgentAuthResponse{ + render.JSON(rw, r, WorkspaceAgentAuthResponse{ SessionToken: agent.AuthToken.String(), }) } diff --git a/coderd/agentauth_test.go b/coderd/workspaceagentauth_test.go similarity index 93% rename from coderd/agentauth_test.go rename to coderd/workspaceagentauth_test.go index bdd45329c09fa..2bab26b978c32 100644 --- a/coderd/agentauth_test.go +++ b/coderd/workspaceagentauth_test.go @@ -28,7 +28,7 @@ import ( "github.com/coder/coder/provisionersdk/proto" ) -func TestPostAgentAuthenticateGoogleInstanceIdentity(t *testing.T) { +func TestPostWorkspaceAgentAuthenticateGoogleInstanceIdentity(t *testing.T) { t.Parallel() t.Run("Expired", func(t *testing.T) { t.Parallel() @@ -38,7 +38,7 @@ func TestPostAgentAuthenticateGoogleInstanceIdentity(t *testing.T) { client := coderdtest.New(t, &coderdtest.Options{ GoogleTokenValidator: validator, }) - _, err := client.AuthenticateAgentWithGoogleCloudIdentity(context.Background(), "", createMetadataClient(signedKey)) + _, err := client.AuthWorkspaceAgentWithGoogleCloudIdentity(context.Background(), "", createMetadataClient(signedKey)) var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) require.Equal(t, http.StatusUnauthorized, apiErr.StatusCode()) @@ -52,7 +52,7 @@ func TestPostAgentAuthenticateGoogleInstanceIdentity(t *testing.T) { client := coderdtest.New(t, &coderdtest.Options{ GoogleTokenValidator: validator, }) - _, err := client.AuthenticateAgentWithGoogleCloudIdentity(context.Background(), "", createMetadataClient(signedKey)) + _, err := client.AuthWorkspaceAgentWithGoogleCloudIdentity(context.Background(), "", createMetadataClient(signedKey)) var apiErr *codersdk.Error require.ErrorAs(t, err, &apiErr) require.Equal(t, http.StatusNotFound, apiErr.StatusCode()) @@ -98,7 +98,7 @@ func TestPostAgentAuthenticateGoogleInstanceIdentity(t *testing.T) { require.NoError(t, err) coderdtest.AwaitWorkspaceProvisionJob(t, client, user.Organization, firstHistory.ProvisionJobID) - _, err = client.AuthenticateAgentWithGoogleCloudIdentity(context.Background(), "", createMetadataClient(signedKey)) + _, err = client.AuthWorkspaceAgentWithGoogleCloudIdentity(context.Background(), "", createMetadataClient(signedKey)) require.NoError(t, err) }) } diff --git a/codersdk/projectimport.go b/codersdk/projectimport.go index 7001d63153c09..a3caf211eec3d 100644 --- a/codersdk/projectimport.go +++ b/codersdk/projectimport.go @@ -16,7 +16,7 @@ import ( // ProjectImportJob is not associated with a project by default. Projects // are created from import. func (c *Client) CreateProjectImportJob(ctx context.Context, organization string, req coderd.CreateProjectImportJobRequest) (coderd.ProvisionerJob, error) { - res, err := c.request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/projectimport/%s", organization), req) + res, err := c.request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/project/import/%s", organization), req) if err != nil { return coderd.ProvisionerJob{}, err } @@ -30,7 +30,7 @@ func (c *Client) CreateProjectImportJob(ctx context.Context, organization string // ProjectImportJob returns an import job by ID. func (c *Client) ProjectImportJob(ctx context.Context, organization string, job uuid.UUID) (coderd.ProvisionerJob, error) { - res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/projectimport/%s/%s", organization, job), nil) + res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/project/import/%s/%s", organization, job), nil) if err != nil { return coderd.ProvisionerJob{}, nil } @@ -44,17 +44,17 @@ func (c *Client) ProjectImportJob(ctx context.Context, organization string, job // ProjectImportJobLogsBefore returns logs that occurred before a specific time. func (c *Client) ProjectImportJobLogsBefore(ctx context.Context, organization string, job uuid.UUID, before time.Time) ([]coderd.ProvisionerJobLog, error) { - return c.provisionerJobLogsBefore(ctx, "projectimport", organization, job, before) + return c.provisionerJobLogsBefore(ctx, "project/import", organization, job, before) } // ProjectImportJobLogsAfter streams logs for a project import operation that occurred after a specific time. func (c *Client) ProjectImportJobLogsAfter(ctx context.Context, organization string, job uuid.UUID, after time.Time) (<-chan coderd.ProvisionerJobLog, error) { - return c.provisionerJobLogsAfter(ctx, "projectimport", organization, job, after) + return c.provisionerJobLogsAfter(ctx, "project/import", organization, job, after) } // ProjectImportJobSchemas returns schemas for an import job by ID. func (c *Client) ProjectImportJobSchemas(ctx context.Context, organization string, job uuid.UUID) ([]coderd.ParameterSchema, error) { - res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/projectimport/%s/%s/schemas", organization, job), nil) + res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/project/import/%s/%s/schemas", organization, job), nil) if err != nil { return nil, err } @@ -68,7 +68,7 @@ func (c *Client) ProjectImportJobSchemas(ctx context.Context, organization strin // ProjectImportJobParameters returns computed parameters for a project import job. func (c *Client) ProjectImportJobParameters(ctx context.Context, organization string, job uuid.UUID) ([]coderd.ComputedParameterValue, error) { - res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/projectimport/%s/%s/parameters", organization, job), nil) + res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/project/import/%s/%s/parameters", organization, job), nil) if err != nil { return nil, err } @@ -82,7 +82,7 @@ func (c *Client) ProjectImportJobParameters(ctx context.Context, organization st // ProjectImportJobResources returns resources for a project import job. func (c *Client) ProjectImportJobResources(ctx context.Context, organization string, job uuid.UUID) ([]coderd.ProvisionerJobResource, error) { - res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/projectimport/%s/%s/resources", organization, job), nil) + res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/project/import/%s/%s/resources", organization, job), nil) if err != nil { return nil, err } diff --git a/codersdk/agent.go b/codersdk/workspaceagent.go similarity index 63% rename from codersdk/agent.go rename to codersdk/workspaceagent.go index 841481ca64e3f..477a7e853c774 100644 --- a/codersdk/agent.go +++ b/codersdk/workspaceagent.go @@ -12,11 +12,11 @@ import ( "github.com/coder/coder/coderd" ) -// AuthenticateAgentWithGoogleCloudIdentity uses the Google Compute Engine Metadata API to +// AuthWorkspaceAgentWithGoogleCloudIdentity uses the Google Compute Engine Metadata API to // fetch a signed JWT, and exchange it for a session token for a workspace agent. // // The requesting instance must be registered as a resource in the latest history for a workspace. -func (c *Client) AuthenticateAgentWithGoogleCloudIdentity(ctx context.Context, serviceAccount string, gcpClient *metadata.Client) (coderd.AgentAuthResponse, error) { +func (c *Client) AuthWorkspaceAgentWithGoogleCloudIdentity(ctx context.Context, serviceAccount string, gcpClient *metadata.Client) (coderd.WorkspaceAgentAuthResponse, error) { if serviceAccount == "" { // This is the default name specified by Google. serviceAccount = "default" @@ -27,18 +27,18 @@ func (c *Client) AuthenticateAgentWithGoogleCloudIdentity(ctx context.Context, s // "format=full" is required, otherwise the responding payload will be missing "instance_id". jwt, err := gcpClient.Get(fmt.Sprintf("instance/service-accounts/%s/identity?audience=coder&format=full", serviceAccount)) if err != nil { - return coderd.AgentAuthResponse{}, xerrors.Errorf("get metadata identity: %w", err) + return coderd.WorkspaceAgentAuthResponse{}, xerrors.Errorf("get metadata identity: %w", err) } - res, err := c.request(ctx, http.MethodPost, "/api/v2/agent/authenticate/google-instance-identity", coderd.GoogleInstanceIdentityToken{ + res, err := c.request(ctx, http.MethodPost, "/api/v2/agent/auth/google-instance-identity", coderd.GoogleInstanceIdentityToken{ JSONWebToken: jwt, }) if err != nil { - return coderd.AgentAuthResponse{}, err + return coderd.WorkspaceAgentAuthResponse{}, err } defer res.Body.Close() if res.StatusCode != http.StatusOK { - return coderd.AgentAuthResponse{}, readBodyAsError(res) + return coderd.WorkspaceAgentAuthResponse{}, readBodyAsError(res) } - var resp coderd.AgentAuthResponse + var resp coderd.WorkspaceAgentAuthResponse return resp, json.NewDecoder(res.Body).Decode(&resp) } diff --git a/codersdk/agent_test.go b/codersdk/workspaceagent_test.go similarity index 79% rename from codersdk/agent_test.go rename to codersdk/workspaceagent_test.go index 6ea25b41858d4..7ed538e37cd47 100644 --- a/codersdk/agent_test.go +++ b/codersdk/workspaceagent_test.go @@ -13,12 +13,12 @@ import ( "github.com/coder/coder/coderd/coderdtest" ) -func TestAuthenticateAgentUsingGoogleCloudIdentity(t *testing.T) { +func TestAuthWorkspaceAgentUsingGoogleCloudIdentity(t *testing.T) { t.Parallel() t.Run("Error", func(t *testing.T) { t.Parallel() client := coderdtest.New(t, nil) - _, err := client.AuthenticateAgentWithGoogleCloudIdentity(context.Background(), "", metadata.NewClient(&http.Client{ + _, err := client.AuthWorkspaceAgentWithGoogleCloudIdentity(context.Background(), "", metadata.NewClient(&http.Client{ Transport: roundTripper(func(req *http.Request) (*http.Response, error) { return &http.Response{ StatusCode: http.StatusOK, diff --git a/codersdk/workspaces.go b/codersdk/workspaces.go index 28f926c518049..459694e3c38b5 100644 --- a/codersdk/workspaces.go +++ b/codersdk/workspaces.go @@ -68,7 +68,7 @@ func (c *Client) ListWorkspaceHistory(ctx context.Context, owner, workspace stri if owner == "" { owner = "me" } - res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaces/%s/%s/version", owner, workspace), nil) + res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaces/%s/%s/history", owner, workspace), nil) if err != nil { return nil, err } @@ -89,7 +89,7 @@ func (c *Client) WorkspaceHistory(ctx context.Context, owner, workspace, history if history == "" { history = "latest" } - res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaces/%s/%s/version/%s", owner, workspace, history), nil) + res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaces/%s/%s/history/%s", owner, workspace, history), nil) if err != nil { return coderd.WorkspaceHistory{}, err } @@ -123,7 +123,7 @@ func (c *Client) CreateWorkspaceHistory(ctx context.Context, owner, workspace st if owner == "" { owner = "me" } - res, err := c.request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/workspaces/%s/%s/version", owner, workspace), request) + res, err := c.request(ctx, http.MethodPost, fmt.Sprintf("/api/v2/workspaces/%s/%s/history", owner, workspace), request) if err != nil { return coderd.WorkspaceHistory{}, err } @@ -136,7 +136,7 @@ func (c *Client) CreateWorkspaceHistory(ctx context.Context, owner, workspace st } func (c *Client) WorkspaceProvisionJob(ctx context.Context, organization string, job uuid.UUID) (coderd.ProvisionerJob, error) { - res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspaceprovision/%s/%s", organization, job), nil) + res, err := c.request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/workspace/provision/%s/%s", organization, job), nil) if err != nil { return coderd.ProvisionerJob{}, nil } @@ -150,10 +150,10 @@ func (c *Client) WorkspaceProvisionJob(ctx context.Context, organization string, // WorkspaceProvisionJobLogsBefore returns logs that occurred before a specific time. func (c *Client) WorkspaceProvisionJobLogsBefore(ctx context.Context, organization string, job uuid.UUID, before time.Time) ([]coderd.ProvisionerJobLog, error) { - return c.provisionerJobLogsBefore(ctx, "workspaceprovision", organization, job, before) + return c.provisionerJobLogsBefore(ctx, "workspace/provision", organization, job, before) } // WorkspaceProvisionJobLogsAfter streams logs for a workspace provision operation that occurred after a specific time. func (c *Client) WorkspaceProvisionJobLogsAfter(ctx context.Context, organization string, job uuid.UUID, after time.Time) (<-chan coderd.ProvisionerJobLog, error) { - return c.provisionerJobLogsAfter(ctx, "workspaceprovision", organization, job, after) + return c.provisionerJobLogsAfter(ctx, "workspace/provision", organization, job, after) } diff --git a/httpmw/agent.go b/httpmw/workspaceagent.go similarity index 72% rename from httpmw/agent.go rename to httpmw/workspaceagent.go index 2dd72acf31775..85a46ed0001cb 100644 --- a/httpmw/agent.go +++ b/httpmw/workspaceagent.go @@ -13,19 +13,19 @@ import ( "github.com/coder/coder/httpapi" ) -type agentContextKey struct{} +type workspaceAgentContextKey struct{} -// Agent returns the workspace agent from the ExtractAgent handler. -func Agent(r *http.Request) database.ProvisionerJobAgent { - user, ok := r.Context().Value(agentContextKey{}).(database.ProvisionerJobAgent) +// WorkspaceAgent returns the workspace agent from the ExtractAgent handler. +func WorkspaceAgent(r *http.Request) database.ProvisionerJobAgent { + user, ok := r.Context().Value(workspaceAgentContextKey{}).(database.ProvisionerJobAgent) if !ok { panic("developer error: agent middleware not provided") } return user } -// ExtractAgent requires authentication using a valid agent token. -func ExtractAgent(db database.Store) func(http.Handler) http.Handler { +// ExtractWorkspaceAgent requires authentication using a valid agent token. +func ExtractWorkspaceAgent(db database.Store) func(http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { cookie, err := r.Cookie(AuthCookie) @@ -58,7 +58,7 @@ func ExtractAgent(db database.Store) func(http.Handler) http.Handler { return } - ctx := context.WithValue(r.Context(), agentContextKey{}, agent) + ctx := context.WithValue(r.Context(), workspaceAgentContextKey{}, agent) next.ServeHTTP(rw, r.WithContext(ctx)) }) } diff --git a/httpmw/agent_test.go b/httpmw/workspaceagent_test.go similarity index 91% rename from httpmw/agent_test.go rename to httpmw/workspaceagent_test.go index d645d5aa842dd..b36d74c9c23dc 100644 --- a/httpmw/agent_test.go +++ b/httpmw/workspaceagent_test.go @@ -15,7 +15,7 @@ import ( "github.com/coder/coder/httpmw" ) -func TestAgent(t *testing.T) { +func TestWorkspaceAgent(t *testing.T) { t.Parallel() setup := func(db database.Store) (*http.Request, uuid.UUID) { @@ -33,7 +33,7 @@ func TestAgent(t *testing.T) { db := databasefake.New() rtr := chi.NewRouter() rtr.Use( - httpmw.ExtractAgent(db), + httpmw.ExtractWorkspaceAgent(db), ) rtr.Get("/", nil) r, _ := setup(db) @@ -50,10 +50,10 @@ func TestAgent(t *testing.T) { db := databasefake.New() rtr := chi.NewRouter() rtr.Use( - httpmw.ExtractAgent(db), + httpmw.ExtractWorkspaceAgent(db), ) rtr.Get("/", func(rw http.ResponseWriter, r *http.Request) { - _ = httpmw.Agent(r) + _ = httpmw.WorkspaceAgent(r) rw.WriteHeader(http.StatusOK) }) r, token := setup(db)