From 60d5002eb68e6cfc1ccce578a7d00bbb5d11c6e5 Mon Sep 17 00:00:00 2001 From: Spike Curtis Date: Fri, 25 Aug 2023 10:10:15 +0400 Subject: [PATCH] refactor: change template archive extraction to be on provisioner (#9264) * refactor provisionersdk protocol Signed-off-by: Spike Curtis * refactor provisioners to use new protocol Signed-off-by: Spike Curtis * refactor provisionerd to use new protocol Signed-off-by: Spike Curtis * refactor tests & proto renames * Fixes from self-review Signed-off-by: Spike Curtis * appease fmt & link Signed-off-by: Spike Curtis * code review fixes & e2e fixes Signed-off-by: Spike Curtis * More fmt Signed-off-by: Spike Curtis * Code review fixes Signed-off-by: Spike Curtis * new gen; use uuid for session workdir Signed-off-by: Spike Curtis * Revert nix-based gen CI task until dogfood is on nix Signed-off-by: Spike Curtis * revert deleting dogfood Docker stuff Signed-off-by: Spike Curtis * Revert "revert deleting dogfood Docker stuff" This reverts commit 97621581670e21945c78ac46955c1862727914c7. --------- Signed-off-by: Spike Curtis --- Makefile | 8 +- cli/agent_test.go | 18 +- cli/configssh_test.go | 21 +- cli/create_test.go | 95 +- cli/gitssh_test.go | 2 +- cli/portforward_test.go | 2 +- cli/restart_test.go | 42 +- cli/server.go | 13 +- cli/show_test.go | 7 +- cli/ssh_test.go | 8 +- cli/start_test.go | 24 +- cli/state_test.go | 16 +- cli/templatecreate_test.go | 77 +- cli/templatepull_test.go | 10 +- cli/templatepush_test.go | 31 +- cli/update_test.go | 55 +- coderd/activitybump_test.go | 23 +- coderd/autobuild/lifecycle_executor_test.go | 22 +- coderd/coderd_test.go | 2 +- coderd/coderdtest/coderdtest.go | 20 +- coderd/gitauth_test.go | 30 +- coderd/gitsshkey_test.go | 2 +- coderd/insights_test.go | 16 +- .../prometheusmetrics_test.go | 10 +- .../provisionerdserver/provisionerdserver.go | 6 +- .../provisionerdserver_test.go | 8 +- coderd/provisionerjobs_test.go | 16 +- coderd/templates_test.go | 2 +- coderd/templateversions_test.go | 88 +- coderd/workspaceagents_test.go | 88 +- coderd/workspaceapps/apptest/setup.go | 8 +- coderd/workspaceapps/db_test.go | 8 +- coderd/workspacebuilds_test.go | 65 +- coderd/workspaceresourceauth_test.go | 18 +- coderd/workspaces_test.go | 108 +- enterprise/cli/provisionerdaemons.go | 16 +- enterprise/coderd/appearance_test.go | 2 +- enterprise/coderd/provisionerdaemons_test.go | 6 +- enterprise/coderd/workspaceagents_test.go | 6 +- enterprise/coderd/workspacequota_test.go | 70 +- enterprise/coderd/workspaces_test.go | 40 +- provisioner/echo/serve.go | 299 +-- provisioner/echo/serve_test.go | 314 +-- provisioner/terraform/executor.go | 122 +- .../terraform/executor_internal_test.go | 4 +- provisioner/terraform/parse.go | 22 +- provisioner/terraform/parse_test.go | 214 +- provisioner/terraform/provision.go | 254 +- provisioner/terraform/provision_test.go | 527 ++--- provisioner/terraform/serve.go | 2 +- provisioner/terraform/testdata/fake_cancel.sh | 15 +- .../terraform/testdata/fake_cancel_hang.sh | 12 +- provisionerd/proto/provisionerd.pb.go | 394 ++-- provisionerd/proto/provisionerd.proto | 16 +- provisionerd/provisionerd.go | 9 - provisionerd/provisionerd_test.go | 452 ++-- provisionerd/runner/runner.go | 410 ++-- provisionersdk/errors.go | 19 + provisionersdk/proto/provisioner.pb.go | 2099 ++++++++--------- provisionersdk/proto/provisioner.proto | 185 +- provisionersdk/proto/provisioner_drpc.pb.go | 124 +- provisionersdk/serve.go | 27 +- provisionersdk/serve_test.go | 50 +- provisionersdk/session.go | 318 +++ provisionersdk/transport.go | 2 +- scaletest/agentconn/run_test.go | 8 +- scaletest/createworkspaces/run_test.go | 34 +- scaletest/reconnectingpty/run_test.go | 8 +- scaletest/workspacebuild/run_test.go | 18 +- scaletest/workspacetraffic/run_test.go | 16 +- site/e2e/helpers.ts | 201 +- site/e2e/provisionerGenerated.ts | 320 +-- site/e2e/tests/app.spec.ts | 2 +- site/e2e/tests/createWorkspace.spec.ts | 2 +- site/e2e/tests/outdatedAgent.spec.ts | 2 +- site/e2e/tests/outdatedCLI.spec.ts | 2 +- site/e2e/tests/webTerminal.spec.ts | 2 +- 77 files changed, 3789 insertions(+), 3825 deletions(-) create mode 100644 provisionersdk/errors.go create mode 100644 provisionersdk/session.go diff --git a/Makefile b/Makefile index 62528464cb..56acd83ff7 100644 --- a/Makefile +++ b/Makefile @@ -456,10 +456,10 @@ DB_GEN_FILES := \ # all gen targets should be added here and to gen/mark-fresh gen: \ - coderd/database/dump.sql \ - $(DB_GEN_FILES) \ provisionersdk/proto/provisioner.pb.go \ provisionerd/proto/provisionerd.pb.go \ + coderd/database/dump.sql \ + $(DB_GEN_FILES) \ site/src/api/typesGenerated.ts \ coderd/rbac/object_gen.go \ docs/admin/prometheus.md \ @@ -478,10 +478,10 @@ gen: \ # used during releases so we don't run generation scripts. gen/mark-fresh: files="\ - coderd/database/dump.sql \ - $(DB_GEN_FILES) \ provisionersdk/proto/provisioner.pb.go \ provisionerd/proto/provisionerd.pb.go \ + coderd/database/dump.sql \ + $(DB_GEN_FILES) \ site/src/api/typesGenerated.ts \ coderd/rbac/object_gen.go \ docs/admin/prometheus.md \ diff --git a/cli/agent_test.go b/cli/agent_test.go index d33bb55d00..7073f7c0f1 100644 --- a/cli/agent_test.go +++ b/cli/agent_test.go @@ -75,9 +75,9 @@ func TestWorkspaceAgent(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "somename", Type: "someinstance", @@ -127,9 +127,9 @@ func TestWorkspaceAgent(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "somename", Type: "someinstance", @@ -179,9 +179,9 @@ func TestWorkspaceAgent(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "somename", Type: "someinstance", diff --git a/cli/configssh_test.go b/cli/configssh_test.go index a592efa424..44246da259 100644 --- a/cli/configssh_test.go +++ b/cli/configssh_test.go @@ -82,9 +82,9 @@ func TestConfigSSH(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: []*proto.Response{{ + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", @@ -720,22 +720,11 @@ func TestConfigSSH_Hostnames(t *testing.T) { resources = append(resources, resource) } - provisionResponse := []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Resources: resources, - }, - }, - }} - client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) user := coderdtest.CreateFirstUser(t, client) // authToken := uuid.NewString() - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionPlan: provisionResponse, - ProvisionApply: provisionResponse, - }) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, + echo.WithResources(resources)) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) diff --git a/cli/create_test.go b/cli/create_test.go index f3436c0268..bdd229775e 100644 --- a/cli/create_test.go +++ b/cli/create_test.go @@ -29,11 +29,7 @@ func TestCreate(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionApply: provisionCompleteWithAgent, - ProvisionPlan: provisionCompleteWithAgent, - }) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, completeWithAgent()) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) args := []string{ @@ -84,11 +80,7 @@ func TestCreate(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) owner := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionApply: provisionCompleteWithAgent, - ProvisionPlan: provisionCompleteWithAgent, - }) + version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, completeWithAgent()) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) _, user := coderdtest.CreateAnotherUser(t, client, owner.OrganizationID) @@ -141,11 +133,7 @@ func TestCreate(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionApply: provisionCompleteWithAgent, - ProvisionPlan: provisionCompleteWithAgent, - }) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, completeWithAgent()) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { var defaultTTLMillis int64 = 2 * 60 * 60 * 1000 // 2 hours @@ -240,6 +228,22 @@ func TestCreate(t *testing.T) { }) } +func prepareEchoResponses(parameters []*proto.RichParameter) *echo.Responses { + return &echo.Responses{ + Parse: echo.ParseComplete, + ProvisionPlan: []*proto.Response{ + { + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ + Parameters: parameters, + }, + }, + }, + }, + ProvisionApply: echo.ApplyComplete, + } +} + func TestCreateWithRichParameters(t *testing.T) { t.Parallel() @@ -258,27 +262,12 @@ func TestCreateWithRichParameters(t *testing.T) { immutableParameterValue = "4" ) - echoResponses := &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ - { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Parameters: []*proto.RichParameter{ - {Name: firstParameterName, Description: firstParameterDescription, Mutable: true}, - {Name: secondParameterName, DisplayName: secondParameterDisplayName, Description: secondParameterDescription, Mutable: true}, - {Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false}, - }, - }, - }, - }, - }, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }}, - } + echoResponses := prepareEchoResponses([]*proto.RichParameter{ + {Name: firstParameterName, Description: firstParameterDescription, Mutable: true}, + {Name: secondParameterName, DisplayName: secondParameterDisplayName, Description: secondParameterDescription, Mutable: true}, + {Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false}, + }, + ) t.Run("InputParameters", func(t *testing.T) { t.Parallel() @@ -427,28 +416,6 @@ func TestCreateValidateRichParameters(t *testing.T) { {Name: boolParameterName, Type: "bool", Mutable: true}, } - prepareEchoResponses := func(richParameters []*proto.RichParameter) *echo.Responses { - return &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ - { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Parameters: richParameters, - }, - }, - }, - }, - ProvisionApply: []*proto.Provision_Response{ - { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }, - }, - } - } - t.Run("ValidateString", func(t *testing.T) { t.Parallel() @@ -626,20 +593,16 @@ func TestCreateWithGitAuth(t *testing.T) { t.Parallel() echoResponses := &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ + ProvisionPlan: []*proto.Response{ { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ GitAuthProviders: []string{"github"}, }, }, }, }, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }}, + ProvisionApply: echo.ApplyComplete, } client := coderdtest.New(t, &coderdtest.Options{ diff --git a/cli/gitssh_test.go b/cli/gitssh_test.go index 9c38ef945b..3e5045acf0 100644 --- a/cli/gitssh_test.go +++ b/cli/gitssh_test.go @@ -48,7 +48,7 @@ func prepareTestGitSSH(ctx context.Context, t *testing.T) (*codersdk.Client, str agentToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(agentToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) diff --git a/cli/portforward_test.go b/cli/portforward_test.go index ce48076852..030133a7ae 100644 --- a/cli/portforward_test.go +++ b/cli/portforward_test.go @@ -302,7 +302,7 @@ func runAgent(t *testing.T, client *codersdk.Client, userID uuid.UUID) codersdk. agentToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, orgID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(agentToken), }) diff --git a/cli/restart_test.go b/cli/restart_test.go index b68a3f843b..43b512c1bc 100644 --- a/cli/restart_test.go +++ b/cli/restart_test.go @@ -20,30 +20,14 @@ import ( func TestRestart(t *testing.T) { t.Parallel() - echoResponses := &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ - { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Parameters: []*proto.RichParameter{ - { - Name: ephemeralParameterName, - Description: ephemeralParameterDescription, - Mutable: true, - Ephemeral: true, - }, - }, - }, - }, - }, + echoResponses := prepareEchoResponses([]*proto.RichParameter{ + { + Name: ephemeralParameterName, + Description: ephemeralParameterDescription, + Mutable: true, + Ephemeral: true, }, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }}, - } + }) t.Run("OK", func(t *testing.T) { t.Parallel() @@ -187,10 +171,10 @@ func TestRestartWithParameters(t *testing.T) { echoResponses := &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ + ProvisionPlan: []*proto.Response{ { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ Parameters: []*proto.RichParameter{ { Name: immutableParameterName, @@ -202,11 +186,7 @@ func TestRestartWithParameters(t *testing.T) { }, }, }, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }}, + ProvisionApply: echo.ApplyComplete, } t.Run("DoNotAskForImmutables", func(t *testing.T) { diff --git a/cli/server.go b/cli/server.go index 1cd6ec4757..9d6b4f975c 100644 --- a/cli/server.go +++ b/cli/server.go @@ -41,7 +41,6 @@ import ( "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/collectors" "github.com/prometheus/client_golang/prometheus/promhttp" - "github.com/spf13/afero" "go.opentelemetry.io/otel/trace" "golang.org/x/mod/semver" "golang.org/x/oauth2" @@ -1304,7 +1303,11 @@ func newProvisionerDaemon( defer wg.Done() defer cancel() - err := echo.Serve(ctx, afero.NewOsFs(), &provisionersdk.ServeOptions{Listener: echoServer}) + err := echo.Serve(ctx, &provisionersdk.ServeOptions{ + Listener: echoServer, + WorkDirectory: workDir, + Logger: logger.Named("echo"), + }) if err != nil { select { case errCh <- err: @@ -1336,10 +1339,11 @@ func newProvisionerDaemon( err := terraform.Serve(ctx, &terraform.ServeOptions{ ServeOptions: &provisionersdk.ServeOptions{ - Listener: terraformServer, + Listener: terraformServer, + Logger: logger.Named("terraform"), + WorkDirectory: workDir, }, CachePath: tfDir, - Logger: logger.Named("terraform"), Tracer: tracer, }) if err != nil && !xerrors.Is(err, context.Canceled) { @@ -1366,7 +1370,6 @@ func newProvisionerDaemon( UpdateInterval: time.Second, ForceCancelInterval: cfg.Provisioner.ForceCancelInterval.Value(), Provisioners: provisioners, - WorkDirectory: workDir, TracerProvider: coderAPI.TracerProvider, Metrics: &metrics, }), nil diff --git a/cli/show_test.go b/cli/show_test.go index c77e5dc017..ccbe182cc7 100644 --- a/cli/show_test.go +++ b/cli/show_test.go @@ -7,7 +7,6 @@ import ( "github.com/coder/coder/v2/cli/clitest" "github.com/coder/coder/v2/coderd/coderdtest" - "github.com/coder/coder/v2/provisioner/echo" "github.com/coder/coder/v2/pty/ptytest" ) @@ -17,11 +16,7 @@ func TestShow(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) user := coderdtest.CreateFirstUser(t, client) - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionApply: provisionCompleteWithAgent, - ProvisionPlan: provisionCompleteWithAgent, - }) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, completeWithAgent()) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID) diff --git a/cli/ssh_test.go b/cli/ssh_test.go index 5e670d44d0..971dc2873f 100644 --- a/cli/ssh_test.go +++ b/cli/ssh_test.go @@ -56,10 +56,10 @@ func setupWorkspaceForAgent(t *testing.T, mutate func([]*proto.Agent) []*proto.A agentToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "dev", Type: "google_compute_instance", diff --git a/cli/start_test.go b/cli/start_test.go index e92d70cd71..dff4048f3e 100644 --- a/cli/start_test.go +++ b/cli/start_test.go @@ -33,10 +33,10 @@ func TestStart(t *testing.T) { echoResponses := &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ + ProvisionPlan: []*proto.Response{ { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ Parameters: []*proto.RichParameter{ { Name: ephemeralParameterName, @@ -49,11 +49,7 @@ func TestStart(t *testing.T) { }, }, }, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }}, + ProvisionApply: echo.ApplyComplete, } t.Run("BuildOptions", func(t *testing.T) { @@ -151,10 +147,10 @@ func TestStartWithParameters(t *testing.T) { echoResponses := &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ + ProvisionPlan: []*proto.Response{ { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ Parameters: []*proto.RichParameter{ { Name: immutableParameterName, @@ -166,11 +162,7 @@ func TestStartWithParameters(t *testing.T) { }, }, }, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }}, + ProvisionApply: echo.ApplyComplete, } t.Run("DoNotAskForImmutables", func(t *testing.T) { diff --git a/cli/state_test.go b/cli/state_test.go index 6273135d39..a240a6d2c8 100644 --- a/cli/state_test.go +++ b/cli/state_test.go @@ -25,9 +25,9 @@ func TestStatePull(t *testing.T) { wantState := []byte("some state") version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ State: wantState, }, }, @@ -53,9 +53,9 @@ func TestStatePull(t *testing.T) { wantState := []byte("some state") version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ State: wantState, }, }, @@ -83,7 +83,7 @@ func TestStatePush(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionApply: echo.ApplyComplete, }) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -108,7 +108,7 @@ func TestStatePush(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionApply: echo.ApplyComplete, }) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) diff --git a/cli/templatecreate_test.go b/cli/templatecreate_test.go index 1c3d6d6c95..ba5dad7b4a 100644 --- a/cli/templatecreate_test.go +++ b/cli/templatecreate_test.go @@ -19,26 +19,52 @@ import ( "github.com/coder/coder/v2/testutil" ) -var provisionCompleteWithAgent = []*proto.Provision_Response{ - { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Resources: []*proto.Resource{ - { - Type: "compute", - Name: "main", - Agents: []*proto.Agent{ +func completeWithAgent() *echo.Responses { + return &echo.Responses{ + Parse: echo.ParseComplete, + ProvisionPlan: []*proto.Response{ + { + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ + Resources: []*proto.Resource{ { - Name: "smith", - OperatingSystem: "linux", - Architecture: "i386", + Type: "compute", + Name: "main", + Agents: []*proto.Agent{ + { + Name: "smith", + OperatingSystem: "linux", + Architecture: "i386", + }, + }, }, }, }, }, }, }, - }, + ProvisionApply: []*proto.Response{ + { + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ + Resources: []*proto.Resource{ + { + Type: "compute", + Name: "main", + Agents: []*proto.Agent{ + { + Name: "smith", + OperatingSystem: "linux", + Architecture: "i386", + }, + }, + }, + }, + }, + }, + }, + }, + } } func TestTemplateCreate(t *testing.T) { @@ -47,10 +73,7 @@ func TestTemplateCreate(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) coderdtest.CreateFirstUser(t, client) - source := clitest.CreateTemplateVersionSource(t, &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionApply: provisionCompleteWithAgent, - }) + source := clitest.CreateTemplateVersionSource(t, completeWithAgent()) args := []string{ "templates", "create", @@ -85,10 +108,7 @@ func TestTemplateCreate(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) coderdtest.CreateFirstUser(t, client) - source := clitest.CreateTemplateVersionSource(t, &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionApply: provisionCompleteWithAgent, - }) + source := clitest.CreateTemplateVersionSource(t, completeWithAgent()) require.NoError(t, os.Remove(filepath.Join(source, ".terraform.lock.hcl"))) args := []string{ "templates", @@ -128,10 +148,7 @@ func TestTemplateCreate(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) coderdtest.CreateFirstUser(t, client) - source := clitest.CreateTemplateVersionSource(t, &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionApply: provisionCompleteWithAgent, - }) + source := clitest.CreateTemplateVersionSource(t, completeWithAgent()) require.NoError(t, os.Remove(filepath.Join(source, ".terraform.lock.hcl"))) args := []string{ "templates", @@ -167,10 +184,7 @@ func TestTemplateCreate(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) coderdtest.CreateFirstUser(t, client) - source, err := echo.Tar(&echo.Responses{ - Parse: echo.ParseComplete, - ProvisionApply: provisionCompleteWithAgent, - }) + source, err := echo.Tar(completeWithAgent()) require.NoError(t, err) args := []string{ @@ -196,10 +210,7 @@ func TestTemplateCreate(t *testing.T) { coderdtest.CreateFirstUser(t, client) create := func() error { - source := clitest.CreateTemplateVersionSource(t, &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionApply: provisionCompleteWithAgent, - }) + source := clitest.CreateTemplateVersionSource(t, completeWithAgent()) args := []string{ "templates", "create", diff --git a/cli/templatepull_test.go b/cli/templatepull_test.go index f6d8ececc9..95b0a6cf9a 100644 --- a/cli/templatepull_test.go +++ b/cli/templatepull_test.go @@ -205,9 +205,9 @@ func TestTemplatePull(t *testing.T) { // a template version source. func genTemplateVersionSource() *echo.Responses { return &echo.Responses{ - Parse: []*proto.Parse_Response{ + Parse: []*proto.Response{ { - Type: &proto.Parse_Response_Log{ + Type: &proto.Response_Log{ Log: &proto.Log{ Output: uuid.NewString(), }, @@ -215,11 +215,11 @@ func genTemplateVersionSource() *echo.Responses { }, { - Type: &proto.Parse_Response_Complete{ - Complete: &proto.Parse_Complete{}, + Type: &proto.Response_Parse{ + Parse: &proto.ParseComplete{}, }, }, }, - ProvisionApply: echo.ProvisionComplete, + ProvisionApply: echo.ApplyComplete, } } diff --git a/cli/templatepush_test.go b/cli/templatepush_test.go index 4f2e00a359..4c41597802 100644 --- a/cli/templatepush_test.go +++ b/cli/templatepush_test.go @@ -38,7 +38,7 @@ func TestTemplatePush(t *testing.T) { // Test the cli command. source := clitest.CreateTemplateVersionSource(t, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionApply: echo.ApplyComplete, }) inv, root := clitest.New(t, "templates", "push", template.Name, "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho), "--name", "example") clitest.SetupConfig(t, client, root) @@ -82,7 +82,7 @@ func TestTemplatePush(t *testing.T) { template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) source := clitest.CreateTemplateVersionSource(t, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionApply: echo.ApplyComplete, }) wantMessage := strings.Repeat("a", 72) @@ -121,7 +121,7 @@ func TestTemplatePush(t *testing.T) { template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) source := clitest.CreateTemplateVersionSource(t, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionApply: echo.ApplyComplete, }) ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) @@ -168,7 +168,7 @@ func TestTemplatePush(t *testing.T) { // Test the cli command. source := clitest.CreateTemplateVersionSource(t, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionApply: echo.ApplyComplete, }) require.NoError(t, os.Remove(filepath.Join(source, ".terraform.lock.hcl"))) @@ -211,7 +211,7 @@ func TestTemplatePush(t *testing.T) { // Test the cli command. source := clitest.CreateTemplateVersionSource(t, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionApply: echo.ApplyComplete, }) require.NoError(t, os.Remove(filepath.Join(source, ".terraform.lock.hcl"))) @@ -248,7 +248,7 @@ func TestTemplatePush(t *testing.T) { // Test the cli command. source := clitest.CreateTemplateVersionSource(t, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionApply: echo.ApplyComplete, }) inv, root := clitest.New(t, "templates", "push", template.Name, "--activate=false", "--directory", source, "--test.provisioner", string(database.ProvisionerTypeEcho), "--name", "example") clitest.SetupConfig(t, client, root) @@ -293,7 +293,7 @@ func TestTemplatePush(t *testing.T) { // Test the cli command. source := clitest.CreateTemplateVersionSource(t, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionApply: echo.ApplyComplete, }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, @@ -340,7 +340,7 @@ func TestTemplatePush(t *testing.T) { source, err := echo.Tar(&echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionApply: echo.ApplyComplete, }) require.NoError(t, err) @@ -619,10 +619,7 @@ func TestTemplatePush(t *testing.T) { t.Parallel() client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) user := coderdtest.CreateFirstUser(t, client) - source := clitest.CreateTemplateVersionSource(t, &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionApply: provisionCompleteWithAgent, - }) + source := clitest.CreateTemplateVersionSource(t, completeWithAgent()) const templateName = "my-template" args := []string{ @@ -665,16 +662,16 @@ func TestTemplatePush(t *testing.T) { func createEchoResponsesWithTemplateVariables(templateVariables []*proto.TemplateVariable) *echo.Responses { return &echo.Responses{ - Parse: []*proto.Parse_Response{ + Parse: []*proto.Response{ { - Type: &proto.Parse_Response_Complete{ - Complete: &proto.Parse_Complete{ + Type: &proto.Response_Parse{ + Parse: &proto.ParseComplete{ TemplateVariables: templateVariables, }, }, }, }, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, + ProvisionApply: echo.ApplyComplete, } } diff --git a/cli/update_test.go b/cli/update_test.go index 57e49d0db3..0efa1f997c 100644 --- a/cli/update_test.go +++ b/cli/update_test.go @@ -57,8 +57,8 @@ func TestUpdate(t *testing.T) { version2 := coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: echo.ProvisionComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionApply: echo.ApplyComplete, + ProvisionPlan: echo.PlanComplete, }, template.ID) _ = coderdtest.AwaitTemplateVersionJob(t, client, version2.ID) @@ -100,28 +100,13 @@ func TestUpdateWithRichParameters(t *testing.T) { immutableParameterValue = "4" ) - echoResponses := &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ - { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Parameters: []*proto.RichParameter{ - {Name: firstParameterName, Description: firstParameterDescription, Mutable: true}, - {Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false}, - {Name: secondParameterName, Description: secondParameterDescription, Mutable: true}, - {Name: ephemeralParameterName, Description: ephemeralParameterDescription, Mutable: true, Ephemeral: true}, - }, - }, - }, - }, - }, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }}, - } + echoResponses := prepareEchoResponses([]*proto.RichParameter{ + {Name: firstParameterName, Description: firstParameterDescription, Mutable: true}, + {Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false}, + {Name: secondParameterName, Description: secondParameterDescription, Mutable: true}, + {Name: ephemeralParameterName, Description: ephemeralParameterDescription, Mutable: true, Ephemeral: true}, + }, + ) t.Run("ImmutableCannotBeCustomized", func(t *testing.T) { t.Parallel() @@ -313,28 +298,6 @@ func TestUpdateValidateRichParameters(t *testing.T) { {Name: boolParameterName, Type: "bool", Mutable: true}, } - prepareEchoResponses := func(richParameters []*proto.RichParameter) *echo.Responses { - return &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ - { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Parameters: richParameters, - }, - }, - }, - }, - ProvisionApply: []*proto.Provision_Response{ - { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }, - }, - } - } - t.Run("ValidateString", func(t *testing.T) { t.Parallel() diff --git a/coderd/activitybump_test.go b/coderd/activitybump_test.go index 15965f5ab1..8ce018a4e9 100644 --- a/coderd/activitybump_test.go +++ b/coderd/activitybump_test.go @@ -17,7 +17,6 @@ import ( "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/codersdk/agentsdk" "github.com/coder/coder/v2/provisioner/echo" - "github.com/coder/coder/v2/provisionersdk/proto" "github.com/coder/coder/v2/testutil" ) @@ -60,25 +59,9 @@ func TestWorkspaceActivityBump(t *testing.T) { ttlMillis := int64(ttl / time.Millisecond) agentToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Resources: []*proto.Resource{{ - Name: "example", - Type: "aws_instance", - Agents: []*proto.Agent{{ - Id: uuid.NewString(), - Name: "agent", - Auth: &proto.Agent_Token{ - Token: agentToken, - }, - }}, - }}, - }, - }, - }}, + Parse: echo.ParseComplete, + ProvisionPlan: echo.PlanComplete, + ProvisionApply: echo.ProvisionApplyWithAgent(agentToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) diff --git a/coderd/autobuild/lifecycle_executor_test.go b/coderd/autobuild/lifecycle_executor_test.go index 356926d9bb..7159f3b7d5 100644 --- a/coderd/autobuild/lifecycle_executor_test.go +++ b/coderd/autobuild/lifecycle_executor_test.go @@ -683,8 +683,8 @@ func TestExecutorFailedWorkspace(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: echo.ProvisionFailed, + ProvisionPlan: echo.PlanComplete, + ProvisionApply: echo.ApplyFailed, }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { ctr.FailureTTLMillis = ptr.Ref[int64](failureTTL.Milliseconds()) @@ -733,8 +733,8 @@ func TestExecutorInactiveWorkspace(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, + ProvisionApply: echo.ApplyComplete, }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { ctr.TimeTilDormantMillis = ptr.Ref[int64](inactiveTTL.Milliseconds()) @@ -766,22 +766,16 @@ func mustProvisionWorkspaceWithParameters(t *testing.T, client *codersdk.Client, user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ + ProvisionPlan: []*proto.Response{ { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ Parameters: richParameters, }, }, }, }, - ProvisionApply: []*proto.Provision_Response{ - { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }, - }, + ProvisionApply: echo.ApplyComplete, }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) diff --git a/coderd/coderd_test.go b/coderd/coderd_test.go index 1924c68439..6edf4657cc 100644 --- a/coderd/coderd_test.go +++ b/coderd/coderd_test.go @@ -181,7 +181,7 @@ func TestDERPForceWebSockets(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) diff --git a/coderd/coderdtest/coderdtest.go b/coderd/coderdtest/coderdtest.go index b915b9ffbd..18062a549a 100644 --- a/coderd/coderdtest/coderdtest.go +++ b/coderd/coderdtest/coderdtest.go @@ -37,7 +37,6 @@ import ( "github.com/google/uuid" "github.com/moby/moby/pkg/namesgenerator" "github.com/prometheus/client_golang/prometheus" - "github.com/spf13/afero" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "golang.org/x/oauth2" @@ -469,10 +468,13 @@ func NewProvisionerDaemon(t testing.TB, coderAPI *coderd.API) io.Closer { _ = echoServer.Close() cancelFunc() }) - fs := afero.NewMemMapFs() + // seems t.TempDir() is not safe to call from a different goroutine + workDir := t.TempDir() go func() { - err := echo.Serve(ctx, fs, &provisionersdk.ServeOptions{ - Listener: echoServer, + err := echo.Serve(ctx, &provisionersdk.ServeOptions{ + Listener: echoServer, + WorkDirectory: workDir, + Logger: coderAPI.Logger.Named("echo").Leveled(slog.LevelDebug), }) assert.NoError(t, err) }() @@ -480,7 +482,6 @@ func NewProvisionerDaemon(t testing.TB, coderAPI *coderd.API) io.Closer { closer := provisionerd.New(func(ctx context.Context) (provisionerdproto.DRPCProvisionerDaemonClient, error) { return coderAPI.CreateInMemoryProvisionerDaemon(ctx, 0) }, &provisionerd.Options{ - Filesystem: fs, Logger: coderAPI.Logger.Named("provisionerd").Leveled(slog.LevelDebug), JobPollInterval: 50 * time.Millisecond, UpdateInterval: 250 * time.Millisecond, @@ -488,7 +489,6 @@ func NewProvisionerDaemon(t testing.TB, coderAPI *coderd.API) io.Closer { Provisioners: provisionerd.Provisioners{ string(database.ProvisionerTypeEcho): sdkproto.NewDRPCProvisionerClient(echoClient), }, - WorkDirectory: t.TempDir(), }) t.Cleanup(func() { _ = closer.Close() @@ -506,11 +506,11 @@ func NewExternalProvisionerDaemon(t *testing.T, client *codersdk.Client, org uui cancelFunc() <-serveDone }) - fs := afero.NewMemMapFs() go func() { defer close(serveDone) - err := echo.Serve(ctx, fs, &provisionersdk.ServeOptions{ - Listener: echoServer, + err := echo.Serve(ctx, &provisionersdk.ServeOptions{ + Listener: echoServer, + WorkDirectory: t.TempDir(), }) assert.NoError(t, err) }() @@ -522,7 +522,6 @@ func NewExternalProvisionerDaemon(t *testing.T, client *codersdk.Client, org uui Tags: tags, }) }, &provisionerd.Options{ - Filesystem: fs, Logger: slogtest.Make(t, nil).Named("provisionerd").Leveled(slog.LevelDebug), JobPollInterval: 50 * time.Millisecond, UpdateInterval: 250 * time.Millisecond, @@ -530,7 +529,6 @@ func NewExternalProvisionerDaemon(t *testing.T, client *codersdk.Client, org uui Provisioners: provisionerd.Provisioners{ string(database.ProvisionerTypeEcho): sdkproto.NewDRPCProvisionerClient(echoClient), }, - WorkDirectory: t.TempDir(), }) t.Cleanup(func() { _ = closer.Close() diff --git a/coderd/gitauth_test.go b/coderd/gitauth_test.go index 6aa4d4735b..c0ad89a1b5 100644 --- a/coderd/gitauth_test.go +++ b/coderd/gitauth_test.go @@ -23,7 +23,6 @@ import ( "github.com/coder/coder/v2/codersdk" "github.com/coder/coder/v2/codersdk/agentsdk" "github.com/coder/coder/v2/provisioner/echo" - "github.com/coder/coder/v2/provisionersdk/proto" "github.com/coder/coder/v2/testutil" ) @@ -227,7 +226,7 @@ func TestGitAuthCallback(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -256,24 +255,9 @@ func TestGitAuthCallback(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ - Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Resources: []*proto.Resource{{ - Name: "example", - Type: "aws_instance", - Agents: []*proto.Agent{{ - Id: uuid.NewString(), - Auth: &proto.Agent_Token{ - Token: authToken, - }, - }}, - }}, - }, - }, - }}, + Parse: echo.ParseComplete, + ProvisionPlan: echo.PlanComplete, + ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) @@ -342,7 +326,7 @@ func TestGitAuthCallback(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -400,7 +384,7 @@ func TestGitAuthCallback(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -443,7 +427,7 @@ func TestGitAuthCallback(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) diff --git a/coderd/gitsshkey_test.go b/coderd/gitsshkey_test.go index a406ed6a1d..be1f43c52e 100644 --- a/coderd/gitsshkey_test.go +++ b/coderd/gitsshkey_test.go @@ -108,7 +108,7 @@ func TestAgentGitSSHKey(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) project := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) diff --git a/coderd/insights_test.go b/coderd/insights_test.go index 351905e9b6..83498bbb36 100644 --- a/coderd/insights_test.go +++ b/coderd/insights_test.go @@ -48,7 +48,7 @@ func TestDeploymentInsights(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -134,7 +134,7 @@ func TestUserLatencyInsights(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -498,18 +498,18 @@ func TestTemplateInsights_Golden(t *testing.T) { // Create the template version and template. version := coderdtest.CreateTemplateVersion(t, client, firstUser.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ + ProvisionPlan: []*proto.Response{ { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ Parameters: parameters, }, }, }, }, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: resources, }, }, diff --git a/coderd/prometheusmetrics/prometheusmetrics_test.go b/coderd/prometheusmetrics/prometheusmetrics_test.go index c6d65418cb..bf6f475ad1 100644 --- a/coderd/prometheusmetrics/prometheusmetrics_test.go +++ b/coderd/prometheusmetrics/prometheusmetrics_test.go @@ -268,10 +268,10 @@ func TestAgents(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", @@ -494,7 +494,7 @@ func prepareWorkspaceAndAgent(t *testing.T, client *codersdk.Client, user coders version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index efb942f8a3..f61606a142 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -280,7 +280,7 @@ func (server *Server) AcquireJob(ctx context.Context, _ *proto.Empty) (*proto.Ac RichParameterValues: convertRichParameterValues(workspaceBuildParameters), VariableValues: asVariableValues(templateVariables), GitAuthProviders: gitAuthProviders, - Metadata: &sdkproto.Provision_Metadata{ + Metadata: &sdkproto.Metadata{ CoderUrl: server.AccessURL.String(), WorkspaceTransition: transition, WorkspaceName: workspace.Name, @@ -316,7 +316,7 @@ func (server *Server) AcquireJob(ctx context.Context, _ *proto.Empty) (*proto.Ac TemplateDryRun: &proto.AcquiredJob_TemplateDryRun{ RichParameterValues: convertRichParameterValues(input.RichParameterValues), VariableValues: asVariableValues(templateVariables), - Metadata: &sdkproto.Provision_Metadata{ + Metadata: &sdkproto.Metadata{ CoderUrl: server.AccessURL.String(), WorkspaceName: input.WorkspaceName, }, @@ -337,7 +337,7 @@ func (server *Server) AcquireJob(ctx context.Context, _ *proto.Empty) (*proto.Ac protoJob.Type = &proto.AcquiredJob_TemplateImport_{ TemplateImport: &proto.AcquiredJob_TemplateImport{ UserVariableValues: convertVariableValues(userVariableValues), - Metadata: &sdkproto.Provision_Metadata{ + Metadata: &sdkproto.Metadata{ CoderUrl: server.AccessURL.String(), }, }, diff --git a/coderd/provisionerdserver/provisionerdserver_test.go b/coderd/provisionerdserver/provisionerdserver_test.go index f539337224..5a317cd531 100644 --- a/coderd/provisionerdserver/provisionerdserver_test.go +++ b/coderd/provisionerdserver/provisionerdserver_test.go @@ -267,7 +267,7 @@ func TestAcquireJob(t *testing.T) { Id: gitAuthProvider, AccessToken: "access_token", }}, - Metadata: &sdkproto.Provision_Metadata{ + Metadata: &sdkproto.Metadata{ CoderUrl: srv.AccessURL.String(), WorkspaceTransition: sdkproto.WorkspaceTransition_START, WorkspaceName: workspace.Name, @@ -359,7 +359,7 @@ func TestAcquireJob(t *testing.T) { want, err := json.Marshal(&proto.AcquiredJob_TemplateDryRun_{ TemplateDryRun: &proto.AcquiredJob_TemplateDryRun{ - Metadata: &sdkproto.Provision_Metadata{ + Metadata: &sdkproto.Metadata{ CoderUrl: srv.AccessURL.String(), WorkspaceName: "testing", }, @@ -391,7 +391,7 @@ func TestAcquireJob(t *testing.T) { want, err := json.Marshal(&proto.AcquiredJob_TemplateImport_{ TemplateImport: &proto.AcquiredJob_TemplateImport{ - Metadata: &sdkproto.Provision_Metadata{ + Metadata: &sdkproto.Metadata{ CoderUrl: srv.AccessURL.String(), }, }, @@ -434,7 +434,7 @@ func TestAcquireJob(t *testing.T) { UserVariableValues: []*sdkproto.VariableValue{ {Name: "first", Sensitive: true, Value: "first_value"}, }, - Metadata: &sdkproto.Provision_Metadata{ + Metadata: &sdkproto.Metadata{ CoderUrl: srv.AccessURL.String(), }, }, diff --git a/coderd/provisionerjobs_test.go b/coderd/provisionerjobs_test.go index 0bfd00e46a..5d1715a9fe 100644 --- a/coderd/provisionerjobs_test.go +++ b/coderd/provisionerjobs_test.go @@ -20,16 +20,16 @@ func TestProvisionerJobLogs(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Log{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Log{ Log: &proto.Log{ Level: proto.LogLevel_INFO, Output: "log-output", }, }, }, { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{}, }, }}, }) @@ -59,16 +59,16 @@ func TestProvisionerJobLogs(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Log{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Log{ Log: &proto.Log{ Level: proto.LogLevel_INFO, Output: "log-output", }, }, }, { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{}, }, }}, }) diff --git a/coderd/templates_test.go b/coderd/templates_test.go index fcdb7e64e2..403370b5da 100644 --- a/coderd/templates_test.go +++ b/coderd/templates_test.go @@ -1203,7 +1203,7 @@ func TestTemplateMetrics(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) diff --git a/coderd/templateversions_test.go b/coderd/templateversions_test.go index f81b29ee82..d06e68fabb 100644 --- a/coderd/templateversions_test.go +++ b/coderd/templateversions_test.go @@ -136,8 +136,8 @@ func TestPostTemplateVersionsByOrganization(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) data, err := echo.Tar(&echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: echo.ProvisionComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionApply: echo.ApplyComplete, + ProvisionPlan: echo.PlanComplete, }) require.NoError(t, err) @@ -245,8 +245,8 @@ func TestPatchCancelTemplateVersion(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Log{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Log{ Log: &proto.Log{}, }, }}, @@ -284,8 +284,8 @@ func TestPatchCancelTemplateVersion(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Log{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Log{ Log: &proto.Log{}, }, }}, @@ -346,9 +346,9 @@ func TestTemplateVersionsGitAuth(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: []*proto.Response{{ + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ GitAuthProviders: []string{"github"}, }, }, @@ -400,9 +400,9 @@ func TestTemplateVersionResources(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "some", Type: "example", @@ -439,17 +439,17 @@ func TestTemplateVersionLogs(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Log{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Log{ Log: &proto.Log{ Level: proto.LogLevel_INFO, Output: "example", }, }, }, { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "some", Type: "example", @@ -610,15 +610,15 @@ func TestTemplateVersionDryRun(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{ + ProvisionApply: []*proto.Response{ { - Type: &proto.Provision_Response_Log{ + Type: &proto.Response_Log{ Log: &proto.Log{}, }, }, { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{resource}, }, }, @@ -677,8 +677,8 @@ func TestTemplateVersionDryRun(t *testing.T) { // This import job will never finish version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Log{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Log{ Log: &proto.Log{}, }, }}, @@ -705,15 +705,15 @@ func TestTemplateVersionDryRun(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{ + ProvisionApply: []*proto.Response{ { - Type: &proto.Provision_Response_Log{ + Type: &proto.Response_Log{ Log: &proto.Log{}, }, }, { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{}, }, }, }, @@ -776,15 +776,15 @@ func TestTemplateVersionDryRun(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{ + ProvisionApply: []*proto.Response{ { - Type: &proto.Provision_Response_Log{ + Type: &proto.Response_Log{ Log: &proto.Log{}, }, }, { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{}, }, }, }, @@ -1040,21 +1040,17 @@ func TestTemplateVersionVariables(t *testing.T) { createEchoResponses := func(templateVariables []*proto.TemplateVariable) *echo.Responses { return &echo.Responses{ - Parse: []*proto.Parse_Response{ + Parse: []*proto.Response{ { - Type: &proto.Parse_Response_Complete{ - Complete: &proto.Parse_Complete{ + Type: &proto.Response_Parse{ + Parse: &proto.ParseComplete{ TemplateVariables: templateVariables, }, }, }, }, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }}, + ProvisionPlan: echo.PlanComplete, + ProvisionApply: echo.ApplyComplete, } } @@ -1418,10 +1414,10 @@ func TestTemplateVersionParameters_Order(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ + ProvisionPlan: []*proto.Response{ { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ Parameters: []*proto.RichParameter{ { Name: firstParameterName, @@ -1453,11 +1449,7 @@ func TestTemplateVersionParameters_Order(t *testing.T) { }, }, }, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }}, + ProvisionApply: echo.ApplyComplete, }) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) diff --git a/coderd/workspaceagents_test.go b/coderd/workspaceagents_test.go index 48a399cee3..43694e95e6 100644 --- a/coderd/workspaceagents_test.go +++ b/coderd/workspaceagents_test.go @@ -43,10 +43,10 @@ func TestWorkspaceAgent(t *testing.T) { tmpDir := t.TempDir() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", @@ -87,10 +87,10 @@ func TestWorkspaceAgent(t *testing.T) { tmpDir := t.TempDir() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", @@ -132,10 +132,10 @@ func TestWorkspaceAgent(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", @@ -188,10 +188,10 @@ func TestWorkspaceAgentStartupLogs(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", @@ -252,10 +252,10 @@ func TestWorkspaceAgentStartupLogs(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", @@ -319,7 +319,7 @@ func TestWorkspaceAgentListen(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -360,7 +360,7 @@ func TestWorkspaceAgentListen(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) @@ -371,10 +371,10 @@ func TestWorkspaceAgentListen(t *testing.T) { version = coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", @@ -419,7 +419,7 @@ func TestWorkspaceAgentTailnet(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -471,7 +471,7 @@ func TestWorkspaceAgentTailnetDirectDisabled(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -548,10 +548,10 @@ func TestWorkspaceAgentListeningPorts(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", @@ -806,9 +806,9 @@ func TestWorkspaceAgentAppHealth(t *testing.T) { } version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", @@ -893,7 +893,7 @@ func TestWorkspaceAgentReportStats(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -942,7 +942,7 @@ func TestWorkspaceAgent_LifecycleState(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -1014,10 +1014,10 @@ func TestWorkspaceAgent_Metadata(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", @@ -1184,7 +1184,7 @@ func TestWorkspaceAgent_Startup(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -1238,7 +1238,7 @@ func TestWorkspaceAgent_Startup(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -1293,7 +1293,7 @@ func TestWorkspaceAgent_UpdatedDERP(t *testing.T) { agentToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(agentToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) diff --git a/coderd/workspaceapps/apptest/setup.go b/coderd/workspaceapps/apptest/setup.go index 9d9a804901..6ab541f078 100644 --- a/coderd/workspaceapps/apptest/setup.go +++ b/coderd/workspaceapps/apptest/setup.go @@ -288,10 +288,10 @@ func createWorkspaceWithApps(t *testing.T, client *codersdk.Client, orgID uuid.U appURL := fmt.Sprintf("%s://127.0.0.1:%d?%s", scheme, port, proxyTestAppQuery) version := coderdtest.CreateTemplateVersion(t, client, orgID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", diff --git a/coderd/workspaceapps/db_test.go b/coderd/workspaceapps/db_test.go index 1783fcec17..163247f6d4 100644 --- a/coderd/workspaceapps/db_test.go +++ b/coderd/workspaceapps/db_test.go @@ -94,10 +94,10 @@ func Test_ResolveRequest(t *testing.T) { agentAuthToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, firstUser.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", diff --git a/coderd/workspacebuilds_test.go b/coderd/workspacebuilds_test.go index cd62f6a750..0ee810e3e3 100644 --- a/coderd/workspacebuilds_test.go +++ b/coderd/workspacebuilds_test.go @@ -376,12 +376,12 @@ func TestPatchCancelWorkspaceBuild(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Log{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Log{ Log: &proto.Log{}, }, }}, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, }) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -401,11 +401,12 @@ func TestPatchCancelWorkspaceBuild(t *testing.T) { require.Eventually(t, func() bool { var err error build, err = client.WorkspaceBuild(ctx, build.ID) + // job gets marked Failed when there is an Error; in practice we never get to Status = Canceled + // because provisioners report an Error when canceled. We check the Error string to ensure we don't mask + // other errors in this test. return assert.NoError(t, err) && - // The job will never actually cancel successfully because it will never send a - // provision complete response. - assert.Empty(t, build.Job.Error) && - build.Job.Status == codersdk.ProvisionerJobCanceling + build.Job.Error == "canceled" && + build.Job.Status == codersdk.ProvisionerJobFailed }, testutil.WaitShort, testutil.IntervalFast) }) t.Run("User is not allowed to cancel", func(t *testing.T) { @@ -415,12 +416,12 @@ func TestPatchCancelWorkspaceBuild(t *testing.T) { owner := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, owner.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Log{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Log{ Log: &proto.Log{}, }, }}, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, }) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) template := coderdtest.CreateTemplate(t, client, owner.OrganizationID, version.ID) @@ -452,9 +453,9 @@ func TestWorkspaceBuildResources(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "some", Type: "example", @@ -494,16 +495,16 @@ func TestWorkspaceBuildLogs(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Log{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Log{ Log: &proto.Log{ Level: proto.LogLevel_INFO, Output: "example", }, }, }, { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "some", Type: "example", @@ -548,10 +549,10 @@ func TestWorkspaceBuildState(t *testing.T) { wantState := []byte("some kinda state") version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ State: wantState, }, }, @@ -764,31 +765,31 @@ func TestWorkspaceBuildDebugMode(t *testing.T) { // Interact as template admin echoResponses := &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Log{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Log{ Log: &proto.Log{ Level: proto.LogLevel_DEBUG, Output: "want-it", }, }, }, { - Type: &proto.Provision_Response_Log{ + Type: &proto.Response_Log{ Log: &proto.Log{ Level: proto.LogLevel_TRACE, Output: "dont-want-it", }, }, }, { - Type: &proto.Provision_Response_Log{ + Type: &proto.Response_Log{ Log: &proto.Log{ Level: proto.LogLevel_DEBUG, Output: "done", }, }, }, { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{}, }, }}, } @@ -831,7 +832,10 @@ func TestWorkspaceBuildDebugMode(t *testing.T) { if !ok { break processingLogs } - + t.Logf("got log: %s -- %s | %s | %s", log.Level, log.Stage, log.Source, log.Output) + if log.Source != "provisioner" { + continue + } logsProcessed++ require.NotEqual(t, "dont-want-it", log.Output, "unexpected log message", "%s log message shouldn't be logged: %s") @@ -841,7 +845,6 @@ func TestWorkspaceBuildDebugMode(t *testing.T) { } } } - - require.Len(t, echoResponses.ProvisionApply, logsProcessed) + require.Equal(t, 2, logsProcessed) }) } diff --git a/coderd/workspaceresourceauth_test.go b/coderd/workspaceresourceauth_test.go index feadc62dde..fdf1bd2335 100644 --- a/coderd/workspaceresourceauth_test.go +++ b/coderd/workspaceresourceauth_test.go @@ -26,9 +26,9 @@ func TestPostWorkspaceAuthAzureInstanceIdentity(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "somename", Type: "someinstance", @@ -71,9 +71,9 @@ func TestPostWorkspaceAuthAWSInstanceIdentity(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "somename", Type: "someinstance", @@ -157,9 +157,9 @@ func TestPostWorkspaceAuthGoogleInstanceIdentity(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "somename", Type: "someinstance", diff --git a/coderd/workspaces_test.go b/coderd/workspaces_test.go index ebedb8497d..8da37158b1 100644 --- a/coderd/workspaces_test.go +++ b/coderd/workspaces_test.go @@ -174,9 +174,9 @@ func TestWorkspace(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "some", Type: "example", @@ -214,9 +214,9 @@ func TestWorkspace(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "some", Type: "example", @@ -258,9 +258,9 @@ func TestWorkspace(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "some", Type: "example", @@ -1248,7 +1248,7 @@ func TestWorkspaceFilterManual(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -1276,7 +1276,7 @@ func TestWorkspaceFilterManual(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -1316,10 +1316,10 @@ func TestWorkspaceFilterManual(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", @@ -1374,7 +1374,7 @@ func TestWorkspaceFilterManual(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -1418,7 +1418,7 @@ func TestWorkspaceFilterManual(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -1457,7 +1457,7 @@ func TestWorkspaceFilterManual(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -1575,7 +1575,7 @@ func TestPostWorkspaceBuild(t *testing.T) { client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ - ProvisionApply: []*proto.Provision_Response{{}}, + ProvisionApply: []*proto.Response{{}}, }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) @@ -2138,10 +2138,10 @@ func TestWorkspaceWatcher(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", @@ -2231,10 +2231,10 @@ func TestWorkspaceWatcher(t *testing.T) { // Add a new version that will fail. badVersion := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Error: "test error", }, }, @@ -2299,9 +2299,9 @@ func TestWorkspaceResource(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "beta", Type: "example", @@ -2367,9 +2367,9 @@ func TestWorkspaceResource(t *testing.T) { } version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "some", Type: "example", @@ -2424,9 +2424,9 @@ func TestWorkspaceResource(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "some", Type: "example", @@ -2497,10 +2497,10 @@ func TestWorkspaceWithRichParameters(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ + ProvisionPlan: []*proto.Response{ { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ Parameters: []*proto.RichParameter{ { Name: firstParameterName, @@ -2521,9 +2521,9 @@ func TestWorkspaceWithRichParameters(t *testing.T) { }, }, }, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{}, }, }}, }) @@ -2590,10 +2590,10 @@ func TestWorkspaceWithOptionalRichParameters(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ + ProvisionPlan: []*proto.Response{ { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ Parameters: []*proto.RichParameter{ { Name: firstParameterName, @@ -2612,9 +2612,9 @@ func TestWorkspaceWithOptionalRichParameters(t *testing.T) { }, }, }, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{}, }, }}, }) @@ -2681,10 +2681,10 @@ func TestWorkspaceWithEphemeralRichParameters(t *testing.T) { user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{ + ProvisionPlan: []*proto.Response{ { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ Parameters: []*proto.RichParameter{ { Name: firstParameterName, @@ -2706,9 +2706,9 @@ func TestWorkspaceWithEphemeralRichParameters(t *testing.T) { }, }, }, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{}, }, }}, }) diff --git a/enterprise/cli/provisionerdaemons.go b/enterprise/cli/provisionerdaemons.go index 82d853503a..e46756578d 100644 --- a/enterprise/cli/provisionerdaemons.go +++ b/enterprise/cli/provisionerdaemons.go @@ -70,6 +70,11 @@ func (r *RootCmd) provisionerDaemonStart() *clibase.Cmd { return xerrors.Errorf("mkdir %q: %w", cacheDir, err) } + tempDir, err := os.MkdirTemp("", "provisionerd") + if err != nil { + return err + } + terraformClient, terraformServer := provisionersdk.MemTransportPipe() go func() { <-ctx.Done() @@ -84,10 +89,11 @@ func (r *RootCmd) provisionerDaemonStart() *clibase.Cmd { err := terraform.Serve(ctx, &terraform.ServeOptions{ ServeOptions: &provisionersdk.ServeOptions{ - Listener: terraformServer, + Listener: terraformServer, + Logger: logger.Named("terraform"), + WorkDirectory: tempDir, }, CachePath: cacheDir, - Logger: logger.Named("terraform"), }) if err != nil && !xerrors.Is(err, context.Canceled) { select { @@ -97,11 +103,6 @@ func (r *RootCmd) provisionerDaemonStart() *clibase.Cmd { } }() - tempDir, err := os.MkdirTemp("", "provisionerd") - if err != nil { - return err - } - logger.Info(ctx, "starting provisioner daemon", slog.F("tags", tags)) provisioners := provisionerd.Provisioners{ @@ -121,7 +122,6 @@ func (r *RootCmd) provisionerDaemonStart() *clibase.Cmd { JobPollJitter: pollJitter, UpdateInterval: 500 * time.Millisecond, Provisioners: provisioners, - WorkDirectory: tempDir, }) var exitErr error diff --git a/enterprise/coderd/appearance_test.go b/enterprise/coderd/appearance_test.go index 2cf7259044..8ee2c07137 100644 --- a/enterprise/coderd/appearance_test.go +++ b/enterprise/coderd/appearance_test.go @@ -111,7 +111,7 @@ func TestServiceBanners(t *testing.T) { agentClient.SetSessionToken(authToken) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, ProvisionApply: echo.ProvisionApplyWithAgent(authToken), }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) diff --git a/enterprise/coderd/provisionerdaemons_test.go b/enterprise/coderd/provisionerdaemons_test.go index d9b688fab8..e190a3df90 100644 --- a/enterprise/coderd/provisionerdaemons_test.go +++ b/enterprise/coderd/provisionerdaemons_test.go @@ -139,9 +139,9 @@ func TestProvisionerDaemonServe(t *testing.T) { authToken := uuid.NewString() data, err := echo.Tar(&echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: []*proto.Response{{ + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", diff --git a/enterprise/coderd/workspaceagents_test.go b/enterprise/coderd/workspaceagents_test.go index 52e59858f5..5b7ecbe1bc 100644 --- a/enterprise/coderd/workspaceagents_test.go +++ b/enterprise/coderd/workspaceagents_test.go @@ -73,9 +73,9 @@ func setupWorkspaceAgent(t *testing.T, client *codersdk.Client, user codersdk.Cr authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", diff --git a/enterprise/coderd/workspacequota_test.go b/enterprise/coderd/workspacequota_test.go index 3119168696..69c9a4bc3d 100644 --- a/enterprise/coderd/workspacequota_test.go +++ b/enterprise/coderd/workspacequota_test.go @@ -89,9 +89,9 @@ func TestWorkspaceQuota(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", @@ -183,39 +183,15 @@ func TestWorkspaceQuota(t *testing.T) { require.NoError(t, err) verifyQuota(ctx, t, client, 0, 4) - stopResp := []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Resources: []*proto.Resource{{ - Name: "example", - Type: "aws_instance", - DailyCost: 1, - }}, - }, - }, - }} - - startResp := []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Resources: []*proto.Resource{{ - Name: "example", - Type: "aws_instance", - DailyCost: 2, - }}, - }, - }, - }} - version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlanMap: map[proto.WorkspaceTransition][]*proto.Provision_Response{ - proto.WorkspaceTransition_START: startResp, - proto.WorkspaceTransition_STOP: stopResp, + ProvisionPlanMap: map[proto.WorkspaceTransition][]*proto.Response{ + proto.WorkspaceTransition_START: planWithCost(2), + proto.WorkspaceTransition_STOP: planWithCost(1), }, - ProvisionApplyMap: map[proto.WorkspaceTransition][]*proto.Provision_Response{ - proto.WorkspaceTransition_START: startResp, - proto.WorkspaceTransition_STOP: stopResp, + ProvisionApplyMap: map[proto.WorkspaceTransition][]*proto.Response{ + proto.WorkspaceTransition_START: applyWithCost(2), + proto.WorkspaceTransition_STOP: applyWithCost(1), }, }) @@ -258,3 +234,31 @@ func TestWorkspaceQuota(t *testing.T) { require.Equal(t, codersdk.WorkspaceStatusRunning, build.Status) }) } + +func planWithCost(cost int32) []*proto.Response { + return []*proto.Response{{ + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ + Resources: []*proto.Resource{{ + Name: "example", + Type: "aws_instance", + DailyCost: cost, + }}, + }, + }, + }} +} + +func applyWithCost(cost int32) []*proto.Response { + return []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ + Resources: []*proto.Resource{{ + Name: "example", + Type: "aws_instance", + DailyCost: cost, + }}, + }, + }, + }} +} diff --git a/enterprise/coderd/workspaces_test.go b/enterprise/coderd/workspaces_test.go index 373b79c78d..db14ae96f1 100644 --- a/enterprise/coderd/workspaces_test.go +++ b/enterprise/coderd/workspaces_test.go @@ -120,8 +120,8 @@ func TestWorkspaceAutobuild(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: echo.ProvisionFailed, + ProvisionPlan: echo.PlanComplete, + ProvisionApply: echo.ApplyFailed, }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { ctr.FailureTTLMillis = ptr.Ref[int64](failureTTL.Milliseconds()) @@ -166,8 +166,8 @@ func TestWorkspaceAutobuild(t *testing.T) { }) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: echo.ProvisionFailed, + ProvisionPlan: echo.PlanComplete, + ProvisionApply: echo.ApplyFailed, }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { ctr.FailureTTLMillis = ptr.Ref[int64](failureTTL.Milliseconds()) @@ -212,8 +212,8 @@ func TestWorkspaceAutobuild(t *testing.T) { }) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, + ProvisionApply: echo.ApplyComplete, }) // Create a template without setting a failure_ttl. template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) @@ -255,8 +255,8 @@ func TestWorkspaceAutobuild(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, + ProvisionApply: echo.ApplyComplete, }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { ctr.TimeTilDormantMillis = ptr.Ref[int64](inactiveTTL.Milliseconds()) @@ -311,8 +311,8 @@ func TestWorkspaceAutobuild(t *testing.T) { }) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, + ProvisionApply: echo.ApplyComplete, }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { ctr.TimeTilDormantMillis = ptr.Ref[int64](inactiveTTL.Milliseconds()) @@ -353,8 +353,8 @@ func TestWorkspaceAutobuild(t *testing.T) { }) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, + ProvisionApply: echo.ApplyComplete, }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { ctr.TimeTilDormantAutoDeleteMillis = ptr.Ref[int64](autoDeleteTTL.Milliseconds()) @@ -395,8 +395,8 @@ func TestWorkspaceAutobuild(t *testing.T) { }) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, + ProvisionApply: echo.ApplyComplete, }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { ctr.TimeTilDormantMillis = ptr.Ref[int64](inactiveTTL.Milliseconds()) @@ -447,8 +447,8 @@ func TestWorkspaceAutobuild(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, + ProvisionApply: echo.ApplyComplete, }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { ctr.TimeTilDormantMillis = ptr.Ref[int64](transitionTTL.Milliseconds()) @@ -516,8 +516,8 @@ func TestWorkspaceAutobuild(t *testing.T) { }) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, + ProvisionApply: echo.ApplyComplete, }) template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID, func(ctr *codersdk.CreateTemplateRequest) { ctr.TimeTilDormantAutoDeleteMillis = ptr.Ref[int64](dormantTTL.Milliseconds()) @@ -578,8 +578,8 @@ func TestWorkspaceAutobuild(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: echo.ProvisionComplete, + ProvisionPlan: echo.PlanComplete, + ProvisionApply: echo.ApplyComplete, }) coderdtest.AwaitTemplateVersionJob(t, client, version.ID) diff --git a/provisioner/echo/serve.go b/provisioner/echo/serve.go index c057254704..9e22157bc3 100644 --- a/provisioner/echo/serve.go +++ b/provisioner/echo/serve.go @@ -5,25 +5,24 @@ import ( "bytes" "context" "fmt" + "os" "path/filepath" "strings" + "github.com/google/uuid" "golang.org/x/xerrors" protobuf "google.golang.org/protobuf/proto" - "github.com/google/uuid" - "github.com/spf13/afero" - "github.com/coder/coder/v2/provisionersdk" "github.com/coder/coder/v2/provisionersdk/proto" ) // ProvisionApplyWithAgent returns provision responses that will mock a fake // "aws_instance" resource with an agent that has the given auth token. -func ProvisionApplyWithAgent(authToken string) []*proto.Provision_Response { - return []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ +func ProvisionApplyWithAgent(authToken string) []*proto.Response { + return []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", @@ -42,23 +41,36 @@ func ProvisionApplyWithAgent(authToken string) []*proto.Provision_Response { var ( // ParseComplete is a helper to indicate an empty parse completion. - ParseComplete = []*proto.Parse_Response{{ - Type: &proto.Parse_Response_Complete{ - Complete: &proto.Parse_Complete{}, + ParseComplete = []*proto.Response{{ + Type: &proto.Response_Parse{ + Parse: &proto.ParseComplete{}, }, }} - // ProvisionComplete is a helper to indicate an empty provision completion. - ProvisionComplete = []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, + // PlanComplete is a helper to indicate an empty provision completion. + PlanComplete = []*proto.Response{{ + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{}, + }, + }} + // ApplyComplete is a helper to indicate an empty provision completion. + ApplyComplete = []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{}, }, }} - // ProvisionFailed is a helper to convey a failed provision - // operation. - ProvisionFailed = []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + // PlanFailed is a helper to convey a failed plan operation + PlanFailed = []*proto.Response{{ + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ + Error: "failed!", + }, + }, + }} + // ApplyFailed is a helper to convey a failed apply operation + ApplyFailed = []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Error: "failed!", }, }, @@ -66,120 +78,116 @@ var ( ) // Serve starts the echo provisioner. -func Serve(ctx context.Context, filesystem afero.Fs, options *provisionersdk.ServeOptions) error { - return provisionersdk.Serve(ctx, &echo{ - filesystem: filesystem, - }, options) +func Serve(ctx context.Context, options *provisionersdk.ServeOptions) error { + return provisionersdk.Serve(ctx, &echo{}, options) } // The echo provisioner serves as a dummy provisioner primarily // used for testing. It echos responses from JSON files in the // format %d.protobuf. It's used for testing. -type echo struct { - filesystem afero.Fs +type echo struct{} + +func readResponses(sess *provisionersdk.Session, trans string, suffix string) ([]*proto.Response, error) { + var responses []*proto.Response + for i := 0; ; i++ { + paths := []string{ + // Try more specific path first, then fallback to generic. + filepath.Join(sess.WorkDirectory, fmt.Sprintf("%d.%s.%s", i, trans, suffix)), + filepath.Join(sess.WorkDirectory, fmt.Sprintf("%d.%s", i, suffix)), + } + for pathIndex, path := range paths { + _, err := os.Stat(path) + if err != nil && pathIndex == (len(paths)-1) { + // If there are zero messages, something is wrong + if i == 0 { + // Error if nothing is around to enable failed states. + return nil, xerrors.Errorf("no state: %w", err) + } + // Otherwise, we've read all responses + return responses, nil + } + if err != nil { + // try next path + continue + } + data, err := os.ReadFile(path) + if err != nil { + return nil, xerrors.Errorf("read file %q: %w", path, err) + } + response := new(proto.Response) + err = protobuf.Unmarshal(data, response) + if err != nil { + return nil, xerrors.Errorf("unmarshal: %w", err) + } + responses = append(responses, response) + break + } + } } // Parse reads requests from the provided directory to stream responses. -func (e *echo) Parse(request *proto.Parse_Request, stream proto.DRPCProvisioner_ParseStream) error { - for index := 0; ; index++ { - path := filepath.Join(request.Directory, fmt.Sprintf("%d.parse.protobuf", index)) - _, err := e.filesystem.Stat(path) - if err != nil { - if index == 0 { - // Error if nothing is around to enable failed states. - return xerrors.Errorf("no state: %w", err) - } - break +func (*echo) Parse(sess *provisionersdk.Session, _ *proto.ParseRequest, _ <-chan struct{}) *proto.ParseComplete { + responses, err := readResponses(sess, "unspecified", "parse.protobuf") + if err != nil { + return &proto.ParseComplete{Error: err.Error()} + } + for _, response := range responses { + if log := response.GetLog(); log != nil { + sess.ProvisionLog(log.Level, log.Output) } - data, err := afero.ReadFile(e.filesystem, path) - if err != nil { - return xerrors.Errorf("read file %q: %w", path, err) - } - var response proto.Parse_Response - err = protobuf.Unmarshal(data, &response) - if err != nil { - return xerrors.Errorf("unmarshal: %w", err) - } - err = stream.Send(&response) - if err != nil { - return err + if complete := response.GetParse(); complete != nil { + return complete } } - <-stream.Context().Done() - return stream.Context().Err() + + // if we didn't get a complete from the filesystem, that's an error + return provisionersdk.ParseErrorf("complete response missing") } -// Provision reads requests from the provided directory to stream responses. -func (e *echo) Provision(stream proto.DRPCProvisioner_ProvisionStream) error { - msg, err := stream.Recv() +// Plan reads requests from the provided directory to stream responses. +func (*echo) Plan(sess *provisionersdk.Session, req *proto.PlanRequest, canceledOrComplete <-chan struct{}) *proto.PlanComplete { + responses, err := readResponses( + sess, + strings.ToLower(req.GetMetadata().GetWorkspaceTransition().String()), + "plan.protobuf") if err != nil { - return err + return &proto.PlanComplete{Error: err.Error()} + } + for _, response := range responses { + if log := response.GetLog(); log != nil { + sess.ProvisionLog(log.Level, log.Output) + } + if complete := response.GetPlan(); complete != nil { + return complete + } } - var config *proto.Provision_Config - switch { - case msg.GetPlan() != nil: - config = msg.GetPlan().GetConfig() - case msg.GetApply() != nil: - config = msg.GetApply().GetConfig() - default: - // Probably a cancel - return nil + // some tests use Echo without a complete response to test cancel + <-canceledOrComplete + return provisionersdk.PlanErrorf("canceled") +} + +// Apply reads requests from the provided directory to stream responses. +func (*echo) Apply(sess *provisionersdk.Session, req *proto.ApplyRequest, canceledOrComplete <-chan struct{}) *proto.ApplyComplete { + responses, err := readResponses( + sess, + strings.ToLower(req.GetMetadata().GetWorkspaceTransition().String()), + "apply.protobuf") + if err != nil { + return &proto.ApplyComplete{Error: err.Error()} + } + for _, response := range responses { + if log := response.GetLog(); log != nil { + sess.ProvisionLog(log.Level, log.Output) + } + if complete := response.GetApply(); complete != nil { + return complete + } } -outer: - for i := 0; ; i++ { - var extension string - if msg.GetPlan() != nil { - extension = ".plan.protobuf" - } else { - extension = ".apply.protobuf" - } - var ( - path string - pathIndex int - ) - // Try more specific path first, then fallback to generic. - paths := []string{ - filepath.Join(config.Directory, fmt.Sprintf("%d.%s.provision"+extension, i, strings.ToLower(config.GetMetadata().GetWorkspaceTransition().String()))), - filepath.Join(config.Directory, fmt.Sprintf("%d.provision"+extension, i)), - } - for pathIndex, path = range paths { - _, err := e.filesystem.Stat(path) - if err != nil && pathIndex == len(paths)-1 { - // If there are zero messages, something is wrong. - if i == 0 { - // Error if nothing is around to enable failed states. - return xerrors.New("no state") - } - // Otherwise, we're done with the entire provision. - break outer - } else if err != nil { - continue - } - break - } - data, err := afero.ReadFile(e.filesystem, path) - if err != nil { - return xerrors.Errorf("read file %q: %w", path, err) - } - var response proto.Provision_Response - err = protobuf.Unmarshal(data, &response) - if err != nil { - return xerrors.Errorf("unmarshal: %w", err) - } - r, ok := filterLogResponses(config, &response) - if !ok { - continue - } - - err = stream.Send(r) - if err != nil { - return err - } - } - <-stream.Context().Done() - return stream.Context().Err() + // some tests use Echo without a complete response to test cancel + <-canceledOrComplete + return provisionersdk.ApplyErrorf("canceled") } func (*echo) Shutdown(_ context.Context, _ *proto.Empty) (*proto.Empty, error) { @@ -188,29 +196,42 @@ func (*echo) Shutdown(_ context.Context, _ *proto.Empty) (*proto.Empty, error) { // Responses is a collection of mocked responses to Provision operations. type Responses struct { - Parse []*proto.Parse_Response + Parse []*proto.Response // ProvisionApply and ProvisionPlan are used to mock ALL responses of // Apply and Plan, regardless of transition. - ProvisionApply []*proto.Provision_Response - ProvisionPlan []*proto.Provision_Response + ProvisionApply []*proto.Response + ProvisionPlan []*proto.Response // ProvisionApplyMap and ProvisionPlanMap are used to mock specific // transition responses. They are prioritized over the generic responses. - ProvisionApplyMap map[proto.WorkspaceTransition][]*proto.Provision_Response - ProvisionPlanMap map[proto.WorkspaceTransition][]*proto.Provision_Response + ProvisionApplyMap map[proto.WorkspaceTransition][]*proto.Response + ProvisionPlanMap map[proto.WorkspaceTransition][]*proto.Response } // Tar returns a tar archive of responses to provisioner operations. func Tar(responses *Responses) ([]byte, error) { if responses == nil { responses = &Responses{ - ParseComplete, ProvisionComplete, ProvisionComplete, + ParseComplete, ApplyComplete, PlanComplete, nil, nil, } } if responses.ProvisionPlan == nil { - responses.ProvisionPlan = responses.ProvisionApply + for _, resp := range responses.ProvisionApply { + if resp.GetLog() != nil { + responses.ProvisionPlan = append(responses.ProvisionPlan, resp) + continue + } + responses.ProvisionPlan = append(responses.ProvisionPlan, &proto.Response{ + Type: &proto.Response_Plan{Plan: &proto.PlanComplete{ + Error: resp.GetApply().GetError(), + Resources: resp.GetApply().GetResources(), + Parameters: resp.GetApply().GetParameters(), + GitAuthProviders: resp.GetApply().GetGitAuthProviders(), + }}, + }) + } } var buffer bytes.Buffer @@ -245,20 +266,20 @@ func Tar(responses *Responses) ([]byte, error) { } } for index, response := range responses.ProvisionApply { - err := writeProto(fmt.Sprintf("%d.provision.apply.protobuf", index), response) + err := writeProto(fmt.Sprintf("%d.apply.protobuf", index), response) if err != nil { return nil, err } } for index, response := range responses.ProvisionPlan { - err := writeProto(fmt.Sprintf("%d.provision.plan.protobuf", index), response) + err := writeProto(fmt.Sprintf("%d.plan.protobuf", index), response) if err != nil { return nil, err } } for trans, m := range responses.ProvisionApplyMap { for i, rs := range m { - err := writeProto(fmt.Sprintf("%d.%s.provision.apply.protobuf", i, strings.ToLower(trans.String())), rs) + err := writeProto(fmt.Sprintf("%d.%s.apply.protobuf", i, strings.ToLower(trans.String())), rs) if err != nil { return nil, err } @@ -266,7 +287,7 @@ func Tar(responses *Responses) ([]byte, error) { } for trans, m := range responses.ProvisionPlanMap { for i, rs := range m { - err := writeProto(fmt.Sprintf("%d.%s.provision.plan.protobuf", i, strings.ToLower(trans.String())), rs) + err := writeProto(fmt.Sprintf("%d.%s.plan.protobuf", i, strings.ToLower(trans.String())), rs) if err != nil { return nil, err } @@ -279,22 +300,14 @@ func Tar(responses *Responses) ([]byte, error) { return buffer.Bytes(), nil } -func filterLogResponses(config *proto.Provision_Config, response *proto.Provision_Response) (*proto.Provision_Response, bool) { - responseLog, ok := response.Type.(*proto.Provision_Response_Log) - if !ok { - // Pass all non-log responses - return response, true +func WithResources(resources []*proto.Resource) *Responses { + return &Responses{ + Parse: ParseComplete, + ProvisionApply: []*proto.Response{{Type: &proto.Response_Apply{Apply: &proto.ApplyComplete{ + Resources: resources, + }}}}, + ProvisionPlan: []*proto.Response{{Type: &proto.Response_Plan{Plan: &proto.PlanComplete{ + Resources: resources, + }}}}, } - - if config.ProvisionerLogLevel == "" { - // Don't change the default behavior of "echo" - return response, true - } - - provisionerLogLevel := proto.LogLevel_value[strings.ToUpper(config.ProvisionerLogLevel)] - if int32(responseLog.Log.Level) < provisionerLogLevel { - // Log level is not enabled - return nil, false - } - return response, true } diff --git a/provisioner/echo/serve_test.go b/provisioner/echo/serve_test.go index 01b283f8a5..6590f2ecaf 100644 --- a/provisioner/echo/serve_test.go +++ b/provisioner/echo/serve_test.go @@ -1,27 +1,23 @@ package echo_test import ( - "archive/tar" - "bytes" "context" - "io" - "os" - "path/filepath" "testing" - "github.com/spf13/afero" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/coder/coder/v2/provisioner/echo" "github.com/coder/coder/v2/provisionersdk" "github.com/coder/coder/v2/provisionersdk/proto" + "github.com/coder/coder/v2/testutil" ) func TestEcho(t *testing.T) { t.Parallel() - fs := afero.NewMemMapFs() + workdir := t.TempDir() + // Create an in-memory provisioner to communicate with. client, server := provisionersdk.MemTransportPipe() ctx, cancelFunc := context.WithCancel(context.Background()) @@ -31,8 +27,9 @@ func TestEcho(t *testing.T) { cancelFunc() }) go func() { - err := echo.Serve(ctx, fs, &provisionersdk.ServeOptions{ - Listener: server, + err := echo.Serve(ctx, &provisionersdk.ServeOptions{ + Listener: server, + WorkDirectory: workdir, }) assert.NoError(t, err) }() @@ -40,25 +37,39 @@ func TestEcho(t *testing.T) { t.Run("Parse", func(t *testing.T) { t.Parallel() + ctx, cancel := context.WithTimeout(ctx, testutil.WaitShort) + defer cancel() - responses := []*proto.Parse_Response{{ - Type: &proto.Parse_Response_Log{ - Log: &proto.Log{ - Output: "log-output", + responses := []*proto.Response{ + { + Type: &proto.Response_Log{ + Log: &proto.Log{ + Output: "log-output", + }, }, }, - }, { - Type: &proto.Parse_Response_Complete{ - Complete: &proto.Parse_Complete{}, + { + Type: &proto.Response_Parse{ + Parse: &proto.ParseComplete{}, + }, }, - }} + } data, err := echo.Tar(&echo.Responses{ Parse: responses, }) require.NoError(t, err) - client, err := api.Parse(ctx, &proto.Parse_Request{ - Directory: unpackTar(t, fs, data), - }) + client, err := api.Session(ctx) + require.NoError(t, err) + defer func() { + err := client.Close() + require.NoError(t, err) + }() + err = client.Send(&proto.Request{Type: &proto.Request_Config{Config: &proto.Config{ + TemplateSourceArchive: data, + }}}) + require.NoError(t, err) + + err = client.Send(&proto.Request{Type: &proto.Request_Parse{Parse: &proto.ParseRequest{}}}) require.NoError(t, err) log, err := client.Recv() require.NoError(t, err) @@ -70,95 +81,117 @@ func TestEcho(t *testing.T) { t.Run("Provision", func(t *testing.T) { t.Parallel() + ctx, cancel := context.WithTimeout(ctx, testutil.WaitShort) + defer cancel() - responses := []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Log{ - Log: &proto.Log{ - Level: proto.LogLevel_INFO, - Output: "log-output", - }, - }, - }, { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Resources: []*proto.Resource{{ - Name: "resource", - }}, - }, - }, - }} - data, err := echo.Tar(&echo.Responses{ - ProvisionApply: responses, - }) - require.NoError(t, err) - client, err := api.Provision(ctx) - require.NoError(t, err) - err = client.Send(&proto.Provision_Request{ - Type: &proto.Provision_Request_Plan{ - Plan: &proto.Provision_Plan{ - Config: &proto.Provision_Config{ - Directory: unpackTar(t, fs, data), + planResponses := []*proto.Response{ + { + Type: &proto.Response_Log{ + Log: &proto.Log{ + Level: proto.LogLevel_INFO, + Output: "log-output", }, }, }, + { + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ + Resources: []*proto.Resource{{ + Name: "resource", + }}, + }, + }, + }, + } + applyResponses := []*proto.Response{ + { + Type: &proto.Response_Log{ + Log: &proto.Log{ + Level: proto.LogLevel_INFO, + Output: "log-output", + }, + }, + }, + { + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ + Resources: []*proto.Resource{{ + Name: "resource", + }}, + }, + }, + }, + } + data, err := echo.Tar(&echo.Responses{ + ProvisionPlan: planResponses, + ProvisionApply: applyResponses, }) require.NoError(t, err) + client, err := api.Session(ctx) + require.NoError(t, err) + defer func() { + err := client.Close() + require.NoError(t, err) + }() + err = client.Send(&proto.Request{Type: &proto.Request_Config{Config: &proto.Config{ + TemplateSourceArchive: data, + }}}) + require.NoError(t, err) + + err = client.Send(&proto.Request{Type: &proto.Request_Plan{Plan: &proto.PlanRequest{}}}) + require.NoError(t, err) log, err := client.Recv() require.NoError(t, err) - require.Equal(t, responses[0].GetLog().Output, log.GetLog().Output) + require.Equal(t, planResponses[0].GetLog().Output, log.GetLog().Output) complete, err := client.Recv() require.NoError(t, err) - require.Equal(t, responses[1].GetComplete().Resources[0].Name, - complete.GetComplete().Resources[0].Name) + require.Equal(t, planResponses[1].GetPlan().Resources[0].Name, + complete.GetPlan().Resources[0].Name) + + err = client.Send(&proto.Request{Type: &proto.Request_Apply{Apply: &proto.ApplyRequest{}}}) + require.NoError(t, err) + log, err = client.Recv() + require.NoError(t, err) + require.Equal(t, applyResponses[0].GetLog().Output, log.GetLog().Output) + complete, err = client.Recv() + require.NoError(t, err) + require.Equal(t, applyResponses[1].GetApply().Resources[0].Name, + complete.GetApply().Resources[0].Name) }) t.Run("ProvisionStop", func(t *testing.T) { t.Parallel() // Stop responses should be returned when the workspace is being stopped. - - defaultResponses := []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Resources: []*proto.Resource{{ - Name: "DEFAULT", - }}, - }, - }, - }} - stopResponses := []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Resources: []*proto.Resource{{ - Name: "STOP", - }}, - }, - }, - }} data, err := echo.Tar(&echo.Responses{ - ProvisionApply: defaultResponses, - ProvisionPlan: defaultResponses, - ProvisionPlanMap: map[proto.WorkspaceTransition][]*proto.Provision_Response{ - proto.WorkspaceTransition_STOP: stopResponses, + ProvisionApply: applyCompleteResource("DEFAULT"), + ProvisionPlan: planCompleteResource("DEFAULT"), + ProvisionPlanMap: map[proto.WorkspaceTransition][]*proto.Response{ + proto.WorkspaceTransition_STOP: planCompleteResource("STOP"), }, - ProvisionApplyMap: map[proto.WorkspaceTransition][]*proto.Provision_Response{ - proto.WorkspaceTransition_STOP: stopResponses, + ProvisionApplyMap: map[proto.WorkspaceTransition][]*proto.Response{ + proto.WorkspaceTransition_STOP: applyCompleteResource("STOP"), }, }) require.NoError(t, err) - client, err := api.Provision(ctx) + client, err := api.Session(ctx) + require.NoError(t, err) + defer func() { + err := client.Close() + require.NoError(t, err) + }() + err = client.Send(&proto.Request{Type: &proto.Request_Config{Config: &proto.Config{ + TemplateSourceArchive: data, + }}}) require.NoError(t, err) // Do stop. - err = client.Send(&proto.Provision_Request{ - Type: &proto.Provision_Request_Plan{ - Plan: &proto.Provision_Plan{ - Config: &proto.Provision_Config{ - Directory: unpackTar(t, fs, data), - Metadata: &proto.Provision_Metadata{ - WorkspaceTransition: proto.WorkspaceTransition_STOP, - }, + err = client.Send(&proto.Request{ + Type: &proto.Request_Plan{ + Plan: &proto.PlanRequest{ + Metadata: &proto.Metadata{ + WorkspaceTransition: proto.WorkspaceTransition_STOP, }, }, }, @@ -168,22 +201,16 @@ func TestEcho(t *testing.T) { complete, err := client.Recv() require.NoError(t, err) require.Equal(t, - stopResponses[0].GetComplete().Resources[0].Name, - complete.GetComplete().Resources[0].Name, + "STOP", + complete.GetPlan().Resources[0].Name, ) // Do start. - client, err = api.Provision(ctx) - require.NoError(t, err) - - err = client.Send(&proto.Provision_Request{ - Type: &proto.Provision_Request_Plan{ - Plan: &proto.Provision_Plan{ - Config: &proto.Provision_Config{ - Directory: unpackTar(t, fs, data), - Metadata: &proto.Provision_Metadata{ - WorkspaceTransition: proto.WorkspaceTransition_START, - }, + err = client.Send(&proto.Request{ + Type: &proto.Request_Plan{ + Plan: &proto.PlanRequest{ + Metadata: &proto.Metadata{ + WorkspaceTransition: proto.WorkspaceTransition_START, }, }, }, @@ -193,31 +220,33 @@ func TestEcho(t *testing.T) { complete, err = client.Recv() require.NoError(t, err) require.Equal(t, - defaultResponses[0].GetComplete().Resources[0].Name, - complete.GetComplete().Resources[0].Name, + "DEFAULT", + complete.GetPlan().Resources[0].Name, ) }) t.Run("ProvisionWithLogLevel", func(t *testing.T) { t.Parallel() + ctx, cancel := context.WithTimeout(ctx, testutil.WaitShort) + defer cancel() - responses := []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Log{ + responses := []*proto.Response{{ + Type: &proto.Response_Log{ Log: &proto.Log{ Level: proto.LogLevel_TRACE, Output: "log-output-trace", }, }, }, { - Type: &proto.Provision_Response_Log{ + Type: &proto.Response_Log{ Log: &proto.Log{ Level: proto.LogLevel_INFO, Output: "log-output-info", }, }, }, { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "resource", }}, @@ -225,49 +254,62 @@ func TestEcho(t *testing.T) { }, }} data, err := echo.Tar(&echo.Responses{ + ProvisionPlan: echo.PlanComplete, ProvisionApply: responses, }) require.NoError(t, err) - client, err := api.Provision(ctx) + client, err := api.Session(ctx) require.NoError(t, err) - err = client.Send(&proto.Provision_Request{ - Type: &proto.Provision_Request_Plan{ - Plan: &proto.Provision_Plan{ - Config: &proto.Provision_Config{ - Directory: unpackTar(t, fs, data), - ProvisionerLogLevel: "debug", - }, - }, - }, - }) + defer func() { + err := client.Close() + require.NoError(t, err) + }() + err = client.Send(&proto.Request{Type: &proto.Request_Config{Config: &proto.Config{ + TemplateSourceArchive: data, + ProvisionerLogLevel: "debug", + }}}) + require.NoError(t, err) + + // Plan is required before apply + err = client.Send(&proto.Request{Type: &proto.Request_Plan{Plan: &proto.PlanRequest{}}}) + require.NoError(t, err) + complete, err := client.Recv() + require.NoError(t, err) + require.NotNil(t, complete.GetPlan()) + + err = client.Send(&proto.Request{Type: &proto.Request_Apply{Apply: &proto.ApplyRequest{}}}) require.NoError(t, err) log, err := client.Recv() require.NoError(t, err) // Skip responses[0] as it's trace level require.Equal(t, responses[1].GetLog().Output, log.GetLog().Output) - complete, err := client.Recv() + complete, err = client.Recv() require.NoError(t, err) - require.Equal(t, responses[2].GetComplete().Resources[0].Name, - complete.GetComplete().Resources[0].Name) + require.Equal(t, responses[2].GetApply().Resources[0].Name, + complete.GetApply().Resources[0].Name) }) } -func unpackTar(t *testing.T, fs afero.Fs, data []byte) string { - directory := t.TempDir() - reader := tar.NewReader(bytes.NewReader(data)) - for { - header, err := reader.Next() - if err != nil { - break - } - // #nosec - path := filepath.Join(directory, header.Name) - file, err := fs.OpenFile(path, os.O_CREATE|os.O_RDWR, 0o600) - require.NoError(t, err) - _, err = io.CopyN(file, reader, 1<<20) - require.ErrorIs(t, err, io.EOF) - err = file.Close() - require.NoError(t, err) - } - return directory +func planCompleteResource(name string) []*proto.Response { + return []*proto.Response{{ + Type: &proto.Response_Plan{ + Plan: &proto.PlanComplete{ + Resources: []*proto.Resource{{ + Name: name, + }}, + }, + }, + }} +} + +func applyCompleteResource(name string) []*proto.Response { + return []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ + Resources: []*proto.Resource{{ + Name: name, + }}, + }, + }, + }} } diff --git a/provisioner/terraform/executor.go b/provisioner/terraform/executor.go index cd847910e4..d523eeca19 100644 --- a/provisioner/terraform/executor.go +++ b/provisioner/terraform/executor.go @@ -25,6 +25,7 @@ import ( ) type executor struct { + logger slog.Logger server *server mut *sync.Mutex binaryPath string @@ -50,8 +51,10 @@ func (e *executor) execWriteOutput(ctx, killCtx context.Context, args, env []str ctx, span := e.server.startTrace(ctx, fmt.Sprintf("exec - terraform %s", args[0])) defer span.End() span.SetAttributes(attribute.StringSlice("args", args)) + e.logger.Debug(ctx, "starting command", slog.F("args", args)) defer func() { + e.logger.Debug(ctx, "closing writers", slog.Error(err)) closeErr := stdOutWriter.Close() if err == nil && closeErr != nil { err = closeErr @@ -62,6 +65,7 @@ func (e *executor) execWriteOutput(ctx, killCtx context.Context, args, env []str } }() if ctx.Err() != nil { + e.logger.Debug(ctx, "context canceled before command started", slog.F("args", args)) return ctx.Err() } @@ -90,11 +94,14 @@ func (e *executor) execWriteOutput(ctx, killCtx context.Context, args, env []str ) err = cmd.Start() if err != nil { + e.logger.Debug(ctx, "failed to start command", slog.F("args", args)) return err } - interruptCommandOnCancel(ctx, killCtx, cmd) + interruptCommandOnCancel(ctx, killCtx, e.logger, cmd) - return cmd.Wait() + err = cmd.Wait() + e.logger.Debug(ctx, "command done", slog.F("args", args), slog.Error(err)) + return err } // execParseJSON must only be called while the lock is held. @@ -120,7 +127,7 @@ func (e *executor) execParseJSON(ctx, killCtx context.Context, args, env []strin if err != nil { return err } - interruptCommandOnCancel(ctx, killCtx, cmd) + interruptCommandOnCancel(ctx, killCtx, e.logger, cmd) err = cmd.Wait() if err != nil { @@ -207,15 +214,23 @@ func (e *executor) init(ctx, killCtx context.Context, logr logSink) error { return e.execWriteOutput(ctx, killCtx, args, e.basicEnv(), outWriter, errWriter) } +func getPlanFilePath(workdir string) string { + return filepath.Join(workdir, "terraform.tfplan") +} + +func getStateFilePath(workdir string) string { + return filepath.Join(workdir, "terraform.tfstate") +} + // revive:disable-next-line:flag-parameter -func (e *executor) plan(ctx, killCtx context.Context, env, vars []string, logr logSink, destroy bool) (*proto.Provision_Response, error) { +func (e *executor) plan(ctx, killCtx context.Context, env, vars []string, logr logSink, destroy bool) (*proto.PlanComplete, error) { ctx, span := e.server.startTrace(ctx, tracing.FuncName()) defer span.End() e.mut.Lock() defer e.mut.Unlock() - planfilePath := filepath.Join(e.workdir, "terraform.tfplan") + planfilePath := getPlanFilePath(e.workdir) args := []string{ "plan", "-no-color", @@ -248,19 +263,10 @@ func (e *executor) plan(ctx, killCtx context.Context, env, vars []string, logr l if err != nil { return nil, err } - planFileByt, err := os.ReadFile(planfilePath) - if err != nil { - return nil, err - } - return &proto.Provision_Response{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Parameters: state.Parameters, - Resources: state.Resources, - GitAuthProviders: state.GitAuthProviders, - Plan: planFileByt, - }, - }, + return &proto.PlanComplete{ + Parameters: state.Parameters, + Resources: state.Resources, + GitAuthProviders: state.GitAuthProviders, }, nil } @@ -346,7 +352,7 @@ func (e *executor) graph(ctx, killCtx context.Context) (string, error) { if err != nil { return "", err } - interruptCommandOnCancel(ctx, killCtx, cmd) + interruptCommandOnCancel(ctx, killCtx, e.logger, cmd) err = cmd.Wait() if err != nil { @@ -357,33 +363,22 @@ func (e *executor) graph(ctx, killCtx context.Context) (string, error) { func (e *executor) apply( ctx, killCtx context.Context, - plan []byte, env []string, logr logSink, -) (*proto.Provision_Response, error) { +) (*proto.ApplyComplete, error) { ctx, span := e.server.startTrace(ctx, tracing.FuncName()) defer span.End() e.mut.Lock() defer e.mut.Unlock() - planFile, err := os.CreateTemp("", "coder-terrafrom-plan") - if err != nil { - return nil, xerrors.Errorf("create plan file: %w", err) - } - _, err = planFile.Write(plan) - if err != nil { - return nil, xerrors.Errorf("write plan file: %w", err) - } - defer os.Remove(planFile.Name()) - args := []string{ "apply", "-no-color", "-auto-approve", "-input=false", "-json", - planFile.Name(), + getPlanFilePath(e.workdir), } outWriter, doneOut := provisionLogWriter(logr) @@ -395,7 +390,7 @@ func (e *executor) apply( <-doneErr }() - err = e.execWriteOutput(ctx, killCtx, args, env, outWriter, errWriter) + err := e.execWriteOutput(ctx, killCtx, args, env, outWriter, errWriter) if err != nil { return nil, xerrors.Errorf("terraform apply: %w", err) } @@ -408,15 +403,11 @@ func (e *executor) apply( if err != nil { return nil, xerrors.Errorf("read statefile %q: %w", statefilePath, err) } - return &proto.Provision_Response{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Parameters: state.Parameters, - Resources: state.Resources, - GitAuthProviders: state.GitAuthProviders, - State: stateContent, - }, - }, + return &proto.ApplyComplete{ + Parameters: state.Parameters, + Resources: state.Resources, + GitAuthProviders: state.GitAuthProviders, + State: stateContent, }, nil } @@ -461,48 +452,28 @@ func (e *executor) state(ctx, killCtx context.Context) (*tfjson.State, error) { return state, nil } -func interruptCommandOnCancel(ctx, killCtx context.Context, cmd *exec.Cmd) { +func interruptCommandOnCancel(ctx, killCtx context.Context, logger slog.Logger, cmd *exec.Cmd) { go func() { select { case <-ctx.Done(): + var err error switch runtime.GOOS { case "windows": // Interrupts aren't supported by Windows. - _ = cmd.Process.Kill() + err = cmd.Process.Kill() default: - _ = cmd.Process.Signal(os.Interrupt) + err = cmd.Process.Signal(os.Interrupt) } + logger.Debug(ctx, "interrupted command", slog.F("args", cmd.Args), slog.Error(err)) case <-killCtx.Done(): + logger.Debug(ctx, "kill context ended", slog.F("args", cmd.Args)) } }() } type logSink interface { - Log(*proto.Log) -} - -type streamLogSink struct { - // Any errors writing to the stream will be logged to logger. - logger slog.Logger - stream proto.DRPCProvisioner_ProvisionStream -} - -var _ logSink = streamLogSink{} - -func (s streamLogSink) Log(l *proto.Log) { - err := s.stream.Send(&proto.Provision_Response{ - Type: &proto.Provision_Response_Log{ - Log: l, - }, - }) - if err != nil { - s.logger.Warn(context.Background(), "write log to stream", - slog.F("level", l.Level.String()), - slog.F("message", l.Output), - slog.Error(err), - ) - } + ProvisionLog(l proto.LogLevel, o string) } // logWriter creates a WriteCloser that will log each line of text at the given level. The WriteCloser must be closed @@ -526,7 +497,7 @@ func readAndLog(sink logSink, r io.Reader, done chan<- any, level proto.LogLevel continue } - sink.Log(&proto.Log{Level: level, Output: scanner.Text()}) + sink.ProvisionLog(level, scanner.Text()) continue } @@ -543,7 +514,7 @@ func readAndLog(sink logSink, r io.Reader, done chan<- any, level proto.LogLevel if logLevel == proto.LogLevel_INFO { logLevel = proto.LogLevel_DEBUG } - sink.Log(&proto.Log{Level: logLevel, Output: log.Message}) + sink.ProvisionLog(logLevel, log.Message) } } @@ -588,7 +559,7 @@ func provisionReadAndLog(sink logSink, r io.Reader, done chan<- any) { } logLevel := convertTerraformLogLevel(log.Level, sink) - sink.Log(&proto.Log{Level: logLevel, Output: log.Message}) + sink.ProvisionLog(logLevel, log.Message) // If the diagnostic is provided, let's provide a bit more info! if log.Diagnostic == nil { @@ -596,7 +567,7 @@ func provisionReadAndLog(sink logSink, r io.Reader, done chan<- any) { } logLevel = convertTerraformLogLevel(string(log.Diagnostic.Severity), sink) for _, diagLine := range strings.Split(FormatDiagnostic(log.Diagnostic), "\n") { - sink.Log(&proto.Log{Level: logLevel, Output: diagLine}) + sink.ProvisionLog(logLevel, diagLine) } } } @@ -614,10 +585,7 @@ func convertTerraformLogLevel(logLevel string, sink logSink) proto.LogLevel { case "error": return proto.LogLevel_ERROR default: - sink.Log(&proto.Log{ - Level: proto.LogLevel_WARN, - Output: fmt.Sprintf("unable to convert log level %s", logLevel), - }) + sink.ProvisionLog(proto.LogLevel_WARN, fmt.Sprintf("unable to convert log level %s", logLevel)) return proto.LogLevel_INFO } } diff --git a/provisioner/terraform/executor_internal_test.go b/provisioner/terraform/executor_internal_test.go index fd203c9b1e..97cb528537 100644 --- a/provisioner/terraform/executor_internal_test.go +++ b/provisioner/terraform/executor_internal_test.go @@ -16,8 +16,8 @@ type mockLogger struct { var _ logSink = &mockLogger{} -func (m *mockLogger) Log(l *proto.Log) { - m.logs = append(m.logs, l) +func (m *mockLogger) ProvisionLog(l proto.LogLevel, o string) { + m.logs = append(m.logs, &proto.Log{Level: l, Output: o}) } func TestLogWriter_Mainline(t *testing.T) { diff --git a/provisioner/terraform/parse.go b/provisioner/terraform/parse.go index 6c52dc1313..10ab7b801b 100644 --- a/provisioner/terraform/parse.go +++ b/provisioner/terraform/parse.go @@ -12,18 +12,20 @@ import ( "golang.org/x/xerrors" "github.com/coder/coder/v2/coderd/tracing" + "github.com/coder/coder/v2/provisionersdk" "github.com/coder/coder/v2/provisionersdk/proto" ) // Parse extracts Terraform variables from source-code. -func (s *server) Parse(request *proto.Parse_Request, stream proto.DRPCProvisioner_ParseStream) error { - _, span := s.startTrace(stream.Context(), tracing.FuncName()) +func (s *server) Parse(sess *provisionersdk.Session, _ *proto.ParseRequest, _ <-chan struct{}) *proto.ParseComplete { + ctx := sess.Context() + _, span := s.startTrace(ctx, tracing.FuncName()) defer span.End() // Load the module and print any parse errors. - module, diags := tfconfig.LoadModule(request.Directory) + module, diags := tfconfig.LoadModule(sess.WorkDirectory) if diags.HasErrors() { - return xerrors.Errorf("load module: %s", formatDiagnostics(request.Directory, diags)) + return provisionersdk.ParseErrorf("load module: %s", formatDiagnostics(sess.WorkDirectory, diags)) } // Sort variables by (filename, line) to make the ordering consistent @@ -40,17 +42,13 @@ func (s *server) Parse(request *proto.Parse_Request, stream proto.DRPCProvisione for _, v := range variables { mv, err := convertTerraformVariable(v) if err != nil { - return xerrors.Errorf("can't convert the Terraform variable to a managed one: %w", err) + return provisionersdk.ParseErrorf("can't convert the Terraform variable to a managed one: %s", err) } templateVariables = append(templateVariables, mv) } - return stream.Send(&proto.Parse_Response{ - Type: &proto.Parse_Response_Complete{ - Complete: &proto.Parse_Complete{ - TemplateVariables: templateVariables, - }, - }, - }) + return &proto.ParseComplete{ + TemplateVariables: templateVariables, + } } // Converts a Terraform variable to a template-wide variable, processed by Coder. diff --git a/provisioner/terraform/parse_test.go b/provisioner/terraform/parse_test.go index aa0e19984b..c28532af25 100644 --- a/provisioner/terraform/parse_test.go +++ b/provisioner/terraform/parse_test.go @@ -4,8 +4,6 @@ package terraform_test import ( "encoding/json" - "os" - "path/filepath" "testing" "github.com/stretchr/testify/require" @@ -21,9 +19,8 @@ func TestParse(t *testing.T) { testCases := []struct { Name string Files map[string]string - Response *proto.Parse_Response - // If ErrorContains is not empty, then response.Recv() should return an - // error containing this string before a Complete response is returned. + Response *proto.ParseComplete + // If ErrorContains is not empty, then the ParseComplete should have an Error containing the given string ErrorContains string }{ { @@ -33,16 +30,12 @@ func TestParse(t *testing.T) { description = "Testing!" }`, }, - Response: &proto.Parse_Response{ - Type: &proto.Parse_Response_Complete{ - Complete: &proto.Parse_Complete{ - TemplateVariables: []*proto.TemplateVariable{ - { - Name: "A", - Description: "Testing!", - Required: true, - }, - }, + Response: &proto.ParseComplete{ + TemplateVariables: []*proto.TemplateVariable{ + { + Name: "A", + Description: "Testing!", + Required: true, }, }, }, @@ -54,15 +47,11 @@ func TestParse(t *testing.T) { default = "wow" }`, }, - Response: &proto.Parse_Response{ - Type: &proto.Parse_Response_Complete{ - Complete: &proto.Parse_Complete{ - TemplateVariables: []*proto.TemplateVariable{ - { - Name: "A", - DefaultValue: "wow", - }, - }, + Response: &proto.ParseComplete{ + TemplateVariables: []*proto.TemplateVariable{ + { + Name: "A", + DefaultValue: "wow", }, }, }, @@ -76,15 +65,11 @@ func TestParse(t *testing.T) { } }`, }, - Response: &proto.Parse_Response{ - Type: &proto.Parse_Response_Complete{ - Complete: &proto.Parse_Complete{ - TemplateVariables: []*proto.TemplateVariable{ - { - Name: "A", - Required: true, - }, - }, + Response: &proto.ParseComplete{ + TemplateVariables: []*proto.TemplateVariable{ + { + Name: "A", + Required: true, }, }, }, @@ -104,27 +89,23 @@ func TestParse(t *testing.T) { "main2.tf": `variable "baz" { } variable "quux" { }`, }, - Response: &proto.Parse_Response{ - Type: &proto.Parse_Response_Complete{ - Complete: &proto.Parse_Complete{ - TemplateVariables: []*proto.TemplateVariable{ - { - Name: "foo", - Required: true, - }, - { - Name: "bar", - Required: true, - }, - { - Name: "baz", - Required: true, - }, - { - Name: "quux", - Required: true, - }, - }, + Response: &proto.ParseComplete{ + TemplateVariables: []*proto.TemplateVariable{ + { + Name: "foo", + Required: true, + }, + { + Name: "bar", + Required: true, + }, + { + Name: "baz", + Required: true, + }, + { + Name: "quux", + Required: true, }, }, }, @@ -139,19 +120,15 @@ func TestParse(t *testing.T) { sensitive = true }`, }, - Response: &proto.Parse_Response{ - Type: &proto.Parse_Response_Complete{ - Complete: &proto.Parse_Complete{ - TemplateVariables: []*proto.TemplateVariable{ - { - Name: "A", - Description: "Testing!", - Type: "bool", - DefaultValue: "true", - Required: false, - Sensitive: true, - }, - }, + Response: &proto.ParseComplete{ + TemplateVariables: []*proto.TemplateVariable{ + { + Name: "A", + Description: "Testing!", + Type: "bool", + DefaultValue: "true", + Required: false, + Sensitive: true, }, }, }, @@ -166,19 +143,15 @@ func TestParse(t *testing.T) { sensitive = true }`, }, - Response: &proto.Parse_Response{ - Type: &proto.Parse_Response_Complete{ - Complete: &proto.Parse_Complete{ - TemplateVariables: []*proto.TemplateVariable{ - { - Name: "A", - Description: "Testing!", - Type: "string", - DefaultValue: "abc", - Required: false, - Sensitive: true, - }, - }, + Response: &proto.ParseComplete{ + TemplateVariables: []*proto.TemplateVariable{ + { + Name: "A", + Description: "Testing!", + Type: "string", + DefaultValue: "abc", + Required: false, + Sensitive: true, }, }, }, @@ -193,19 +166,15 @@ func TestParse(t *testing.T) { sensitive = true }`, }, - Response: &proto.Parse_Response{ - Type: &proto.Parse_Response_Complete{ - Complete: &proto.Parse_Complete{ - TemplateVariables: []*proto.TemplateVariable{ - { - Name: "A", - Description: "Testing!", - Type: "string", - DefaultValue: "", - Required: false, - Sensitive: true, - }, - }, + Response: &proto.ParseComplete{ + TemplateVariables: []*proto.TemplateVariable{ + { + Name: "A", + Description: "Testing!", + Type: "string", + DefaultValue: "", + Required: false, + Sensitive: true, }, }, }, @@ -219,19 +188,15 @@ func TestParse(t *testing.T) { sensitive = true }`, }, - Response: &proto.Parse_Response{ - Type: &proto.Parse_Response_Complete{ - Complete: &proto.Parse_Complete{ - TemplateVariables: []*proto.TemplateVariable{ - { - Name: "A", - Description: "Testing!", - Type: "string", - DefaultValue: "", - Required: true, - Sensitive: true, - }, - }, + Response: &proto.ParseComplete{ + TemplateVariables: []*proto.TemplateVariable{ + { + Name: "A", + Description: "Testing!", + Type: "string", + DefaultValue: "", + Required: true, + Sensitive: true, }, }, }, @@ -243,40 +208,31 @@ func TestParse(t *testing.T) { t.Run(testCase.Name, func(t *testing.T) { t.Parallel() - // Write all files to the temporary test directory. - directory := t.TempDir() - for path, content := range testCase.Files { - err := os.WriteFile(filepath.Join(directory, path), []byte(content), 0o600) - require.NoError(t, err) - } - - response, err := api.Parse(ctx, &proto.Parse_Request{ - Directory: directory, + session := configure(ctx, t, api, &proto.Config{ + TemplateSourceArchive: makeTar(t, testCase.Files), }) + + err := session.Send(&proto.Request{Type: &proto.Request_Parse{Parse: &proto.ParseRequest{}}}) require.NoError(t, err) for { - msg, err := response.Recv() - if err != nil { - if testCase.ErrorContains != "" { - require.ErrorContains(t, err, testCase.ErrorContains) - break - } + msg, err := session.Recv() + require.NoError(t, err) - require.NoError(t, err) - } - - if msg.GetComplete() == nil { - continue - } if testCase.ErrorContains != "" { - t.Fatal("expected error but job completed successfully") + require.Contains(t, msg.GetParse().GetError(), testCase.ErrorContains) + break + } + + // Ignore logs in this test + if msg.GetLog() != nil { + continue } // Ensure the want and got are equivalent! want, err := json.Marshal(testCase.Response) require.NoError(t, err) - got, err := json.Marshal(msg) + got, err := json.Marshal(msg.GetParse()) require.NoError(t, err) require.Equal(t, string(want), string(got)) diff --git a/provisioner/terraform/provision.go b/provisioner/terraform/provision.go index 504984520d..ab832e4408 100644 --- a/provisioner/terraform/provision.go +++ b/provisioner/terraform/provision.go @@ -4,11 +4,10 @@ import ( "context" "fmt" "os" - "path/filepath" "strings" "time" - "golang.org/x/xerrors" + "cdr.dev/slog" "github.com/coder/coder/v2/coderd/tracing" "github.com/coder/coder/v2/provisionersdk" @@ -16,48 +15,23 @@ import ( "github.com/coder/terraform-provider-coder/provider" ) -// Provision executes `terraform apply` or `terraform plan` for dry runs. -func (s *server) Provision(stream proto.DRPCProvisioner_ProvisionStream) error { - ctx, span := s.startTrace(stream.Context(), tracing.FuncName()) - defer span.End() - - request, err := stream.Recv() - if err != nil { - return err - } - if request.GetCancel() != nil { - return nil - } - - var ( - applyRequest = request.GetApply() - planRequest = request.GetPlan() - ) - - var config *proto.Provision_Config - if applyRequest == nil && planRequest == nil { - return nil - } else if applyRequest != nil { - config = applyRequest.Config - } else if planRequest != nil { - config = planRequest.Config - } - - // Create a context for graceful cancellation bound to the stream +func (s *server) setupContexts(parent context.Context, canceledOrComplete <-chan struct{}) ( + ctx context.Context, cancel func(), killCtx context.Context, kill func(), +) { + // Create a context for graceful cancellation bound to the session // context. This ensures that we will perform graceful cancellation // even on connection loss. - ctx, cancel := context.WithCancel(ctx) - defer cancel() + ctx, cancel = context.WithCancel(parent) // Create a separate context for forceful cancellation not tied to // the stream so that we can control when to terminate the process. - killCtx, kill := context.WithCancel(context.Background()) - defer kill() + killCtx, kill = context.WithCancel(context.Background()) // Ensure processes are eventually cleaned up on graceful // cancellation or disconnect. go func() { <-ctx.Done() + s.logger.Debug(ctx, "graceful context done") // TODO(mafredri): We should track this provision request as // part of graceful server shutdown procedure. Waiting on a @@ -66,134 +40,131 @@ func (s *server) Provision(stream proto.DRPCProvisioner_ProvisionStream) error { defer t.Stop() select { case <-t.C: + s.logger.Debug(ctx, "exit timeout hit") kill() case <-killCtx.Done(): + s.logger.Debug(ctx, "kill context done") } }() + // Process cancel go func() { - for { - request, err := stream.Recv() - if err != nil { - return - } - if request.GetCancel() == nil { - // We only process cancellation requests here. - continue - } - cancel() - return - } + <-canceledOrComplete + s.logger.Debug(ctx, "canceledOrComplete closed") + cancel() }() + return ctx, cancel, killCtx, kill +} - sink := streamLogSink{ - logger: s.logger.Named("execution_logs"), - stream: stream, - } +func (s *server) Plan( + sess *provisionersdk.Session, request *proto.PlanRequest, canceledOrComplete <-chan struct{}, +) *proto.PlanComplete { + ctx, span := s.startTrace(sess.Context(), tracing.FuncName()) + defer span.End() + ctx, cancel, killCtx, kill := s.setupContexts(ctx, canceledOrComplete) + defer cancel() + defer kill() - e := s.executor(config.Directory) - if err = e.checkMinVersion(ctx); err != nil { - return err - } - logTerraformEnvVars(sink) - - statefilePath := filepath.Join(config.Directory, "terraform.tfstate") - if len(config.State) > 0 { - err = os.WriteFile(statefilePath, config.State, 0o600) - if err != nil { - return xerrors.Errorf("write statefile %q: %w", statefilePath, err) - } + e := s.executor(sess.WorkDirectory) + if err := e.checkMinVersion(ctx); err != nil { + return provisionersdk.PlanErrorf(err.Error()) } + logTerraformEnvVars(sess) // If we're destroying, exit early if there's no state. This is necessary to // avoid any cases where a workspace is "locked out" of terraform due to // e.g. bad template param values and cannot be deleted. This is just for // contingency, in the future we will try harder to prevent workspaces being // broken this hard. - if config.Metadata.WorkspaceTransition == proto.WorkspaceTransition_DESTROY && len(config.State) == 0 { - _ = stream.Send(&proto.Provision_Response{ - Type: &proto.Provision_Response_Log{ - Log: &proto.Log{ - Level: proto.LogLevel_INFO, - Output: "The terraform state does not exist, there is nothing to do", - }, - }, - }) + if request.Metadata.GetWorkspaceTransition() == proto.WorkspaceTransition_DESTROY && len(sess.Config.State) == 0 { + sess.ProvisionLog(proto.LogLevel_INFO, "The terraform state does not exist, there is nothing to do") + return &proto.PlanComplete{} + } - return stream.Send(&proto.Provision_Response{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{}, - }, - }) + statefilePath := getStateFilePath(sess.WorkDirectory) + if len(sess.Config.State) > 0 { + err := os.WriteFile(statefilePath, sess.Config.State, 0o600) + if err != nil { + return provisionersdk.PlanErrorf("write statefile %q: %s", statefilePath, err) + } } s.logger.Debug(ctx, "running initialization") - err = e.init(ctx, killCtx, sink) + err := e.init(ctx, killCtx, sess) if err != nil { - if ctx.Err() != nil { - return stream.Send(&proto.Provision_Response{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Error: err.Error(), - }, - }, - }) - } - return xerrors.Errorf("initialize terraform: %w", err) + s.logger.Debug(ctx, "init failed", slog.Error(err)) + return provisionersdk.PlanErrorf("initialize terraform: %s", err) } s.logger.Debug(ctx, "ran initialization") - env, err := provisionEnv(config, request.GetPlan().GetRichParameterValues(), request.GetPlan().GetGitAuthProviders()) + + env, err := provisionEnv(sess.Config, request.Metadata, request.RichParameterValues, request.GitAuthProviders) if err != nil { - return err + return provisionersdk.PlanErrorf("setup env: %s", err) } - var resp *proto.Provision_Response - if planRequest != nil { - vars, err := planVars(planRequest) - if err != nil { - return err - } - - resp, err = e.plan( - ctx, killCtx, env, vars, sink, - config.Metadata.WorkspaceTransition == proto.WorkspaceTransition_DESTROY, - ) - if err != nil { - if ctx.Err() != nil { - return stream.Send(&proto.Provision_Response{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Error: err.Error(), - }, - }, - }) - } - return xerrors.Errorf("plan terraform: %w", err) - } - return stream.Send(resp) + vars, err := planVars(request) + if err != nil { + return provisionersdk.PlanErrorf("plan vars: %s", err) } - // Must be apply - resp, err = e.apply( - ctx, killCtx, applyRequest.Plan, env, sink, + + resp, err := e.plan( + ctx, killCtx, env, vars, sess, + request.Metadata.GetWorkspaceTransition() == proto.WorkspaceTransition_DESTROY, + ) + if err != nil { + return provisionersdk.PlanErrorf(err.Error()) + } + return resp +} + +func (s *server) Apply( + sess *provisionersdk.Session, request *proto.ApplyRequest, canceledOrComplete <-chan struct{}, +) *proto.ApplyComplete { + ctx, span := s.startTrace(sess.Context(), tracing.FuncName()) + defer span.End() + ctx, cancel, killCtx, kill := s.setupContexts(ctx, canceledOrComplete) + defer cancel() + defer kill() + + e := s.executor(sess.WorkDirectory) + if err := e.checkMinVersion(ctx); err != nil { + return provisionersdk.ApplyErrorf(err.Error()) + } + logTerraformEnvVars(sess) + + // Exit early if there is no plan file. This is necessary to + // avoid any cases where a workspace is "locked out" of terraform due to + // e.g. bad template param values and cannot be deleted. This is just for + // contingency, in the future we will try harder to prevent workspaces being + // broken this hard. + if request.Metadata.GetWorkspaceTransition() == proto.WorkspaceTransition_DESTROY && len(sess.Config.State) == 0 { + sess.ProvisionLog(proto.LogLevel_INFO, "The terraform plan does not exist, there is nothing to do") + return &proto.ApplyComplete{} + } + + // Earlier in the session, Plan() will have written the state file and the plan file. + statefilePath := getStateFilePath(sess.WorkDirectory) + env, err := provisionEnv(sess.Config, request.Metadata, nil, nil) + if err != nil { + return provisionersdk.ApplyErrorf("provision env: %s", err) + } + resp, err := e.apply( + ctx, killCtx, env, sess, ) if err != nil { 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. stateData, _ := os.ReadFile(statefilePath) - return stream.Send(&proto.Provision_Response{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - State: stateData, - Error: errorMessage, - }, - }, - }) + return &proto.ApplyComplete{ + State: stateData, + Error: errorMessage, + } } - return stream.Send(resp) + return resp } -func planVars(plan *proto.Provision_Plan) ([]string, error) { +func planVars(plan *proto.PlanRequest) ([]string, error) { vars := []string{} for _, variable := range plan.VariableValues { vars = append(vars, fmt.Sprintf("%s=%s", variable.Name, variable.Value)) @@ -201,18 +172,21 @@ func planVars(plan *proto.Provision_Plan) ([]string, error) { return vars, nil } -func provisionEnv(config *proto.Provision_Config, richParams []*proto.RichParameterValue, gitAuth []*proto.GitAuthProvider) ([]string, error) { +func provisionEnv( + config *proto.Config, metadata *proto.Metadata, + richParams []*proto.RichParameterValue, gitAuth []*proto.GitAuthProvider, +) ([]string, error) { env := safeEnviron() env = append(env, - "CODER_AGENT_URL="+config.Metadata.CoderUrl, - "CODER_WORKSPACE_TRANSITION="+strings.ToLower(config.Metadata.WorkspaceTransition.String()), - "CODER_WORKSPACE_NAME="+config.Metadata.WorkspaceName, - "CODER_WORKSPACE_OWNER="+config.Metadata.WorkspaceOwner, - "CODER_WORKSPACE_OWNER_EMAIL="+config.Metadata.WorkspaceOwnerEmail, - "CODER_WORKSPACE_OWNER_OIDC_ACCESS_TOKEN="+config.Metadata.WorkspaceOwnerOidcAccessToken, - "CODER_WORKSPACE_ID="+config.Metadata.WorkspaceId, - "CODER_WORKSPACE_OWNER_ID="+config.Metadata.WorkspaceOwnerId, - "CODER_WORKSPACE_OWNER_SESSION_TOKEN="+config.Metadata.WorkspaceOwnerSessionToken, + "CODER_AGENT_URL="+metadata.GetCoderUrl(), + "CODER_WORKSPACE_TRANSITION="+strings.ToLower(metadata.GetWorkspaceTransition().String()), + "CODER_WORKSPACE_NAME="+metadata.GetWorkspaceName(), + "CODER_WORKSPACE_OWNER="+metadata.GetWorkspaceOwner(), + "CODER_WORKSPACE_OWNER_EMAIL="+metadata.GetWorkspaceOwnerEmail(), + "CODER_WORKSPACE_OWNER_OIDC_ACCESS_TOKEN="+metadata.GetWorkspaceOwnerOidcAccessToken(), + "CODER_WORKSPACE_ID="+metadata.GetWorkspaceId(), + "CODER_WORKSPACE_OWNER_ID="+metadata.GetWorkspaceOwnerId(), + "CODER_WORKSPACE_OWNER_SESSION_TOKEN="+metadata.GetWorkspaceOwnerSessionToken(), ) for key, value := range provisionersdk.AgentScriptEnv() { env = append(env, key+"="+value) @@ -258,10 +232,10 @@ func logTerraformEnvVars(sink logSink) { if !tfEnvSafeToPrint[parts[0]] { parts[1] = "" } - sink.Log(&proto.Log{ - Level: proto.LogLevel_WARN, - Output: fmt.Sprintf("terraform environment variable: %s=%s", parts[0], parts[1]), - }) + sink.ProvisionLog( + proto.LogLevel_WARN, + fmt.Sprintf("terraform environment variable: %s=%s", parts[0], parts[1]), + ) } } } diff --git a/provisioner/terraform/provision_test.go b/provisioner/terraform/provision_test.go index 03fc70ed69..254ddec45b 100644 --- a/provisioner/terraform/provision_test.go +++ b/provisioner/terraform/provision_test.go @@ -3,6 +3,8 @@ package terraform_test import ( + "archive/tar" + "bytes" "context" "encoding/json" "errors" @@ -35,6 +37,7 @@ func setupProvisioner(t *testing.T, opts *provisionerServeOptions) (context.Cont opts = &provisionerServeOptions{} } cachePath := t.TempDir() + workDir := t.TempDir() client, server := provisionersdk.MemTransportPipe() ctx, cancelFunc := context.WithCancel(context.Background()) serverErr := make(chan error, 1) @@ -50,40 +53,75 @@ func setupProvisioner(t *testing.T, opts *provisionerServeOptions) (context.Cont go func() { serverErr <- terraform.Serve(ctx, &terraform.ServeOptions{ ServeOptions: &provisionersdk.ServeOptions{ - Listener: server, + Listener: server, + Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug), + WorkDirectory: workDir, }, BinaryPath: opts.binaryPath, CachePath: cachePath, - Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug), ExitTimeout: opts.exitTimeout, }) }() api := proto.NewDRPCProvisionerClient(client) + return ctx, api } -func readProvisionLog(t *testing.T, response proto.DRPCProvisioner_ProvisionClient) ( - string, - *proto.Provision_Complete, -) { - var ( - logBuf strings.Builder - c *proto.Provision_Complete - ) +func makeTar(t *testing.T, files map[string]string) []byte { + t.Helper() + var buffer bytes.Buffer + writer := tar.NewWriter(&buffer) + for name, content := range files { + err := writer.WriteHeader(&tar.Header{ + Name: name, + Size: int64(len(content)), + Mode: 0o644, + }) + require.NoError(t, err) + _, err = writer.Write([]byte(content)) + require.NoError(t, err) + } + err := writer.Flush() + require.NoError(t, err) + return buffer.Bytes() +} + +func configure(ctx context.Context, t *testing.T, client proto.DRPCProvisionerClient, config *proto.Config) proto.DRPCProvisioner_SessionClient { + t.Helper() + sess, err := client.Session(ctx) + require.NoError(t, err) + err = sess.Send(&proto.Request{Type: &proto.Request_Config{Config: config}}) + require.NoError(t, err) + return sess +} + +func readProvisionLog(t *testing.T, response proto.DRPCProvisioner_SessionClient) string { + var logBuf strings.Builder for { msg, err := response.Recv() require.NoError(t, err) if log := msg.GetLog(); log != nil { t.Log(log.Level.String(), log.Output) - _, _ = logBuf.WriteString(log.Output) - } - if c = msg.GetComplete(); c != nil { - require.Empty(t, c.Error) - break + _, err = logBuf.WriteString(log.Output) + require.NoError(t, err) + continue } + break } - return logBuf.String(), c + return logBuf.String() +} + +func sendPlan(sess proto.DRPCProvisioner_SessionClient, transition proto.WorkspaceTransition) error { + return sess.Send(&proto.Request{Type: &proto.Request_Plan{Plan: &proto.PlanRequest{ + Metadata: &proto.Metadata{WorkspaceTransition: transition}, + }}}) +} + +func sendApply(sess proto.DRPCProvisioner_SessionClient, transition proto.WorkspaceTransition) error { + return sess.Send(&proto.Request{Type: &proto.Request_Apply{Apply: &proto.ApplyRequest{ + Metadata: &proto.Metadata{WorkspaceTransition: transition}, + }}}) } func TestProvision_Cancel(t *testing.T) { @@ -109,9 +147,10 @@ func TestProvision_Cancel(t *testing.T) { wantLog: []string{"interrupt", "exit"}, }, { - name: "Cancel apply", - mode: "apply", - startSequence: []string{"init", "apply_start"}, + // Provisioner requires a plan before an apply, so test cancel with plan. + name: "Cancel plan", + mode: "plan", + startSequence: []string{"init", "plan_start"}, wantLog: []string{"interrupt", "exit"}, }, } @@ -131,24 +170,16 @@ func TestProvision_Cancel(t *testing.T) { ctx, api := setupProvisioner(t, &provisionerServeOptions{ binaryPath: binPath, }) - - response, err := api.Provision(ctx) - require.NoError(t, err) - err = response.Send(&proto.Provision_Request{ - Type: &proto.Provision_Request_Apply{ - Apply: &proto.Provision_Apply{ - Config: &proto.Provision_Config{ - Directory: dir, - Metadata: &proto.Provision_Metadata{}, - }, - }, - }, + sess := configure(ctx, t, api, &proto.Config{ + TemplateSourceArchive: makeTar(t, nil), }) + + err = sendPlan(sess, proto.WorkspaceTransition_START) require.NoError(t, err) for _, line := range tt.startSequence { LoopStart: - msg, err := response.Recv() + msg, err := sess.Recv() require.NoError(t, err) t.Log(msg.Type) @@ -160,22 +191,22 @@ func TestProvision_Cancel(t *testing.T) { require.Equal(t, line, log.Output) } - err = response.Send(&proto.Provision_Request{ - Type: &proto.Provision_Request_Cancel{ - Cancel: &proto.Provision_Cancel{}, + err = sess.Send(&proto.Request{ + Type: &proto.Request_Cancel{ + Cancel: &proto.CancelRequest{}, }, }) require.NoError(t, err) var gotLog []string for { - msg, err := response.Recv() + msg, err := sess.Recv() require.NoError(t, err) if log := msg.GetLog(); log != nil { gotLog = append(gotLog, log.Output) } - if c := msg.GetComplete(); c != nil { + if c := msg.GetPlan(); c != nil { require.Contains(t, c.Error, "exit status 1") break } @@ -208,23 +239,17 @@ func TestProvision_CancelTimeout(t *testing.T) { exitTimeout: time.Second, }) - response, err := api.Provision(ctx) - require.NoError(t, err) - err = response.Send(&proto.Provision_Request{ - Type: &proto.Provision_Request_Apply{ - Apply: &proto.Provision_Apply{ - Config: &proto.Provision_Config{ - Directory: dir, - Metadata: &proto.Provision_Metadata{}, - }, - }, - }, + sess := configure(ctx, t, api, &proto.Config{ + TemplateSourceArchive: makeTar(t, nil), }) + + // provisioner requires plan before apply, so test cancel with plan. + err = sendPlan(sess, proto.WorkspaceTransition_START) require.NoError(t, err) - for _, line := range []string{"init", "apply_start"} { + for _, line := range []string{"init", "plan_start"} { LoopStart: - msg, err := response.Recv() + msg, err := sess.Recv() require.NoError(t, err) t.Log(msg.Type) @@ -236,18 +261,14 @@ func TestProvision_CancelTimeout(t *testing.T) { require.Equal(t, line, log.Output) } - err = response.Send(&proto.Provision_Request{ - Type: &proto.Provision_Request_Cancel{ - Cancel: &proto.Provision_Cancel{}, - }, - }) + err = sess.Send(&proto.Request{Type: &proto.Request_Cancel{Cancel: &proto.CancelRequest{}}}) require.NoError(t, err) for { - msg, err := response.Recv() + msg, err := sess.Recv() require.NoError(t, err) - if c := msg.GetComplete(); c != nil { + if c := msg.GetPlan(); c != nil { require.Contains(t, c.Error, "killed") break } @@ -258,17 +279,18 @@ func TestProvision(t *testing.T) { t.Parallel() testCases := []struct { - Name string - Files map[string]string - Request *proto.Provision_Plan + Name string + Files map[string]string + Metadata *proto.Metadata + Request *proto.PlanRequest // Response may be nil to not check the response. - Response *proto.Provision_Response - // If ErrorContains is not empty, then response.Recv() should return an - // error containing this string before a Complete response is returned. + Response *proto.PlanComplete + // If ErrorContains is not empty, PlanComplete should have an Error containing the given string ErrorContains string // If ExpectLogContains is not empty, then the logs should contain it. ExpectLogContains string - Apply bool + // If Apply is true, then send an Apply request and check we get the same Resources as in Response. + Apply bool }{ { Name: "missing-variable", @@ -293,15 +315,11 @@ func TestProvision(t *testing.T) { Files: map[string]string{ "main.tf": `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", - }}, - }, - }, + Response: &proto.PlanComplete{ + Resources: []*proto.Resource{{ + Name: "A", + Type: "null_resource", + }}, }, }, { @@ -309,15 +327,11 @@ func TestProvision(t *testing.T) { Files: map[string]string{ "main.tf": `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", - }}, - }, - }, + Response: &proto.PlanComplete{ + Resources: []*proto.Resource{{ + Name: "A", + Type: "null_resource", + }}, }, Apply: true, }, @@ -334,15 +348,11 @@ func TestProvision(t *testing.T) { } }`, }, - Response: &proto.Provision_Response{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Resources: []*proto.Resource{{ - Name: "A", - Type: "null_resource", - }}, - }, - }, + Response: &proto.PlanComplete{ + Resources: []*proto.Resource{{ + Name: "A", + Type: "null_resource", + }}, }, Apply: true, }, @@ -367,12 +377,8 @@ func TestProvision(t *testing.T) { Files: map[string]string{ "main.tf": `resource "null_resource" "A" {}`, }, - Request: &proto.Provision_Plan{ - Config: &proto.Provision_Config{ - Metadata: &proto.Provision_Metadata{ - WorkspaceTransition: proto.WorkspaceTransition_DESTROY, - }, - }, + Metadata: &proto.Metadata{ + WorkspaceTransition: proto.WorkspaceTransition_DESTROY, }, ExpectLogContains: "nothing to do", }, @@ -406,7 +412,7 @@ func TestProvision(t *testing.T) { } }`, }, - Request: &proto.Provision_Plan{ + Request: &proto.PlanRequest{ RichParameterValues: []*proto.RichParameterValue{ { Name: "Example", @@ -418,27 +424,23 @@ func TestProvision(t *testing.T) { }, }, }, - Response: &proto.Provision_Response{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Parameters: []*proto.RichParameter{ - { - Name: "Example", - Type: "string", - DefaultValue: "foobar", - }, - { - Name: "Sample", - Type: "string", - DefaultValue: "foobaz", - }, - }, - Resources: []*proto.Resource{{ - Name: "example", - Type: "null_resource", - }}, + Response: &proto.PlanComplete{ + Parameters: []*proto.RichParameter{ + { + Name: "Example", + Type: "string", + DefaultValue: "foobar", + }, + { + Name: "Sample", + Type: "string", + DefaultValue: "foobaz", }, }, + Resources: []*proto.Resource{{ + Name: "example", + Type: "null_resource", + }}, }, }, { @@ -488,7 +490,7 @@ func TestProvision(t *testing.T) { ] }`, }, - Request: &proto.Provision_Plan{ + Request: &proto.PlanRequest{ RichParameterValues: []*proto.RichParameterValue{ { Name: "Example", @@ -500,27 +502,23 @@ func TestProvision(t *testing.T) { }, }, }, - Response: &proto.Provision_Response{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Parameters: []*proto.RichParameter{ - { - Name: "Example", - Type: "string", - DefaultValue: "foobar", - }, - { - Name: "Sample", - Type: "string", - DefaultValue: "foobaz", - }, - }, - Resources: []*proto.Resource{{ - Name: "example", - Type: "null_resource", - }}, + Response: &proto.PlanComplete{ + Parameters: []*proto.RichParameter{ + { + Name: "Example", + Type: "string", + DefaultValue: "foobar", + }, + { + Name: "Sample", + Type: "string", + DefaultValue: "foobaz", }, }, + Resources: []*proto.Resource{{ + Name: "example", + Type: "null_resource", + }}, }, }, { @@ -550,25 +548,21 @@ func TestProvision(t *testing.T) { } `, }, - Request: &proto.Provision_Plan{ + Request: &proto.PlanRequest{ GitAuthProviders: []*proto.GitAuthProvider{{ Id: "github", AccessToken: "some-value", }}, }, - Response: &proto.Provision_Response{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ - Resources: []*proto.Resource{{ - Name: "example", - Type: "null_resource", - Metadata: []*proto.Resource_Metadata{{ - Key: "token", - Value: "some-value", - }}, - }}, - }, - }, + Response: &proto.PlanComplete{ + Resources: []*proto.Resource{{ + Name: "example", + Type: "null_resource", + Metadata: []*proto.Resource_Metadata{{ + Key: "token", + Value: "some-value", + }}, + }}, }, }, } @@ -579,50 +573,26 @@ func TestProvision(t *testing.T) { t.Parallel() ctx, api := setupProvisioner(t, nil) + sess := configure(ctx, t, api, &proto.Config{ + TemplateSourceArchive: makeTar(t, testCase.Files), + }) - directory := t.TempDir() - for path, content := range testCase.Files { - err := os.WriteFile(filepath.Join(directory, path), []byte(content), 0o600) - require.NoError(t, err) - } - - planRequest := &proto.Provision_Request{ - Type: &proto.Provision_Request_Plan{ - Plan: &proto.Provision_Plan{ - Config: &proto.Provision_Config{ - Directory: directory, - }, - }, - }, - } + planRequest := &proto.Request{Type: &proto.Request_Plan{Plan: &proto.PlanRequest{ + Metadata: testCase.Metadata, + }}} if testCase.Request != nil { - if planRequest.GetPlan().GetConfig() == nil { - planRequest.GetPlan().Config = &proto.Provision_Config{} - } - planRequest.GetPlan().RichParameterValues = testCase.Request.RichParameterValues - planRequest.GetPlan().GitAuthProviders = testCase.Request.GitAuthProviders - if testCase.Request.Config != nil { - planRequest.GetPlan().Config.State = testCase.Request.Config.State - planRequest.GetPlan().Config.Metadata = testCase.Request.Config.Metadata - } - } - if planRequest.GetPlan().Config.Metadata == nil { - planRequest.GetPlan().Config.Metadata = &proto.Provision_Metadata{} + planRequest = &proto.Request{Type: &proto.Request_Plan{Plan: testCase.Request}} } gotExpectedLog := testCase.ExpectLogContains == "" - provision := func(req *proto.Provision_Request) *proto.Provision_Complete { - response, err := api.Provision(ctx) + provision := func(req *proto.Request) *proto.Response { + err := sess.Send(req) require.NoError(t, err) - err = response.Send(req) - require.NoError(t, err) - - var complete *proto.Provision_Complete - for { - msg, err := response.Recv() - if msg != nil && msg.GetLog() != nil { + msg, err := sess.Recv() + require.NoError(t, err) + if msg.GetLog() != nil { if testCase.ExpectLogContains != "" && strings.Contains(msg.GetLog().Output, testCase.ExpectLogContains) { gotExpectedLog = true } @@ -630,67 +600,51 @@ func TestProvision(t *testing.T) { t.Logf("log: [%s] %s", msg.GetLog().Level, msg.GetLog().Output) continue } - if testCase.ErrorContains != "" { - require.ErrorContains(t, err, testCase.ErrorContains) - break - } - require.NoError(t, err) - - if complete = msg.GetComplete(); complete == nil { - continue - } - - require.NoError(t, err) - - // Remove randomly generated data. - for _, resource := range msg.GetComplete().Resources { - sort.Slice(resource.Agents, func(i, j int) bool { - return resource.Agents[i].Name < resource.Agents[j].Name - }) - - for _, agent := range resource.Agents { - agent.Id = "" - if agent.GetToken() == "" { - continue - } - agent.Auth = &proto.Agent_Token{} - } - } - - if testCase.Response != nil { - require.Equal(t, testCase.Response.GetComplete().Error, msg.GetComplete().Error) - - resourcesGot, err := json.Marshal(msg.GetComplete().Resources) - require.NoError(t, err) - resourcesWant, err := json.Marshal(testCase.Response.GetComplete().Resources) - require.NoError(t, err) - - require.Equal(t, string(resourcesWant), string(resourcesGot)) - - parametersGot, err := json.Marshal(msg.GetComplete().Parameters) - require.NoError(t, err) - parametersWant, err := json.Marshal(testCase.Response.GetComplete().Parameters) - require.NoError(t, err) - require.Equal(t, string(parametersWant), string(parametersGot)) - } - break + return msg } - - return complete } - planComplete := provision(planRequest) + resp := provision(planRequest) + planComplete := resp.GetPlan() + require.NotNil(t, planComplete) + + if testCase.ErrorContains != "" { + require.Contains(t, planComplete.GetError(), testCase.ErrorContains) + } + + if testCase.Response != nil { + require.Equal(t, testCase.Response.Error, planComplete.Error) + + // Remove randomly generated data. + normalizeResources(planComplete.Resources) + resourcesGot, err := json.Marshal(planComplete.Resources) + require.NoError(t, err) + resourcesWant, err := json.Marshal(testCase.Response.Resources) + require.NoError(t, err) + require.Equal(t, string(resourcesWant), string(resourcesGot)) + + parametersGot, err := json.Marshal(planComplete.Parameters) + require.NoError(t, err) + parametersWant, err := json.Marshal(testCase.Response.Parameters) + require.NoError(t, err) + require.Equal(t, string(parametersWant), string(parametersGot)) + } if testCase.Apply { - require.NotNil(t, planComplete.Plan) - provision(&proto.Provision_Request{ - Type: &proto.Provision_Request_Apply{ - Apply: &proto.Provision_Apply{ - Config: planRequest.GetPlan().GetConfig(), - Plan: planComplete.Plan, - }, - }, - }) + resp = provision(&proto.Request{Type: &proto.Request_Apply{Apply: &proto.ApplyRequest{ + Metadata: &proto.Metadata{WorkspaceTransition: proto.WorkspaceTransition_START}, + }}}) + applyComplete := resp.GetApply() + require.NotNil(t, applyComplete) + + if testCase.Response != nil { + normalizeResources(applyComplete.Resources) + resourcesGot, err := json.Marshal(applyComplete.Resources) + require.NoError(t, err) + resourcesWant, err := json.Marshal(testCase.Response.Resources) + require.NoError(t, err) + require.Equal(t, string(resourcesWant), string(resourcesGot)) + } } if !gotExpectedLog { @@ -700,6 +654,22 @@ func TestProvision(t *testing.T) { } } +func normalizeResources(resources []*proto.Resource) { + for _, resource := range resources { + sort.Slice(resource.Agents, func(i, j int) bool { + return resource.Agents[i].Name < resource.Agents[j].Name + }) + + for _, agent := range resource.Agents { + agent.Id = "" + if agent.GetToken() == "" { + continue + } + agent.Auth = &proto.Agent_Token{} + } + } +} + // nolint:paralleltest func TestProvision_ExtraEnv(t *testing.T) { // #nosec @@ -708,31 +678,15 @@ func TestProvision_ExtraEnv(t *testing.T) { t.Setenv("TF_SUPERSECRET", secretValue) ctx, api := setupProvisioner(t, nil) + sess := configure(ctx, t, api, &proto.Config{ + TemplateSourceArchive: makeTar(t, map[string]string{"main.tf": `resource "null_resource" "A" {}`}), + }) - directory := t.TempDir() - path := filepath.Join(directory, "main.tf") - err := os.WriteFile(path, []byte(`resource "null_resource" "A" {}`), 0o600) - require.NoError(t, err) - - request := &proto.Provision_Request{ - Type: &proto.Provision_Request_Plan{ - Plan: &proto.Provision_Plan{ - Config: &proto.Provision_Config{ - Directory: directory, - Metadata: &proto.Provision_Metadata{ - WorkspaceTransition: proto.WorkspaceTransition_START, - }, - }, - }, - }, - } - response, err := api.Provision(ctx) - require.NoError(t, err) - err = response.Send(request) + err := sendPlan(sess, proto.WorkspaceTransition_START) require.NoError(t, err) found := false for { - msg, err := response.Recv() + msg, err := sess.Recv() require.NoError(t, err) if log := msg.GetLog(); log != nil { @@ -742,7 +696,7 @@ func TestProvision_ExtraEnv(t *testing.T) { } require.NotContains(t, log.Output, secretValue) } - if c := msg.GetComplete(); c != nil { + if c := msg.GetPlan(); c != nil { require.Empty(t, c.Error) break } @@ -774,48 +728,19 @@ func TestProvision_SafeEnv(t *testing.T) { ` ctx, api := setupProvisioner(t, nil) - - directory := t.TempDir() - path := filepath.Join(directory, "main.tf") - err := os.WriteFile(path, []byte(echoResource), 0o600) - require.NoError(t, err) - - response, err := api.Provision(ctx) - require.NoError(t, err) - err = response.Send(&proto.Provision_Request{ - Type: &proto.Provision_Request_Plan{ - Plan: &proto.Provision_Plan{ - Config: &proto.Provision_Config{ - Directory: directory, - Metadata: &proto.Provision_Metadata{ - WorkspaceTransition: proto.WorkspaceTransition_START, - }, - }, - }, - }, + sess := configure(ctx, t, api, &proto.Config{ + TemplateSourceArchive: makeTar(t, map[string]string{"main.tf": echoResource}), }) + + err := sendPlan(sess, proto.WorkspaceTransition_START) require.NoError(t, err) - _, complete := readProvisionLog(t, response) + _ = readProvisionLog(t, sess) - response, err = api.Provision(ctx) - require.NoError(t, err) - err = response.Send(&proto.Provision_Request{ - Type: &proto.Provision_Request_Apply{ - Apply: &proto.Provision_Apply{ - Config: &proto.Provision_Config{ - Directory: directory, - Metadata: &proto.Provision_Metadata{ - WorkspaceTransition: proto.WorkspaceTransition_START, - }, - }, - Plan: complete.GetPlan(), - }, - }, - }) + err = sendApply(sess, proto.WorkspaceTransition_START) require.NoError(t, err) - log, _ := readProvisionLog(t, response) + log := readProvisionLog(t, sess) require.Contains(t, log, passedValue) require.NotContains(t, log, secretValue) require.Contains(t, log, "CODER_") diff --git a/provisioner/terraform/serve.go b/provisioner/terraform/serve.go index 7a25d27dca..0fc12ea870 100644 --- a/provisioner/terraform/serve.go +++ b/provisioner/terraform/serve.go @@ -24,7 +24,6 @@ type ServeOptions struct { BinaryPath string // CachePath must not be used by multiple processes at once. CachePath string - Logger slog.Logger Tracer trace.Tracer // ExitTimeout defines how long we will wait for a running Terraform @@ -128,5 +127,6 @@ func (s *server) executor(workdir string) *executor { binaryPath: s.binaryPath, cachePath: s.cachePath, workdir: workdir, + logger: s.logger.Named("executor"), } } diff --git a/provisioner/terraform/testdata/fake_cancel.sh b/provisioner/terraform/testdata/fake_cancel.sh index cd2511facf..2ea713379c 100755 --- a/provisioner/terraform/testdata/fake_cancel.sh +++ b/provisioner/terraform/testdata/fake_cancel.sh @@ -22,8 +22,9 @@ version) ;; init) case "$MODE" in - apply) + plan) echo "init" + exit 0 ;; init) sleep 10 & @@ -39,7 +40,7 @@ init) ;; esac ;; -apply) +plan) sleep 10 & sleep_pid=$! @@ -47,14 +48,14 @@ apply) trap 'json_print interrupt; exit 1' INT trap 'json_print terminate; exit 2' TERM - json_print apply_start + json_print plan_start wait - json_print apply_end + json_print plan_end ;; -plan) - echo "plan not supported" +apply) + echo "apply not supported" exit 1 ;; esac -exit 0 +exit 10 diff --git a/provisioner/terraform/testdata/fake_cancel_hang.sh b/provisioner/terraform/testdata/fake_cancel_hang.sh index c6d29c88c7..e8db67f683 100755 --- a/provisioner/terraform/testdata/fake_cancel_hang.sh +++ b/provisioner/terraform/testdata/fake_cancel_hang.sh @@ -23,19 +23,19 @@ init) echo "init" exit 0 ;; -apply) +plan) trap 'json_print interrupt' INT - json_print apply_start + json_print plan_start sleep 10 2>/dev/null >/dev/null - json_print apply_end + json_print plan_end exit 0 ;; -plan) - echo "plan not supported" +apply) + echo "apply not supported" exit 1 ;; esac -exit 0 +exit 10 diff --git a/provisionerd/proto/provisionerd.pb.go b/provisionerd/proto/provisionerd.pb.go index 29a1e7dc50..018e0f25ac 100644 --- a/provisionerd/proto/provisionerd.pb.go +++ b/provisionerd/proto/provisionerd.pb.go @@ -819,7 +819,7 @@ type AcquiredJob_WorkspaceBuild struct { RichParameterValues []*proto.RichParameterValue `protobuf:"bytes,4,rep,name=rich_parameter_values,json=richParameterValues,proto3" json:"rich_parameter_values,omitempty"` VariableValues []*proto.VariableValue `protobuf:"bytes,5,rep,name=variable_values,json=variableValues,proto3" json:"variable_values,omitempty"` GitAuthProviders []*proto.GitAuthProvider `protobuf:"bytes,6,rep,name=git_auth_providers,json=gitAuthProviders,proto3" json:"git_auth_providers,omitempty"` - Metadata *proto.Provision_Metadata `protobuf:"bytes,7,opt,name=metadata,proto3" json:"metadata,omitempty"` + Metadata *proto.Metadata `protobuf:"bytes,7,opt,name=metadata,proto3" json:"metadata,omitempty"` State []byte `protobuf:"bytes,8,opt,name=state,proto3" json:"state,omitempty"` LogLevel string `protobuf:"bytes,9,opt,name=log_level,json=logLevel,proto3" json:"log_level,omitempty"` } @@ -891,7 +891,7 @@ func (x *AcquiredJob_WorkspaceBuild) GetGitAuthProviders() []*proto.GitAuthProvi return nil } -func (x *AcquiredJob_WorkspaceBuild) GetMetadata() *proto.Provision_Metadata { +func (x *AcquiredJob_WorkspaceBuild) GetMetadata() *proto.Metadata { if x != nil { return x.Metadata } @@ -917,8 +917,8 @@ type AcquiredJob_TemplateImport struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - Metadata *proto.Provision_Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` - UserVariableValues []*proto.VariableValue `protobuf:"bytes,2,rep,name=user_variable_values,json=userVariableValues,proto3" json:"user_variable_values,omitempty"` + Metadata *proto.Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + UserVariableValues []*proto.VariableValue `protobuf:"bytes,2,rep,name=user_variable_values,json=userVariableValues,proto3" json:"user_variable_values,omitempty"` } func (x *AcquiredJob_TemplateImport) Reset() { @@ -953,7 +953,7 @@ func (*AcquiredJob_TemplateImport) Descriptor() ([]byte, []int) { return file_provisionerd_proto_provisionerd_proto_rawDescGZIP(), []int{1, 1} } -func (x *AcquiredJob_TemplateImport) GetMetadata() *proto.Provision_Metadata { +func (x *AcquiredJob_TemplateImport) GetMetadata() *proto.Metadata { if x != nil { return x.Metadata } @@ -974,7 +974,7 @@ type AcquiredJob_TemplateDryRun struct { RichParameterValues []*proto.RichParameterValue `protobuf:"bytes,2,rep,name=rich_parameter_values,json=richParameterValues,proto3" json:"rich_parameter_values,omitempty"` VariableValues []*proto.VariableValue `protobuf:"bytes,3,rep,name=variable_values,json=variableValues,proto3" json:"variable_values,omitempty"` - Metadata *proto.Provision_Metadata `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"` + Metadata *proto.Metadata `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"` } func (x *AcquiredJob_TemplateDryRun) Reset() { @@ -1023,7 +1023,7 @@ func (x *AcquiredJob_TemplateDryRun) GetVariableValues() []*proto.VariableValue return nil } -func (x *AcquiredJob_TemplateDryRun) GetMetadata() *proto.Provision_Metadata { +func (x *AcquiredJob_TemplateDryRun) GetMetadata() *proto.Metadata { if x != nil { return x.Metadata } @@ -1335,7 +1335,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, 0xab, 0x0b, 0x0a, 0x0b, 0x41, 0x63, 0x71, 0x75, 0x69, + 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0x8d, 0x0b, 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, @@ -1368,7 +1368,7 @@ var file_provisionerd_proto_provisionerd_proto_rawDesc = []byte{ 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, 0x74, 0x72, 0x61, 0x63, 0x65, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0xc1, 0x03, 0x0a, 0x0e, 0x57, 0x6f, 0x72, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0xb7, 0x03, 0x0a, 0x0e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, @@ -1389,193 +1389,191 @@ var file_provisionerd_proto_provisionerd_proto_rawDesc = []byte{ 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x47, 0x69, 0x74, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x10, 0x67, 0x69, 0x74, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, - 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x12, 0x3b, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x18, 0x07, 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, 0x08, 0x20, 0x01, - 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x67, - 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, - 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x1a, 0x9b, 0x01, 0x0a, - 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 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, 0x12, 0x4c, 0x0a, 0x14, - 0x75, 0x73, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, - 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x75, 0x73, 0x65, 0x72, 0x56, 0x61, 0x72, 0x69, - 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x1a, 0xed, 0x01, 0x0a, 0x0e, 0x54, - 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x53, 0x0a, - 0x15, 0x72, 0x69, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, - 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, - 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x72, - 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x73, 0x12, 0x43, 0x0a, 0x0f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, - 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, - 0x65, 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, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x1a, 0x40, 0x0a, 0x12, 0x54, 0x72, - 0x61, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 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, - 0x74, 0x79, 0x70, 0x65, 0x22, 0xa5, 0x03, 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, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x12, - 0x51, 0x0a, 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, - 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 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, 0x42, 0x75, 0x69, 0x6c, 0x64, - 0x48, 0x00, 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, - 0x6c, 0x64, 0x12, 0x51, 0x0a, 0x0f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, - 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x65, - 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x70, - 0x6f, 0x72, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, - 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x52, 0x0a, 0x10, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, - 0x65, 0x5f, 0x64, 0x72, 0x79, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x46, - 0x61, 0x69, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, - 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x48, 0x00, 0x52, 0x0e, 0x74, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x65, 0x72, 0x72, - 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x65, - 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x1a, 0x26, 0x0a, 0x0e, 0x57, 0x6f, 0x72, 0x6b, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, - 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, - 0x1a, 0x10, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6f, - 0x72, 0x74, 0x1a, 0x10, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, - 0x79, 0x52, 0x75, 0x6e, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xd8, 0x05, 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, 0x54, 0x0a, 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, - 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 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, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x00, 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x54, 0x0a, 0x0f, 0x74, 0x65, - 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x29, 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, - 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x48, 0x00, - 0x52, 0x0e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, - 0x12, 0x55, 0x0a, 0x10, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x64, 0x72, 0x79, - 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 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, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, - 0x72, 0x79, 0x52, 0x75, 0x6e, 0x48, 0x00, 0x52, 0x0e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, - 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x1a, 0x5b, 0x0a, 0x0e, 0x57, 0x6f, 0x72, 0x6b, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 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, 0x81, 0x02, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, - 0x65, 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, 0x12, 0x43, 0x0a, 0x0f, 0x72, 0x69, 0x63, 0x68, 0x5f, 0x70, 0x61, - 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, - 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, - 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, 0x0e, 0x72, 0x69, 0x63, 0x68, - 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x67, 0x69, - 0x74, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x67, 0x69, 0x74, 0x41, 0x75, 0x74, 0x68, 0x50, - 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x1a, 0x45, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, - 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x33, 0x0a, 0x09, 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, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x73, 0x42, - 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xb0, 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, 0x14, 0x0a, 0x05, - 0x73, 0x74, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, 0x74, 0x61, - 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x05, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x8a, 0x02, 0x0a, 0x10, 0x55, - 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, + 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 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, 0x08, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, + 0x1b, 0x0a, 0x09, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x09, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x4a, 0x04, 0x08, 0x03, + 0x10, 0x04, 0x1a, 0x91, 0x01, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, + 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, + 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x4c, 0x0a, 0x14, 0x75, 0x73, 0x65, 0x72, + 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, + 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x52, 0x12, 0x75, 0x73, 0x65, 0x72, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x1a, 0xe3, 0x01, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x53, 0x0a, 0x15, 0x72, 0x69, 0x63, + 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, + 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, + 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x72, 0x69, 0x63, 0x68, 0x50, + 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x43, + 0x0a, 0x0f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, + 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, + 0x75, 0x65, 0x73, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, + 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x4a, 0x04, 0x08, 0x01, 0x10, 0x02, 0x1a, 0x40, 0x0a, 0x12, + 0x54, 0x72, 0x61, 0x63, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 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, 0x74, 0x79, 0x70, 0x65, 0x22, 0xa5, 0x03, 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, 0x14, 0x0a, 0x05, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, 0x72, 0x6f, + 0x72, 0x12, 0x51, 0x0a, 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x62, + 0x75, 0x69, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 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, 0x42, 0x75, 0x69, + 0x6c, 0x64, 0x48, 0x00, 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, + 0x75, 0x69, 0x6c, 0x64, 0x12, 0x51, 0x0a, 0x0f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, + 0x5f, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x26, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x46, 0x61, 0x69, + 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, + 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x48, 0x00, 0x52, 0x0e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, + 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x52, 0x0a, 0x10, 0x74, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x74, 0x65, 0x5f, 0x64, 0x72, 0x79, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x26, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, + 0x2e, 0x46, 0x61, 0x69, 0x6c, 0x65, 0x64, 0x4a, 0x6f, 0x62, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x48, 0x00, 0x52, 0x0e, 0x74, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x1d, 0x0a, 0x0a, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x43, 0x6f, 0x64, 0x65, 0x1a, 0x26, 0x0a, 0x0e, 0x57, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x14, 0x0a, 0x05, + 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, + 0x74, 0x65, 0x1a, 0x10, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x6d, + 0x70, 0x6f, 0x72, 0x74, 0x1a, 0x10, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, + 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xd8, + 0x05, 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, 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, 0x4c, 0x0a, - 0x12, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, - 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, - 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x11, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, - 0x74, 0x65, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x4c, 0x0a, 0x14, 0x75, - 0x73, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, - 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, - 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x75, 0x73, 0x65, 0x72, 0x56, 0x61, 0x72, 0x69, 0x61, - 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, - 0x64, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, - 0x65, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0x7a, 0x0a, 0x11, 0x55, 0x70, 0x64, 0x61, 0x74, - 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, 0x0a, 0x08, - 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, - 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x0f, 0x76, 0x61, 0x72, 0x69, - 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, - 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x76, - 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x4a, 0x04, 0x08, - 0x02, 0x10, 0x03, 0x22, 0x4a, 0x0a, 0x12, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, - 0x74, 0x61, 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, 0x1d, 0x0a, 0x0a, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x02, - 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x43, 0x6f, 0x73, 0x74, 0x22, - 0x68, 0x0a, 0x13, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x52, 0x65, - 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x08, 0x52, 0x02, 0x6f, 0x6b, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, - 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x0f, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x73, 0x43, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, - 0x64, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x64, 0x67, 0x65, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, - 0x05, 0x52, 0x06, 0x62, 0x75, 0x64, 0x67, 0x65, 0x74, 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, - 0xec, 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, 0x52, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, - 0x74, 0x61, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, - 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x52, 0x65, 0x71, - 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x54, 0x0a, 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, + 0x61, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x29, 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, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x48, 0x00, 0x52, 0x0e, 0x77, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x54, 0x0a, 0x0f, + 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 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, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, + 0x48, 0x00, 0x52, 0x0e, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6f, + 0x72, 0x74, 0x12, 0x55, 0x0a, 0x10, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x64, + 0x72, 0x79, 0x5f, 0x72, 0x75, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x29, 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, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, + 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x48, 0x00, 0x52, 0x0e, 0x74, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x1a, 0x5b, 0x0a, 0x0e, 0x57, 0x6f, 0x72, + 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 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, 0x81, 0x02, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, + 0x61, 0x74, 0x65, 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, 0x12, 0x43, 0x0a, 0x0f, 0x72, 0x69, 0x63, 0x68, 0x5f, + 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, + 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, + 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, 0x0e, 0x72, 0x69, + 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2c, 0x0a, 0x12, + 0x67, 0x69, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x67, 0x69, 0x74, 0x41, 0x75, 0x74, + 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x1a, 0x45, 0x0a, 0x0e, 0x54, 0x65, + 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x33, 0x0a, 0x09, + 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, 0x09, 0x72, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x73, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xb0, 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, 0x14, + 0x0a, 0x05, 0x73, 0x74, 0x61, 0x67, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x73, + 0x74, 0x61, 0x67, 0x65, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x05, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x8a, 0x02, 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, + 0x4c, 0x0a, 0x12, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x72, 0x69, + 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, + 0x74, 0x65, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x11, 0x74, 0x65, 0x6d, 0x70, + 0x6c, 0x61, 0x74, 0x65, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x4c, 0x0a, + 0x14, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, + 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x75, 0x73, 0x65, 0x72, 0x56, 0x61, 0x72, + 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, + 0x65, 0x61, 0x64, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, 0x61, + 0x64, 0x6d, 0x65, 0x4a, 0x04, 0x08, 0x03, 0x10, 0x04, 0x22, 0x7a, 0x0a, 0x11, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x1a, + 0x0a, 0x08, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x08, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x65, 0x64, 0x12, 0x43, 0x0a, 0x0f, 0x76, 0x61, + 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, + 0x0e, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x4a, + 0x04, 0x08, 0x02, 0x10, 0x03, 0x22, 0x4a, 0x0a, 0x12, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, + 0x75, 0x6f, 0x74, 0x61, 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, 0x1d, 0x0a, 0x0a, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x5f, 0x63, 0x6f, 0x73, 0x74, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x43, 0x6f, 0x73, + 0x74, 0x22, 0x68, 0x0a, 0x13, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, + 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x0e, 0x0a, 0x02, 0x6f, 0x6b, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x08, 0x52, 0x02, 0x6f, 0x6b, 0x12, 0x29, 0x0a, 0x10, 0x63, 0x72, 0x65, 0x64, + 0x69, 0x74, 0x73, 0x5f, 0x63, 0x6f, 0x6e, 0x73, 0x75, 0x6d, 0x65, 0x64, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x05, 0x52, 0x0f, 0x63, 0x72, 0x65, 0x64, 0x69, 0x74, 0x73, 0x43, 0x6f, 0x6e, 0x73, 0x75, + 0x6d, 0x65, 0x64, 0x12, 0x16, 0x0a, 0x06, 0x62, 0x75, 0x64, 0x67, 0x65, 0x74, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x05, 0x52, 0x06, 0x62, 0x75, 0x64, 0x67, 0x65, 0x74, 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, 0xec, 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, 0x52, 0x0a, 0x0b, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, + 0x75, 0x6f, 0x74, 0x61, 0x12, 0x20, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, 0x61, 0x52, - 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 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, 0x2e, - 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, - 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, 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, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x21, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x43, 0x6f, 0x6d, 0x6d, 0x69, 0x74, 0x51, 0x75, 0x6f, 0x74, + 0x61, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 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, 0x2e, 0x5a, 0x2c, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, + 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, 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 ( @@ -1618,7 +1616,7 @@ var file_provisionerd_proto_provisionerd_proto_goTypes = []interface{}{ (*proto.VariableValue)(nil), // 22: provisioner.VariableValue (*proto.RichParameterValue)(nil), // 23: provisioner.RichParameterValue (*proto.GitAuthProvider)(nil), // 24: provisioner.GitAuthProvider - (*proto.Provision_Metadata)(nil), // 25: provisioner.Provision.Metadata + (*proto.Metadata)(nil), // 25: provisioner.Metadata (*proto.Resource)(nil), // 26: provisioner.Resource (*proto.RichParameter)(nil), // 27: provisioner.RichParameter } @@ -1642,12 +1640,12 @@ var file_provisionerd_proto_provisionerd_proto_depIdxs = []int32{ 23, // 16: provisionerd.AcquiredJob.WorkspaceBuild.rich_parameter_values:type_name -> provisioner.RichParameterValue 22, // 17: provisionerd.AcquiredJob.WorkspaceBuild.variable_values:type_name -> provisioner.VariableValue 24, // 18: provisionerd.AcquiredJob.WorkspaceBuild.git_auth_providers:type_name -> provisioner.GitAuthProvider - 25, // 19: provisionerd.AcquiredJob.WorkspaceBuild.metadata:type_name -> provisioner.Provision.Metadata - 25, // 20: provisionerd.AcquiredJob.TemplateImport.metadata:type_name -> provisioner.Provision.Metadata + 25, // 19: provisionerd.AcquiredJob.WorkspaceBuild.metadata:type_name -> provisioner.Metadata + 25, // 20: provisionerd.AcquiredJob.TemplateImport.metadata:type_name -> provisioner.Metadata 22, // 21: provisionerd.AcquiredJob.TemplateImport.user_variable_values:type_name -> provisioner.VariableValue 23, // 22: provisionerd.AcquiredJob.TemplateDryRun.rich_parameter_values:type_name -> provisioner.RichParameterValue 22, // 23: provisionerd.AcquiredJob.TemplateDryRun.variable_values:type_name -> provisioner.VariableValue - 25, // 24: provisionerd.AcquiredJob.TemplateDryRun.metadata:type_name -> provisioner.Provision.Metadata + 25, // 24: provisionerd.AcquiredJob.TemplateDryRun.metadata:type_name -> provisioner.Metadata 26, // 25: provisionerd.CompletedJob.WorkspaceBuild.resources:type_name -> provisioner.Resource 26, // 26: provisionerd.CompletedJob.TemplateImport.start_resources:type_name -> provisioner.Resource 26, // 27: provisionerd.CompletedJob.TemplateImport.stop_resources:type_name -> provisioner.Resource diff --git a/provisionerd/proto/provisionerd.proto b/provisionerd/proto/provisionerd.proto index 2a417f48a0..8d4fadffc6 100644 --- a/provisionerd/proto/provisionerd.proto +++ b/provisionerd/proto/provisionerd.proto @@ -19,12 +19,12 @@ message AcquiredJob { repeated provisioner.RichParameterValue rich_parameter_values = 4; repeated provisioner.VariableValue variable_values = 5; repeated provisioner.GitAuthProvider git_auth_providers = 6; - provisioner.Provision.Metadata metadata = 7; + provisioner.Metadata metadata = 7; bytes state = 8; string log_level = 9; } message TemplateImport { - provisioner.Provision.Metadata metadata = 1; + provisioner.Metadata metadata = 1; repeated provisioner.VariableValue user_variable_values = 2; } message TemplateDryRun { @@ -32,7 +32,7 @@ message AcquiredJob { repeated provisioner.RichParameterValue rich_parameter_values = 2; repeated provisioner.VariableValue variable_values = 3; - provisioner.Provision.Metadata metadata = 4; + provisioner.Metadata metadata = 4; } string job_id = 1; @@ -45,9 +45,9 @@ message AcquiredJob { TemplateImport template_import = 7; TemplateDryRun template_dry_run = 8; } - // trace_metadata is currently used for tracing information only. It allows - // jobs to be tied to the request that created them. - map trace_metadata = 9; + // trace_metadata is currently used for tracing information only. It allows + // jobs to be tied to the request that created them. + map trace_metadata = 9; } message FailedJob { @@ -113,7 +113,7 @@ message UpdateJobRequest { string job_id = 1; repeated Log logs = 2; repeated provisioner.TemplateVariable template_variables = 4; - repeated provisioner.VariableValue user_variable_values = 5; + repeated provisioner.VariableValue user_variable_values = 5; bytes readme = 6; } @@ -121,7 +121,7 @@ message UpdateJobResponse { reserved 2; bool canceled = 1; - repeated provisioner.VariableValue variable_values = 3; + repeated provisioner.VariableValue variable_values = 3; } message CommitQuotaRequest { diff --git a/provisionerd/provisionerd.go b/provisionerd/provisionerd.go index f127ab7b58..a341bd5a3d 100644 --- a/provisionerd/provisionerd.go +++ b/provisionerd/provisionerd.go @@ -12,7 +12,6 @@ import ( "github.com/hashicorp/yamux" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/spf13/afero" "github.com/valyala/fasthttp/fasthttputil" "go.opentelemetry.io/otel/attribute" semconv "go.opentelemetry.io/otel/semconv/v1.14.0" @@ -44,7 +43,6 @@ type Provisioners map[string]sdkproto.DRPCProvisionerClient // Options provides customizations to the behavior of a provisioner daemon. type Options struct { - Filesystem afero.Fs Logger slog.Logger TracerProvider trace.TracerProvider Metrics *Metrics @@ -56,8 +54,6 @@ type Options struct { JobPollJitter time.Duration JobPollDebounce time.Duration Provisioners Provisioners - // WorkDirectory must not be used by multiple processes at once. - WorkDirectory string } // New creates and starts a provisioner daemon. @@ -80,9 +76,6 @@ func New(clientDialer Dialer, opts *Options) *Server { if opts.LogBufferInterval == 0 { opts.LogBufferInterval = 250 * time.Millisecond } - if opts.Filesystem == nil { - opts.Filesystem = afero.NewOsFs() - } if opts.TracerProvider == nil { opts.TracerProvider = trace.NewNoopTracerProvider() } @@ -405,8 +398,6 @@ func (p *Server) acquireJob(ctx context.Context) { Updater: p, QuotaCommitter: p, Logger: p.opts.Logger.Named("runner"), - Filesystem: p.opts.Filesystem, - WorkDirectory: p.opts.WorkDirectory, Provisioner: provisioner, UpdateInterval: p.opts.UpdateInterval, ForceCancelInterval: p.opts.ForceCancelInterval, diff --git a/provisionerd/provisionerd_test.go b/provisionerd/provisionerd_test.go index 90b9923996..ee379e0ab9 100644 --- a/provisionerd/provisionerd_test.go +++ b/provisionerd/provisionerd_test.go @@ -25,7 +25,6 @@ import ( "cdr.dev/slog/sloggers/slogtest" "github.com/coder/coder/v2/provisionerd" "github.com/coder/coder/v2/provisionerd/proto" - "github.com/coder/coder/v2/provisionerd/runner" "github.com/coder/coder/v2/provisionersdk" sdkproto "github.com/coder/coder/v2/provisionersdk/proto" "github.com/coder/coder/v2/testutil" @@ -129,7 +128,7 @@ func TestProvisionerd(t *testing.T) { }), Type: &proto.AcquiredJob_TemplateImport_{ TemplateImport: &proto.AcquiredJob_TemplateImport{ - Metadata: &sdkproto.Provision_Metadata{}, + Metadata: &sdkproto.Metadata{}, }, }, }, nil @@ -144,10 +143,15 @@ func TestProvisionerd(t *testing.T) { }), nil }, provisionerd.Provisioners{ "someprovisioner": createProvisionerClient(t, done, provisionerTestServer{ - parse: func(request *sdkproto.Parse_Request, stream sdkproto.DRPCProvisioner_ParseStream) error { + parse: func(_ *provisionersdk.Session, _ *sdkproto.ParseRequest, _ <-chan struct{}) *sdkproto.ParseComplete { closerMutex.Lock() defer closerMutex.Unlock() - return closer.Close() + err := closer.Close() + c := &sdkproto.ParseComplete{} + if err != nil { + c.Error = err.Error() + } + return c }, }), }) @@ -180,7 +184,7 @@ func TestProvisionerd(t *testing.T) { }), Type: &proto.AcquiredJob_TemplateImport_{ TemplateImport: &proto.AcquiredJob_TemplateImport{ - Metadata: &sdkproto.Provision_Metadata{}, + Metadata: &sdkproto.Metadata{}, }, }, }, nil @@ -220,7 +224,7 @@ func TestProvisionerd(t *testing.T) { }), Type: &proto.AcquiredJob_TemplateImport_{ TemplateImport: &proto.AcquiredJob_TemplateImport{ - Metadata: &sdkproto.Provision_Metadata{}, + Metadata: &sdkproto.Metadata{}, }, }, }, nil @@ -235,9 +239,13 @@ func TestProvisionerd(t *testing.T) { }), nil }, provisionerd.Provisioners{ "someprovisioner": createProvisionerClient(t, done, provisionerTestServer{ - parse: func(request *sdkproto.Parse_Request, stream sdkproto.DRPCProvisioner_ParseStream) error { - <-stream.Context().Done() - return nil + parse: func( + _ *provisionersdk.Session, + _ *sdkproto.ParseRequest, + cancelOrComplete <-chan struct{}, + ) *sdkproto.ParseComplete { + <-cancelOrComplete + return &sdkproto.ParseComplete{} }, }), }) @@ -255,7 +263,6 @@ func TestProvisionerd(t *testing.T) { didComplete atomic.Bool didLog atomic.Bool didAcquireJob atomic.Bool - didDryRun = atomic.NewBool(true) didReadme atomic.Bool completeChan = make(chan struct{}) completeOnce sync.Once @@ -273,12 +280,12 @@ func TestProvisionerd(t *testing.T) { JobId: "test", Provisioner: "someprovisioner", TemplateSourceArchive: createTar(t, map[string]string{ - "test.txt": "content", - runner.ReadmeFile: "# A cool template 😎\n", + "test.txt": "content", + provisionersdk.ReadmeFile: "# A cool template 😎\n", }), Type: &proto.AcquiredJob_TemplateImport_{ TemplateImport: &proto.AcquiredJob_TemplateImport{ - Metadata: &sdkproto.Provision_Metadata{}, + Metadata: &sdkproto.Metadata{}, }, }, }, nil @@ -299,54 +306,34 @@ func TestProvisionerd(t *testing.T) { }), nil }, provisionerd.Provisioners{ "someprovisioner": createProvisionerClient(t, done, provisionerTestServer{ - parse: func(request *sdkproto.Parse_Request, stream sdkproto.DRPCProvisioner_ParseStream) error { - data, err := os.ReadFile(filepath.Join(request.Directory, "test.txt")) + parse: func( + s *provisionersdk.Session, + _ *sdkproto.ParseRequest, + cancelOrComplete <-chan struct{}, + ) *sdkproto.ParseComplete { + data, err := os.ReadFile(filepath.Join(s.WorkDirectory, "test.txt")) require.NoError(t, err) require.Equal(t, "content", string(data)) - - err = stream.Send(&sdkproto.Parse_Response{ - Type: &sdkproto.Parse_Response_Log{ - Log: &sdkproto.Log{ - Level: sdkproto.LogLevel_INFO, - Output: "hello", - }, - }, - }) - require.NoError(t, err) - - err = stream.Send(&sdkproto.Parse_Response{ - Type: &sdkproto.Parse_Response_Complete{ - Complete: &sdkproto.Parse_Complete{}, - }, - }) - require.NoError(t, err) - return nil + s.ProvisionLog(sdkproto.LogLevel_INFO, "hello") + return &sdkproto.ParseComplete{} }, - provision: func(stream sdkproto.DRPCProvisioner_ProvisionStream) error { - request, err := stream.Recv() - require.NoError(t, err) - if request.GetApply() != nil { - didDryRun.Store(false) + plan: func( + s *provisionersdk.Session, + _ *sdkproto.PlanRequest, + cancelOrComplete <-chan struct{}, + ) *sdkproto.PlanComplete { + s.ProvisionLog(sdkproto.LogLevel_INFO, "hello") + return &sdkproto.PlanComplete{ + Resources: []*sdkproto.Resource{}, } - err = stream.Send(&sdkproto.Provision_Response{ - Type: &sdkproto.Provision_Response_Log{ - Log: &sdkproto.Log{ - Level: sdkproto.LogLevel_INFO, - Output: "hello", - }, - }, - }) - require.NoError(t, err) - - err = stream.Send(&sdkproto.Provision_Response{ - Type: &sdkproto.Provision_Response_Complete{ - Complete: &sdkproto.Provision_Complete{ - Resources: []*sdkproto.Resource{}, - }, - }, - }) - require.NoError(t, err) - return nil + }, + apply: func( + _ *provisionersdk.Session, + _ *sdkproto.ApplyRequest, + _ <-chan struct{}, + ) *sdkproto.ApplyComplete { + t.Error("dry run should not apply") + return &sdkproto.ApplyComplete{} }, }), }) @@ -355,7 +342,6 @@ func TestProvisionerd(t *testing.T) { require.NoError(t, closer.Close()) assert.True(t, didLog.Load(), "should log some updates") assert.True(t, didComplete.Load(), "should complete the job") - assert.True(t, didDryRun.Load(), "should be a dry run") }) t.Run("TemplateDryRun", func(t *testing.T) { @@ -371,7 +357,7 @@ func TestProvisionerd(t *testing.T) { completeChan = make(chan struct{}) completeOnce sync.Once - metadata = &sdkproto.Provision_Metadata{} + metadata = &sdkproto.Metadata{} ) closer := createProvisionerd(t, func(ctx context.Context) (proto.DRPCProvisionerDaemonClient, error) { @@ -414,16 +400,22 @@ func TestProvisionerd(t *testing.T) { }), nil }, provisionerd.Provisioners{ "someprovisioner": createProvisionerClient(t, done, provisionerTestServer{ - provision: func(stream sdkproto.DRPCProvisioner_ProvisionStream) error { - err := stream.Send(&sdkproto.Provision_Response{ - Type: &sdkproto.Provision_Response_Complete{ - Complete: &sdkproto.Provision_Complete{ - Resources: []*sdkproto.Resource{}, - }, - }, - }) - require.NoError(t, err) - return nil + plan: func( + _ *provisionersdk.Session, + _ *sdkproto.PlanRequest, + _ <-chan struct{}, + ) *sdkproto.PlanComplete { + return &sdkproto.PlanComplete{ + Resources: []*sdkproto.Resource{}, + } + }, + apply: func( + _ *provisionersdk.Session, + _ *sdkproto.ApplyRequest, + _ <-chan struct{}, + ) *sdkproto.ApplyComplete { + t.Error("dry run should not apply") + return &sdkproto.ApplyComplete{} }, }), }) @@ -464,7 +456,7 @@ func TestProvisionerd(t *testing.T) { }), Type: &proto.AcquiredJob_WorkspaceBuild_{ WorkspaceBuild: &proto.AcquiredJob_WorkspaceBuild{ - Metadata: &sdkproto.Provision_Metadata{}, + Metadata: &sdkproto.Metadata{}, }, }, }, nil @@ -482,24 +474,20 @@ func TestProvisionerd(t *testing.T) { }), nil }, provisionerd.Provisioners{ "someprovisioner": createProvisionerClient(t, done, provisionerTestServer{ - provision: func(stream sdkproto.DRPCProvisioner_ProvisionStream) error { - err := stream.Send(&sdkproto.Provision_Response{ - Type: &sdkproto.Provision_Response_Log{ - Log: &sdkproto.Log{ - Level: sdkproto.LogLevel_DEBUG, - Output: "wow", - }, - }, - }) - require.NoError(t, err) - - err = stream.Send(&sdkproto.Provision_Response{ - Type: &sdkproto.Provision_Response_Complete{ - Complete: &sdkproto.Provision_Complete{}, - }, - }) - require.NoError(t, err) - return nil + plan: func( + s *provisionersdk.Session, + _ *sdkproto.PlanRequest, + cancelOrComplete <-chan struct{}, + ) *sdkproto.PlanComplete { + s.ProvisionLog(sdkproto.LogLevel_DEBUG, "wow") + return &sdkproto.PlanComplete{} + }, + apply: func( + _ *provisionersdk.Session, + _ *sdkproto.ApplyRequest, + _ <-chan struct{}, + ) *sdkproto.ApplyComplete { + return &sdkproto.ApplyComplete{} }, }), }) @@ -540,7 +528,7 @@ func TestProvisionerd(t *testing.T) { }), Type: &proto.AcquiredJob_WorkspaceBuild_{ WorkspaceBuild: &proto.AcquiredJob_WorkspaceBuild{ - Metadata: &sdkproto.Provision_Metadata{}, + Metadata: &sdkproto.Metadata{}, }, }, }, nil @@ -567,40 +555,46 @@ func TestProvisionerd(t *testing.T) { }), nil }, provisionerd.Provisioners{ "someprovisioner": createProvisionerClient(t, done, provisionerTestServer{ - provision: func(stream sdkproto.DRPCProvisioner_ProvisionStream) error { - err := stream.Send(&sdkproto.Provision_Response{ - Type: &sdkproto.Provision_Response_Log{ - Log: &sdkproto.Log{ - Level: sdkproto.LogLevel_DEBUG, - Output: "wow", + plan: func( + s *provisionersdk.Session, + _ *sdkproto.PlanRequest, + cancelOrComplete <-chan struct{}, + ) *sdkproto.PlanComplete { + s.ProvisionLog(sdkproto.LogLevel_DEBUG, "wow") + return &sdkproto.PlanComplete{ + Resources: []*sdkproto.Resource{ + { + DailyCost: 10, + }, + { + DailyCost: 15, }, }, - }) - require.NoError(t, err) - - err = stream.Send(&sdkproto.Provision_Response{ - Type: &sdkproto.Provision_Response_Complete{ - Complete: &sdkproto.Provision_Complete{ - Resources: []*sdkproto.Resource{ - { - DailyCost: 10, - }, - { - DailyCost: 15, - }, - }, + } + }, + apply: func( + _ *provisionersdk.Session, + _ *sdkproto.ApplyRequest, + _ <-chan struct{}, + ) *sdkproto.ApplyComplete { + t.Error("should not apply when resources exceed quota") + return &sdkproto.ApplyComplete{ + Resources: []*sdkproto.Resource{ + { + DailyCost: 10, + }, + { + DailyCost: 15, }, }, - }) - require.NoError(t, err) - return nil + } }, }), }) require.Condition(t, closedWithin(completeChan, testutil.WaitShort)) require.NoError(t, closer.Close()) assert.True(t, didLog.Load(), "should log some updates") - assert.False(t, didComplete.Load(), "should complete the job") + assert.False(t, didComplete.Load(), "should not complete the job") assert.True(t, didFail.Load(), "should fail the job") }) @@ -633,7 +627,7 @@ func TestProvisionerd(t *testing.T) { }), Type: &proto.AcquiredJob_WorkspaceBuild_{ WorkspaceBuild: &proto.AcquiredJob_WorkspaceBuild{ - Metadata: &sdkproto.Provision_Metadata{}, + Metadata: &sdkproto.Metadata{}, }, }, }, nil @@ -646,14 +640,24 @@ func TestProvisionerd(t *testing.T) { }), nil }, provisionerd.Provisioners{ "someprovisioner": createProvisionerClient(t, done, provisionerTestServer{ - provision: func(stream sdkproto.DRPCProvisioner_ProvisionStream) error { - return stream.Send(&sdkproto.Provision_Response{ - Type: &sdkproto.Provision_Response_Complete{ - Complete: &sdkproto.Provision_Complete{ - Error: "some error", - }, - }, - }) + plan: func( + s *provisionersdk.Session, + _ *sdkproto.PlanRequest, + cancelOrComplete <-chan struct{}, + ) *sdkproto.PlanComplete { + return &sdkproto.PlanComplete{ + Error: "some error", + } + }, + apply: func( + _ *provisionersdk.Session, + _ *sdkproto.ApplyRequest, + _ <-chan struct{}, + ) *sdkproto.ApplyComplete { + t.Error("should not apply when plan errors") + return &sdkproto.ApplyComplete{ + Error: "some error", + } }, }), }) @@ -683,7 +687,7 @@ func TestProvisionerd(t *testing.T) { }), Type: &proto.AcquiredJob_WorkspaceBuild_{ WorkspaceBuild: &proto.AcquiredJob_WorkspaceBuild{ - Metadata: &sdkproto.Provision_Metadata{}, + Metadata: &sdkproto.Metadata{}, }, }, }, nil @@ -712,31 +716,24 @@ func TestProvisionerd(t *testing.T) { }), nil }, provisionerd.Provisioners{ "someprovisioner": createProvisionerClient(t, done, provisionerTestServer{ - provision: func(stream sdkproto.DRPCProvisioner_ProvisionStream) error { - // Ignore the first provision message! - _, _ = stream.Recv() - - 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) - - msg, err := stream.Recv() - require.NoError(t, err) - require.NotNil(t, msg.GetCancel()) - - return stream.Send(&sdkproto.Provision_Response{ - Type: &sdkproto.Provision_Response_Complete{ - Complete: &sdkproto.Provision_Complete{ - Error: "some error", - }, - }, - }) + plan: func( + s *provisionersdk.Session, + _ *sdkproto.PlanRequest, + canceledOrComplete <-chan struct{}, + ) *sdkproto.PlanComplete { + s.ProvisionLog(sdkproto.LogLevel_DEBUG, "in progress") + <-canceledOrComplete + return &sdkproto.PlanComplete{ + Error: "some error", + } + }, + apply: func( + _ *provisionersdk.Session, + _ *sdkproto.ApplyRequest, + _ <-chan struct{}, + ) *sdkproto.ApplyComplete { + t.Error("should not apply when shut down during plan") + return &sdkproto.ApplyComplete{} }, }), }) @@ -768,7 +765,7 @@ func TestProvisionerd(t *testing.T) { }), Type: &proto.AcquiredJob_WorkspaceBuild_{ WorkspaceBuild: &proto.AcquiredJob_WorkspaceBuild{ - Metadata: &sdkproto.Provision_Metadata{}, + Metadata: &sdkproto.Metadata{}, }, }, }, nil @@ -805,31 +802,24 @@ func TestProvisionerd(t *testing.T) { }), nil }, provisionerd.Provisioners{ "someprovisioner": createProvisionerClient(t, done, provisionerTestServer{ - provision: func(stream sdkproto.DRPCProvisioner_ProvisionStream) error { - // Ignore the first provision message! - _, _ = stream.Recv() - - 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) - - msg, err := stream.Recv() - require.NoError(t, err) - require.NotNil(t, msg.GetCancel()) - - return stream.Send(&sdkproto.Provision_Response{ - Type: &sdkproto.Provision_Response_Complete{ - Complete: &sdkproto.Provision_Complete{ - Error: "some error", - }, - }, - }) + plan: func( + s *provisionersdk.Session, + _ *sdkproto.PlanRequest, + canceledOrComplete <-chan struct{}, + ) *sdkproto.PlanComplete { + s.ProvisionLog(sdkproto.LogLevel_DEBUG, "in progress") + <-canceledOrComplete + return &sdkproto.PlanComplete{ + Error: "some error", + } + }, + apply: func( + _ *provisionersdk.Session, + _ *sdkproto.ApplyRequest, + _ <-chan struct{}, + ) *sdkproto.ApplyComplete { + t.Error("should not apply when shut down during plan") + return &sdkproto.ApplyComplete{} }, }), }) @@ -867,7 +857,7 @@ func TestProvisionerd(t *testing.T) { }), Type: &proto.AcquiredJob_WorkspaceBuild_{ WorkspaceBuild: &proto.AcquiredJob_WorkspaceBuild{ - Metadata: &sdkproto.Provision_Metadata{}, + Metadata: &sdkproto.Metadata{}, }, }, }, nil @@ -898,16 +888,22 @@ func TestProvisionerd(t *testing.T) { return client, nil }, provisionerd.Provisioners{ "someprovisioner": createProvisionerClient(t, done, provisionerTestServer{ - provision: func(stream sdkproto.DRPCProvisioner_ProvisionStream) error { - // Ignore the first provision message! - _, _ = stream.Recv() - return stream.Send(&sdkproto.Provision_Response{ - Type: &sdkproto.Provision_Response_Complete{ - Complete: &sdkproto.Provision_Complete{ - Error: "some error", - }, - }, - }) + plan: func( + _ *provisionersdk.Session, + _ *sdkproto.PlanRequest, + _ <-chan struct{}, + ) *sdkproto.PlanComplete { + return &sdkproto.PlanComplete{ + Error: "some error", + } + }, + apply: func( + _ *provisionersdk.Session, + _ *sdkproto.ApplyRequest, + _ <-chan struct{}, + ) *sdkproto.ApplyComplete { + t.Error("should not apply when error during plan") + return &sdkproto.ApplyComplete{} }, }), }) @@ -945,7 +941,7 @@ func TestProvisionerd(t *testing.T) { }), Type: &proto.AcquiredJob_WorkspaceBuild_{ WorkspaceBuild: &proto.AcquiredJob_WorkspaceBuild{ - Metadata: &sdkproto.Provision_Metadata{}, + Metadata: &sdkproto.Metadata{}, }, }, }, nil @@ -977,14 +973,19 @@ func TestProvisionerd(t *testing.T) { return client, nil }, provisionerd.Provisioners{ "someprovisioner": createProvisionerClient(t, done, provisionerTestServer{ - provision: func(stream sdkproto.DRPCProvisioner_ProvisionStream) error { - // Ignore the first provision message! - _, _ = stream.Recv() - return stream.Send(&sdkproto.Provision_Response{ - Type: &sdkproto.Provision_Response_Complete{ - Complete: &sdkproto.Provision_Complete{}, - }, - }) + plan: func( + _ *provisionersdk.Session, + _ *sdkproto.PlanRequest, + _ <-chan struct{}, + ) *sdkproto.PlanComplete { + return &sdkproto.PlanComplete{} + }, + apply: func( + _ *provisionersdk.Session, + _ *sdkproto.ApplyRequest, + _ <-chan struct{}, + ) *sdkproto.ApplyComplete { + return &sdkproto.ApplyComplete{} }, }), }) @@ -1023,7 +1024,7 @@ func TestProvisionerd(t *testing.T) { }), Type: &proto.AcquiredJob_WorkspaceBuild_{ WorkspaceBuild: &proto.AcquiredJob_WorkspaceBuild{ - Metadata: &sdkproto.Provision_Metadata{}, + Metadata: &sdkproto.Metadata{}, }, }, }, nil @@ -1056,24 +1057,21 @@ func TestProvisionerd(t *testing.T) { }), nil }, provisionerd.Provisioners{ "someprovisioner": createProvisionerClient(t, done, provisionerTestServer{ - provision: func(stream sdkproto.DRPCProvisioner_ProvisionStream) error { - err := stream.Send(&sdkproto.Provision_Response{ - Type: &sdkproto.Provision_Response_Log{ - Log: &sdkproto.Log{ - Level: sdkproto.LogLevel_DEBUG, - Output: "wow", - }, - }, - }) - require.NoError(t, err) - - err = stream.Send(&sdkproto.Provision_Response{ - Type: &sdkproto.Provision_Response_Complete{ - Complete: &sdkproto.Provision_Complete{}, - }, - }) - require.NoError(t, err) - return nil + plan: func( + s *provisionersdk.Session, + _ *sdkproto.PlanRequest, + _ <-chan struct{}, + ) *sdkproto.PlanComplete { + s.ProvisionLog(sdkproto.LogLevel_DEBUG, "wow") + return &sdkproto.PlanComplete{} + }, + apply: func( + s *provisionersdk.Session, + _ *sdkproto.ApplyRequest, + _ <-chan struct{}, + ) *sdkproto.ApplyComplete { + s.ProvisionLog(sdkproto.LogLevel_DEBUG, "wow") + return &sdkproto.ApplyComplete{} }, }), }) @@ -1111,7 +1109,6 @@ func createProvisionerd(t *testing.T, dialer provisionerd.Dialer, provisioners p JobPollInterval: 50 * time.Millisecond, UpdateInterval: 50 * time.Millisecond, Provisioners: provisioners, - WorkDirectory: t.TempDir(), }) t.Cleanup(func() { _ = server.Close() @@ -1172,15 +1169,15 @@ func createProvisionerClient(t *testing.T, done <-chan struct{}, server provisio _ = clientPipe.Close() _ = serverPipe.Close() }) - mux := drpcmux.New() - err := sdkproto.DRPCRegisterProvisioner(mux, &server) - require.NoError(t, err) - srv := drpcserver.New(mux) ctx, cancelFunc := context.WithCancel(context.Background()) closed := make(chan struct{}) go func() { defer close(closed) - _ = srv.Serve(ctx, serverPipe) + _ = provisionersdk.Serve(ctx, &server, &provisionersdk.ServeOptions{ + Listener: serverPipe, + Logger: slogtest.Make(t, nil).Leveled(slog.LevelDebug).Named("test-provisioner"), + WorkDirectory: t.TempDir(), + }) }() t.Cleanup(func() { cancelFunc() @@ -1200,16 +1197,21 @@ func createProvisionerClient(t *testing.T, done <-chan struct{}, server provisio } type provisionerTestServer struct { - parse func(request *sdkproto.Parse_Request, stream sdkproto.DRPCProvisioner_ParseStream) error - provision func(stream sdkproto.DRPCProvisioner_ProvisionStream) error + parse func(s *provisionersdk.Session, r *sdkproto.ParseRequest, canceledOrComplete <-chan struct{}) *sdkproto.ParseComplete + plan func(s *provisionersdk.Session, r *sdkproto.PlanRequest, canceledOrComplete <-chan struct{}) *sdkproto.PlanComplete + apply func(s *provisionersdk.Session, r *sdkproto.ApplyRequest, canceledOrComplete <-chan struct{}) *sdkproto.ApplyComplete } -func (p *provisionerTestServer) Parse(request *sdkproto.Parse_Request, stream sdkproto.DRPCProvisioner_ParseStream) error { - return p.parse(request, stream) +func (p *provisionerTestServer) Parse(s *provisionersdk.Session, r *sdkproto.ParseRequest, canceledOrComplete <-chan struct{}) *sdkproto.ParseComplete { + return p.parse(s, r, canceledOrComplete) } -func (p *provisionerTestServer) Provision(stream sdkproto.DRPCProvisioner_ProvisionStream) error { - return p.provision(stream) +func (p *provisionerTestServer) Plan(s *provisionersdk.Session, r *sdkproto.PlanRequest, canceledOrComplete <-chan struct{}) *sdkproto.PlanComplete { + return p.plan(s, r, canceledOrComplete) +} + +func (p *provisionerTestServer) Apply(s *provisionersdk.Session, r *sdkproto.ApplyRequest, canceledOrComplete <-chan struct{}) *sdkproto.ApplyComplete { + return p.apply(s, r, canceledOrComplete) } // Fulfills the protobuf interface for a ProvisionerDaemon with diff --git a/provisionerd/runner/runner.go b/provisionerd/runner/runner.go index 5911004f98..7afa7a0999 100644 --- a/provisionerd/runner/runner.go +++ b/provisionerd/runner/runner.go @@ -1,15 +1,9 @@ package runner import ( - "archive/tar" - "bytes" "context" "errors" "fmt" - "io" - "os" - "path" - "path/filepath" "reflect" "strings" "sync" @@ -18,7 +12,6 @@ import ( "github.com/google/uuid" "github.com/prometheus/client_golang/prometheus" - "github.com/spf13/afero" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/codes" semconv "go.opentelemetry.io/otel/semconv/v1.14.0" @@ -54,14 +47,14 @@ type Runner struct { sender JobUpdater quotaCommitter QuotaCommitter logger slog.Logger - filesystem afero.Fs - workDirectory string provisioner sdkproto.DRPCProvisionerClient lastUpdate atomic.Pointer[time.Time] updateInterval time.Duration forceCancelInterval time.Duration logBufferInterval time.Duration + // session is the provisioning session with the (possibly remote) provisioner + session sdkproto.DRPCProvisioner_SessionClient // closed when the Runner is finished sending any updates/failed/complete. done chan struct{} // active as long as we are not canceled @@ -108,8 +101,6 @@ type Options struct { Updater JobUpdater QuotaCommitter QuotaCommitter Logger slog.Logger - Filesystem afero.Fs - WorkDirectory string Provisioner sdkproto.DRPCProvisionerClient UpdateInterval time.Duration ForceCancelInterval time.Duration @@ -149,8 +140,6 @@ func New( sender: opts.Updater, quotaCommitter: opts.QuotaCommitter, logger: logger, - filesystem: opts.Filesystem, - workDirectory: opts.WorkDirectory, provisioner: opts.Provisioner, updateInterval: opts.UpdateInterval, forceCancelInterval: opts.ForceCancelInterval, @@ -386,6 +375,14 @@ func (r *Runner) doCleanFinish(ctx context.Context) { r.setComplete(completedJob) }() + var err error + r.session, err = r.provisioner.Session(ctx) + if err != nil { + failedJob = r.failedJobf("open session: %s", err) + return + } + defer r.session.Close() + defer func() { ctx, span := r.startTrace(ctx, tracing.FuncName()) defer span.End() @@ -396,23 +393,6 @@ func (r *Runner) doCleanFinish(ctx context.Context) { Stage: "Cleaning Up", CreatedAt: time.Now().UnixMilli(), }) - - // Cleanup the work directory after execution. - for attempt := 0; attempt < 5; attempt++ { - err := r.filesystem.RemoveAll(r.workDirectory) - if err != nil { - // On Windows, open files cannot be removed. - // When the provisioner daemon is shutting down, - // it may take a few milliseconds for processes to exit. - // See: https://github.com/golang/go/issues/50510 - r.logger.Debug(ctx, "failed to clean work directory; trying again", slog.Error(err)) - time.Sleep(250 * time.Millisecond) - continue - } - r.logger.Debug(ctx, "cleaned up work directory") - break - } - r.flushQueuedLogs(ctx) }() @@ -424,85 +404,19 @@ func (r *Runner) do(ctx context.Context) (*proto.CompletedJob, *proto.FailedJob) ctx, span := r.startTrace(ctx, tracing.FuncName()) defer span.End() - err := r.filesystem.MkdirAll(r.workDirectory, 0o700) - if err != nil { - return nil, r.failedJobf("create work directory %q: %s", r.workDirectory, err) - } - r.queueLog(ctx, &proto.Log{ Source: proto.LogSource_PROVISIONER_DAEMON, Level: sdkproto.LogLevel_INFO, Stage: "Setting up", CreatedAt: time.Now().UnixMilli(), }) - if err != nil { - return nil, r.failedJobf("write log: %s", err) - } - r.logger.Info(ctx, "unpacking template source archive", - slog.F("size_bytes", len(r.job.TemplateSourceArchive)), - ) - - reader := tar.NewReader(bytes.NewBuffer(r.job.TemplateSourceArchive)) - for { - header, err := reader.Next() - if err != nil { - if errors.Is(err, io.EOF) { - break - } - return nil, r.failedJobf("read template source archive: %s", err) - } - // #nosec - headerPath := filepath.Join(r.workDirectory, header.Name) - if !strings.HasPrefix(headerPath, filepath.Clean(r.workDirectory)) { - return nil, r.failedJobf("tar attempts to target relative upper directory") - } - mode := header.FileInfo().Mode() - if mode == 0 { - mode = 0o600 - } - switch header.Typeflag { - case tar.TypeDir: - err = r.filesystem.MkdirAll(headerPath, mode) - if err != nil { - return nil, r.failedJobf("mkdir %q: %s", headerPath, err) - } - r.logger.Debug(context.Background(), "extracted directory", slog.F("path", headerPath)) - case tar.TypeReg: - file, err := r.filesystem.OpenFile(headerPath, os.O_CREATE|os.O_RDWR, mode) - if err != nil { - return nil, r.failedJobf("create file %q (mode %s): %s", headerPath, mode, err) - } - // Max file size of 10MiB. - size, err := io.CopyN(file, reader, 10<<20) - if errors.Is(err, io.EOF) { - err = nil - } - if err != nil { - _ = file.Close() - return nil, r.failedJobf("copy file %q: %s", headerPath, err) - } - err = file.Close() - if err != nil { - return nil, r.failedJobf("close file %q: %s", headerPath, err) - } - r.logger.Debug(context.Background(), "extracted file", - slog.F("size_bytes", size), - slog.F("path", headerPath), - slog.F("mode", mode), - ) - } - } switch jobType := r.job.Type.(type) { case *proto.AcquiredJob_TemplateImport_: r.logger.Debug(context.Background(), "acquired job is template import", slog.F("user_variable_values", redactVariableValues(jobType.TemplateImport.UserVariableValues)), ) - failedJob := r.runReadmeParse(ctx) - if failedJob != nil { - return nil, failedJob - } return r.runTemplateImport(ctx) case *proto.AcquiredJob_TemplateDryRun_: r.logger.Debug(context.Background(), "acquired job is template dry-run", @@ -525,6 +439,14 @@ func (r *Runner) do(ctx context.Context) (*proto.CompletedJob, *proto.FailedJob) } } +func (r *Runner) configure(config *sdkproto.Config) *proto.FailedJob { + err := r.session.Send(&sdkproto.Request{Type: &sdkproto.Request_Config{Config: config}}) + if err != nil { + return r.failedJobf("send config: %s", err) + } + return nil +} + // heartbeatRoutine periodically sends updates on the job, which keeps coder server // from assuming the job is stalled, and allows the runner to learn if the job // has been canceled by the user. @@ -577,45 +499,17 @@ func (r *Runner) heartbeatRoutine(ctx context.Context) { } } -// ReadmeFile is the location we look for to extract documentation from template -// versions. -const ReadmeFile = "README.md" - -func (r *Runner) runReadmeParse(ctx context.Context) *proto.FailedJob { - ctx, span := r.startTrace(ctx, tracing.FuncName()) - defer span.End() - - fi, err := afero.ReadFile(r.filesystem, path.Join(r.workDirectory, ReadmeFile)) - if err != nil { - r.queueLog(ctx, &proto.Log{ - Source: proto.LogSource_PROVISIONER_DAEMON, - Level: sdkproto.LogLevel_DEBUG, - Stage: "No README.md provided", - CreatedAt: time.Now().UnixMilli(), - }) - return nil - } - - _, err = r.update(ctx, &proto.UpdateJobRequest{ - JobId: r.job.JobId, - Logs: []*proto.Log{{ - Source: proto.LogSource_PROVISIONER_DAEMON, - Level: sdkproto.LogLevel_INFO, - Stage: "Adding README.md...", - CreatedAt: time.Now().UnixMilli(), - }}, - Readme: fi, - }) - if err != nil { - return r.failedJobf("write log: %s", err) - } - return nil -} - func (r *Runner) runTemplateImport(ctx context.Context) (*proto.CompletedJob, *proto.FailedJob) { ctx, span := r.startTrace(ctx, tracing.FuncName()) defer span.End() + failedJob := r.configure(&sdkproto.Config{ + TemplateSourceArchive: r.job.GetTemplateSourceArchive(), + }) + if failedJob != nil { + return nil, failedJob + } + // Parse parameters and update the job with the parameter specs r.queueLog(ctx, &proto.Log{ Source: proto.LogSource_PROVISIONER_DAEMON, @@ -623,7 +517,7 @@ func (r *Runner) runTemplateImport(ctx context.Context) (*proto.CompletedJob, *p Stage: "Parsing template parameters", CreatedAt: time.Now().UnixMilli(), }) - templateVariables, err := r.runTemplateImportParse(ctx) + templateVariables, readme, err := r.runTemplateImportParse(ctx) if err != nil { return nil, r.failedJobf("run parse: %s", err) } @@ -634,6 +528,7 @@ func (r *Runner) runTemplateImport(ctx context.Context) (*proto.CompletedJob, *p JobId: r.job.JobId, TemplateVariables: templateVariables, UserVariableValues: r.job.GetTemplateImport().GetUserVariableValues(), + Readme: readme, }) if err != nil { return nil, r.failedJobf("update job: %s", err) @@ -646,7 +541,7 @@ func (r *Runner) runTemplateImport(ctx context.Context) (*proto.CompletedJob, *p Stage: "Detecting persistent resources", CreatedAt: time.Now().UnixMilli(), }) - startProvision, err := r.runTemplateImportProvision(ctx, updateResponse.VariableValues, &sdkproto.Provision_Metadata{ + startProvision, err := r.runTemplateImportProvision(ctx, updateResponse.VariableValues, &sdkproto.Metadata{ CoderUrl: r.job.GetTemplateImport().Metadata.CoderUrl, WorkspaceTransition: sdkproto.WorkspaceTransition_START, }) @@ -661,7 +556,7 @@ func (r *Runner) runTemplateImport(ctx context.Context) (*proto.CompletedJob, *p Stage: "Detecting ephemeral resources", CreatedAt: time.Now().UnixMilli(), }) - stopProvision, err := r.runTemplateImportProvision(ctx, updateResponse.VariableValues, &sdkproto.Provision_Metadata{ + stopProvision, err := r.runTemplateImportProvision(ctx, updateResponse.VariableValues, &sdkproto.Metadata{ CoderUrl: r.job.GetTemplateImport().Metadata.CoderUrl, WorkspaceTransition: sdkproto.WorkspaceTransition_STOP, }) @@ -682,25 +577,24 @@ func (r *Runner) runTemplateImport(ctx context.Context) (*proto.CompletedJob, *p }, nil } -// Parses template variables and parameter schemas from source. -func (r *Runner) runTemplateImportParse(ctx context.Context) ([]*sdkproto.TemplateVariable, error) { +// Parses template variables and README from source. +func (r *Runner) runTemplateImportParse(ctx context.Context) ( + vars []*sdkproto.TemplateVariable, readme []byte, err error, +) { ctx, span := r.startTrace(ctx, tracing.FuncName()) defer span.End() - stream, err := r.provisioner.Parse(ctx, &sdkproto.Parse_Request{ - Directory: r.workDirectory, - }) + err = r.session.Send(&sdkproto.Request{Type: &sdkproto.Request_Parse{Parse: &sdkproto.ParseRequest{}}}) if err != nil { - return nil, xerrors.Errorf("parse source: %w", err) + return nil, nil, xerrors.Errorf("parse source: %w", err) } - defer stream.Close() for { - msg, err := stream.Recv() + msg, err := r.session.Recv() if err != nil { - return nil, xerrors.Errorf("recv parse source: %w", err) + return nil, nil, xerrors.Errorf("recv parse source: %w", err) } switch msgType := msg.Type.(type) { - case *sdkproto.Parse_Response_Log: + case *sdkproto.Response_Log: r.logger.Debug(context.Background(), "parse job logged", slog.F("level", msgType.Log.Level), slog.F("output", msgType.Log.Output), @@ -713,14 +607,20 @@ func (r *Runner) runTemplateImportParse(ctx context.Context) ([]*sdkproto.Templa Output: msgType.Log.Output, Stage: "Parse parameters", }) - case *sdkproto.Parse_Response_Complete: + case *sdkproto.Response_Parse: + pc := msgType.Parse r.logger.Debug(context.Background(), "parse complete", - slog.F("template_variables", msgType.Complete.TemplateVariables), + slog.F("template_variables", pc.TemplateVariables), + slog.F("readme_len", len(pc.Readme)), + slog.F("error", pc.Error), ) + if pc.Error != "" { + return nil, nil, xerrors.Errorf("parse error: %s", pc.Error) + } - return msgType.Complete.TemplateVariables, nil + return msgType.Parse.TemplateVariables, msgType.Parse.Readme, nil default: - return nil, xerrors.Errorf("invalid message type %q received from provisioner", + return nil, nil, xerrors.Errorf("invalid message type %q received from provisioner", reflect.TypeOf(msg.Type).String()) } } @@ -735,13 +635,18 @@ type templateImportProvision struct { // Performs a dry-run provision when importing a template. // This is used to detect resources that would be provisioned for a workspace in various states. // It doesn't define values for rich parameters as they're unknown during template import. -func (r *Runner) runTemplateImportProvision(ctx context.Context, variableValues []*sdkproto.VariableValue, metadata *sdkproto.Provision_Metadata) (*templateImportProvision, error) { +func (r *Runner) runTemplateImportProvision(ctx context.Context, variableValues []*sdkproto.VariableValue, metadata *sdkproto.Metadata) (*templateImportProvision, error) { return r.runTemplateImportProvisionWithRichParameters(ctx, variableValues, nil, metadata) } // Performs a dry-run provision with provided rich parameters. // This is used to detect resources that would be provisioned for a workspace in various states. -func (r *Runner) runTemplateImportProvisionWithRichParameters(ctx context.Context, variableValues []*sdkproto.VariableValue, richParameterValues []*sdkproto.RichParameterValue, metadata *sdkproto.Provision_Metadata) (*templateImportProvision, error) { +func (r *Runner) runTemplateImportProvisionWithRichParameters( + ctx context.Context, + variableValues []*sdkproto.VariableValue, + richParameterValues []*sdkproto.RichParameterValue, + metadata *sdkproto.Metadata, +) (*templateImportProvision, error) { ctx, span := r.startTrace(ctx, tracing.FuncName()) defer span.End() @@ -754,46 +659,38 @@ func (r *Runner) runTemplateImportProvisionWithRichParameters(ctx context.Contex } // use the notStopped so that if we attempt to gracefully cancel, the stream will still be available for us // to send the cancel to the provisioner - stream, err := r.provisioner.Provision(ctx) + err := r.session.Send(&sdkproto.Request{Type: &sdkproto.Request_Plan{Plan: &sdkproto.PlanRequest{ + Metadata: metadata, + RichParameterValues: richParameterValues, + VariableValues: variableValues, + }}}) if err != nil { - return nil, xerrors.Errorf("provision: %w", err) + return nil, xerrors.Errorf("start provision: %w", err) } - defer stream.Close() + nevermind := make(chan struct{}) + defer close(nevermind) go func() { select { + case <-nevermind: + return case <-r.notStopped.Done(): return case <-r.notCanceled.Done(): - _ = stream.Send(&sdkproto.Provision_Request{ - Type: &sdkproto.Provision_Request_Cancel{ - Cancel: &sdkproto.Provision_Cancel{}, + _ = r.session.Send(&sdkproto.Request{ + Type: &sdkproto.Request_Cancel{ + Cancel: &sdkproto.CancelRequest{}, }, }) } }() - err = stream.Send(&sdkproto.Provision_Request{ - Type: &sdkproto.Provision_Request_Plan{ - Plan: &sdkproto.Provision_Plan{ - Config: &sdkproto.Provision_Config{ - Directory: r.workDirectory, - Metadata: metadata, - }, - RichParameterValues: richParameterValues, - VariableValues: variableValues, - }, - }, - }) - if err != nil { - return nil, xerrors.Errorf("start provision: %w", err) - } for { - msg, err := stream.Recv() + msg, err := r.session.Recv() if err != nil { return nil, xerrors.Errorf("recv import provision: %w", err) } switch msgType := msg.Type.(type) { - case *sdkproto.Provision_Response_Log: + case *sdkproto.Response_Log: r.logger.Debug(context.Background(), "template import provision job logged", slog.F("level", msgType.Log.Level), slog.F("output", msgType.Log.Output), @@ -805,25 +702,25 @@ func (r *Runner) runTemplateImportProvisionWithRichParameters(ctx context.Contex Output: msgType.Log.Output, Stage: stage, }) - case *sdkproto.Provision_Response_Complete: - if msgType.Complete.Error != "" { + case *sdkproto.Response_Plan: + c := msgType.Plan + if c.Error != "" { r.logger.Info(context.Background(), "dry-run provision failure", - slog.F("error", msgType.Complete.Error), + slog.F("error", c.Error), ) - return nil, xerrors.New(msgType.Complete.Error) + return nil, xerrors.New(c.Error) } r.logger.Info(context.Background(), "parse dry-run provision successful", - slog.F("resource_count", len(msgType.Complete.Resources)), - slog.F("resources", msgType.Complete.Resources), - slog.F("state_length", len(msgType.Complete.State)), + slog.F("resource_count", len(c.Resources)), + slog.F("resources", c.Resources), ) return &templateImportProvision{ - Resources: msgType.Complete.Resources, - Parameters: msgType.Complete.Parameters, - GitAuthProviders: msgType.Complete.GitAuthProviders, + Resources: c.Resources, + Parameters: c.Parameters, + GitAuthProviders: c.GitAuthProviders, }, nil default: return nil, xerrors.Errorf("invalid message type %q received from provisioner", @@ -864,6 +761,13 @@ func (r *Runner) runTemplateDryRun(ctx context.Context) (*proto.CompletedJob, *p metadata.WorkspaceOwnerId = id.String() } + failedJob := r.configure(&sdkproto.Config{ + TemplateSourceArchive: r.job.GetTemplateSourceArchive(), + }) + if failedJob != nil { + return nil, failedJob + } + // Run the template import provision task since it's already a dry run. provision, err := r.runTemplateImportProvisionWithRichParameters(ctx, r.job.GetTemplateDryRun().GetVariableValues(), @@ -884,41 +788,39 @@ func (r *Runner) runTemplateDryRun(ctx context.Context) (*proto.CompletedJob, *p }, nil } -func (r *Runner) buildWorkspace(ctx context.Context, stage string, req *sdkproto.Provision_Request) ( - *sdkproto.Provision_Complete, *proto.FailedJob, +func (r *Runner) buildWorkspace(ctx context.Context, stage string, req *sdkproto.Request) ( + *sdkproto.Response, *proto.FailedJob, ) { // use the notStopped so that if we attempt to gracefully cancel, the stream // will still be available for us to send the cancel to the provisioner - stream, err := r.provisioner.Provision(ctx) + err := r.session.Send(req) if err != nil { - return nil, r.failedWorkspaceBuildf("provision: %s", err) + return nil, r.failedWorkspaceBuildf("start provision: %s", err) } - defer stream.Close() + nevermind := make(chan struct{}) + defer close(nevermind) go func() { select { + case <-nevermind: + return case <-r.notStopped.Done(): return case <-r.notCanceled.Done(): - _ = stream.Send(&sdkproto.Provision_Request{ - Type: &sdkproto.Provision_Request_Cancel{ - Cancel: &sdkproto.Provision_Cancel{}, + _ = r.session.Send(&sdkproto.Request{ + Type: &sdkproto.Request_Cancel{ + Cancel: &sdkproto.CancelRequest{}, }, }) } }() - err = stream.Send(req) - if err != nil { - return nil, r.failedWorkspaceBuildf("start provision: %s", err) - } - for { - msg, err := stream.Recv() + msg, err := r.session.Recv() if err != nil { return nil, r.failedWorkspaceBuildf("recv workspace provision: %s", err) } switch msgType := msg.Type.(type) { - case *sdkproto.Provision_Response_Log: + case *sdkproto.Response_Log: r.logProvisionerJobLog(context.Background(), msgType.Log.Level, "workspace provisioner job logged", slog.F("level", msgType.Log.Level), slog.F("output", msgType.Log.Output), @@ -932,33 +834,9 @@ func (r *Runner) buildWorkspace(ctx context.Context, stage string, req *sdkproto Output: msgType.Log.Output, Stage: stage, }) - case *sdkproto.Provision_Response_Complete: - if msgType.Complete.Error != "" { - r.logger.Warn(context.Background(), "provision failed; updating state", - slog.F("state_length", len(msgType.Complete.State)), - slog.F("error", msgType.Complete.Error), - ) - - return nil, &proto.FailedJob{ - JobId: r.job.JobId, - Error: msgType.Complete.Error, - Type: &proto.FailedJob_WorkspaceBuild_{ - WorkspaceBuild: &proto.FailedJob_WorkspaceBuild{ - State: msgType.Complete.State, - }, - }, - } - } - - r.logger.Info(context.Background(), "provision successful", - slog.F("resource_count", len(msgType.Complete.Resources)), - slog.F("resources", msgType.Complete.Resources), - slog.F("state_length", len(msgType.Complete.State)), - ) - // Stop looping! - return msgType.Complete, nil default: - return nil, r.failedWorkspaceBuildf("invalid message type %T received from provisioner", msg.Type) + // Stop looping! + return msg, nil } } } @@ -1035,18 +913,19 @@ func (r *Runner) runWorkspaceBuild(ctx context.Context) (*proto.CompletedJob, *p applyStage = "Destroying workspace" } - config := &sdkproto.Provision_Config{ - Directory: r.workDirectory, - Metadata: r.job.GetWorkspaceBuild().Metadata, - State: r.job.GetWorkspaceBuild().State, - - ProvisionerLogLevel: r.job.GetWorkspaceBuild().LogLevel, + failedJob := r.configure(&sdkproto.Config{ + TemplateSourceArchive: r.job.GetTemplateSourceArchive(), + State: r.job.GetWorkspaceBuild().State, + ProvisionerLogLevel: r.job.GetWorkspaceBuild().LogLevel, + }) + if failedJob != nil { + return nil, failedJob } - completedPlan, failed := r.buildWorkspace(ctx, "Planning infrastructure", &sdkproto.Provision_Request{ - Type: &sdkproto.Provision_Request_Plan{ - Plan: &sdkproto.Provision_Plan{ - Config: config, + resp, failed := r.buildWorkspace(ctx, "Planning infrastructure", &sdkproto.Request{ + Type: &sdkproto.Request_Plan{ + Plan: &sdkproto.PlanRequest{ + Metadata: r.job.GetWorkspaceBuild().Metadata, RichParameterValues: r.job.GetWorkspaceBuild().RichParameterValues, VariableValues: r.job.GetWorkspaceBuild().VariableValues, GitAuthProviders: r.job.GetWorkspaceBuild().GitAuthProviders, @@ -1056,9 +935,31 @@ func (r *Runner) runWorkspaceBuild(ctx context.Context) (*proto.CompletedJob, *p if failed != nil { return nil, failed } + planComplete := resp.GetPlan() + if planComplete == nil { + return nil, r.failedWorkspaceBuildf("invalid message type %T received from provisioner", resp.Type) + } + if planComplete.Error != "" { + r.logger.Warn(context.Background(), "plan request failed", + slog.F("error", planComplete.Error), + ) + + return nil, &proto.FailedJob{ + JobId: r.job.JobId, + Error: planComplete.Error, + Type: &proto.FailedJob_WorkspaceBuild_{ + WorkspaceBuild: &proto.FailedJob_WorkspaceBuild{}, + }, + } + } + + r.logger.Info(context.Background(), "plan request successful", + slog.F("resource_count", len(planComplete.Resources)), + slog.F("resources", planComplete.Resources), + ) r.flushQueuedLogs(ctx) if commitQuota { - failed = r.commitQuota(ctx, completedPlan.GetResources()) + failed = r.commitQuota(ctx, planComplete.Resources) r.flushQueuedLogs(ctx) if failed != nil { return nil, failed @@ -1072,25 +973,50 @@ func (r *Runner) runWorkspaceBuild(ctx context.Context) (*proto.CompletedJob, *p CreatedAt: time.Now().UnixMilli(), }) - completedApply, failed := r.buildWorkspace(ctx, applyStage, &sdkproto.Provision_Request{ - Type: &sdkproto.Provision_Request_Apply{ - Apply: &sdkproto.Provision_Apply{ - Config: config, - Plan: completedPlan.GetPlan(), + resp, failed = r.buildWorkspace(ctx, applyStage, &sdkproto.Request{ + Type: &sdkproto.Request_Apply{ + Apply: &sdkproto.ApplyRequest{ + Metadata: r.job.GetWorkspaceBuild().Metadata, }, }, }) if failed != nil { return nil, failed } + applyComplete := resp.GetApply() + if applyComplete == nil { + return nil, r.failedWorkspaceBuildf("invalid message type %T received from provisioner", resp.Type) + } + if applyComplete.Error != "" { + r.logger.Warn(context.Background(), "apply failed; updating state", + slog.F("error", applyComplete.Error), + slog.F("state_len", len(applyComplete.State)), + ) + + return nil, &proto.FailedJob{ + JobId: r.job.JobId, + Error: applyComplete.Error, + Type: &proto.FailedJob_WorkspaceBuild_{ + WorkspaceBuild: &proto.FailedJob_WorkspaceBuild{ + State: applyComplete.State, + }, + }, + } + } + + r.logger.Info(context.Background(), "apply successful", + slog.F("resource_count", len(applyComplete.Resources)), + slog.F("resources", applyComplete.Resources), + slog.F("state_len", len(applyComplete.State)), + ) r.flushQueuedLogs(ctx) return &proto.CompletedJob{ JobId: r.job.JobId, Type: &proto.CompletedJob_WorkspaceBuild_{ WorkspaceBuild: &proto.CompletedJob_WorkspaceBuild{ - State: completedApply.GetState(), - Resources: completedApply.GetResources(), + State: applyComplete.State, + Resources: applyComplete.Resources, }, }, }, nil diff --git a/provisionersdk/errors.go b/provisionersdk/errors.go new file mode 100644 index 0000000000..0dc66e6e6b --- /dev/null +++ b/provisionersdk/errors.go @@ -0,0 +1,19 @@ +package provisionersdk + +import ( + "fmt" + + "github.com/coder/coder/v2/provisionersdk/proto" +) + +func ParseErrorf(format string, args ...any) *proto.ParseComplete { + return &proto.ParseComplete{Error: fmt.Sprintf(format, args...)} +} + +func PlanErrorf(format string, args ...any) *proto.PlanComplete { + return &proto.PlanComplete{Error: fmt.Sprintf(format, args...)} +} + +func ApplyErrorf(format string, args ...any) *proto.ApplyComplete { + return &proto.ApplyComplete{Error: fmt.Sprintf(format, args...)} +} diff --git a/provisionersdk/proto/provisioner.pb.go b/provisionersdk/proto/provisioner.pb.go index f39e9731e6..c0ea0be327 100644 --- a/provisionersdk/proto/provisioner.pb.go +++ b/provisionersdk/proto/provisioner.pb.go @@ -125,6 +125,7 @@ func (AppSharingLevel) EnumDescriptor() ([]byte, []int) { return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{1} } +// WorkspaceTransition is the desired outcome of a build type WorkspaceTransition int32 const ( @@ -1313,15 +1314,27 @@ func (x *Resource) GetDailyCost() int32 { return 0 } -// Parse consumes source-code from a directory to produce inputs. -type Parse struct { +// Metadata is information about a workspace used in the execution of a build +type 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"` + WorkspaceName string `protobuf:"bytes,3,opt,name=workspace_name,json=workspaceName,proto3" json:"workspace_name,omitempty"` + WorkspaceOwner string `protobuf:"bytes,4,opt,name=workspace_owner,json=workspaceOwner,proto3" json:"workspace_owner,omitempty"` + WorkspaceId string `protobuf:"bytes,5,opt,name=workspace_id,json=workspaceId,proto3" json:"workspace_id,omitempty"` + WorkspaceOwnerId string `protobuf:"bytes,6,opt,name=workspace_owner_id,json=workspaceOwnerId,proto3" json:"workspace_owner_id,omitempty"` + WorkspaceOwnerEmail string `protobuf:"bytes,7,opt,name=workspace_owner_email,json=workspaceOwnerEmail,proto3" json:"workspace_owner_email,omitempty"` + TemplateName string `protobuf:"bytes,8,opt,name=template_name,json=templateName,proto3" json:"template_name,omitempty"` + TemplateVersion string `protobuf:"bytes,9,opt,name=template_version,json=templateVersion,proto3" json:"template_version,omitempty"` + WorkspaceOwnerOidcAccessToken string `protobuf:"bytes,10,opt,name=workspace_owner_oidc_access_token,json=workspaceOwnerOidcAccessToken,proto3" json:"workspace_owner_oidc_access_token,omitempty"` + WorkspaceOwnerSessionToken string `protobuf:"bytes,11,opt,name=workspace_owner_session_token,json=workspaceOwnerSessionToken,proto3" json:"workspace_owner_session_token,omitempty"` } -func (x *Parse) Reset() { - *x = Parse{} +func (x *Metadata) Reset() { + *x = Metadata{} if protoimpl.UnsafeEnabled { mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1329,13 +1342,13 @@ func (x *Parse) Reset() { } } -func (x *Parse) String() string { +func (x *Metadata) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Parse) ProtoMessage() {} +func (*Metadata) ProtoMessage() {} -func (x *Parse) ProtoReflect() protoreflect.Message { +func (x *Metadata) ProtoReflect() protoreflect.Message { mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1347,21 +1360,103 @@ func (x *Parse) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Parse.ProtoReflect.Descriptor instead. -func (*Parse) Descriptor() ([]byte, []int) { +// Deprecated: Use Metadata.ProtoReflect.Descriptor instead. +func (*Metadata) Descriptor() ([]byte, []int) { return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{13} } -// Provision consumes source-code from a directory to produce resources. -// Exactly one of Plan or Apply must be provided in a single session. -type Provision struct { +func (x *Metadata) GetCoderUrl() string { + if x != nil { + return x.CoderUrl + } + return "" +} + +func (x *Metadata) GetWorkspaceTransition() WorkspaceTransition { + if x != nil { + return x.WorkspaceTransition + } + return WorkspaceTransition_START +} + +func (x *Metadata) GetWorkspaceName() string { + if x != nil { + return x.WorkspaceName + } + return "" +} + +func (x *Metadata) GetWorkspaceOwner() string { + if x != nil { + return x.WorkspaceOwner + } + return "" +} + +func (x *Metadata) GetWorkspaceId() string { + if x != nil { + return x.WorkspaceId + } + return "" +} + +func (x *Metadata) GetWorkspaceOwnerId() string { + if x != nil { + return x.WorkspaceOwnerId + } + return "" +} + +func (x *Metadata) GetWorkspaceOwnerEmail() string { + if x != nil { + return x.WorkspaceOwnerEmail + } + return "" +} + +func (x *Metadata) GetTemplateName() string { + if x != nil { + return x.TemplateName + } + return "" +} + +func (x *Metadata) GetTemplateVersion() string { + if x != nil { + return x.TemplateVersion + } + return "" +} + +func (x *Metadata) GetWorkspaceOwnerOidcAccessToken() string { + if x != nil { + return x.WorkspaceOwnerOidcAccessToken + } + return "" +} + +func (x *Metadata) GetWorkspaceOwnerSessionToken() string { + if x != nil { + return x.WorkspaceOwnerSessionToken + } + return "" +} + +// Config represents execution configuration shared by all subsequent requests in the Session +type Config struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields + + // template_source_archive is a tar of the template source files + TemplateSourceArchive []byte `protobuf:"bytes,1,opt,name=template_source_archive,json=templateSourceArchive,proto3" json:"template_source_archive,omitempty"` + // state is the provisioner state (if any) + State []byte `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"` + ProvisionerLogLevel string `protobuf:"bytes,3,opt,name=provisioner_log_level,json=provisionerLogLevel,proto3" json:"provisioner_log_level,omitempty"` } -func (x *Provision) Reset() { - *x = Provision{} +func (x *Config) Reset() { + *x = Config{} if protoimpl.UnsafeEnabled { mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1369,13 +1464,13 @@ func (x *Provision) Reset() { } } -func (x *Provision) String() string { +func (x *Config) String() string { return protoimpl.X.MessageStringOf(x) } -func (*Provision) ProtoMessage() {} +func (*Config) ProtoMessage() {} -func (x *Provision) ProtoReflect() protoreflect.Message { +func (x *Config) ProtoReflect() protoreflect.Message { mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) @@ -1387,11 +1482,679 @@ func (x *Provision) ProtoReflect() protoreflect.Message { return mi.MessageOf(x) } -// Deprecated: Use Provision.ProtoReflect.Descriptor instead. -func (*Provision) Descriptor() ([]byte, []int) { +// Deprecated: Use Config.ProtoReflect.Descriptor instead. +func (*Config) Descriptor() ([]byte, []int) { return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{14} } +func (x *Config) GetTemplateSourceArchive() []byte { + if x != nil { + return x.TemplateSourceArchive + } + return nil +} + +func (x *Config) GetState() []byte { + if x != nil { + return x.State + } + return nil +} + +func (x *Config) GetProvisionerLogLevel() string { + if x != nil { + return x.ProvisionerLogLevel + } + return "" +} + +// ParseRequest consumes source-code to produce inputs. +type ParseRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *ParseRequest) Reset() { + *x = ParseRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[15] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ParseRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ParseRequest) ProtoMessage() {} + +func (x *ParseRequest) ProtoReflect() protoreflect.Message { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[15] + 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 ParseRequest.ProtoReflect.Descriptor instead. +func (*ParseRequest) Descriptor() ([]byte, []int) { + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{15} +} + +// ParseComplete indicates a request to parse completed. +type ParseComplete struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` + TemplateVariables []*TemplateVariable `protobuf:"bytes,2,rep,name=template_variables,json=templateVariables,proto3" json:"template_variables,omitempty"` + Readme []byte `protobuf:"bytes,3,opt,name=readme,proto3" json:"readme,omitempty"` +} + +func (x *ParseComplete) Reset() { + *x = ParseComplete{} + if protoimpl.UnsafeEnabled { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[16] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ParseComplete) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ParseComplete) ProtoMessage() {} + +func (x *ParseComplete) ProtoReflect() protoreflect.Message { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[16] + 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 ParseComplete.ProtoReflect.Descriptor instead. +func (*ParseComplete) Descriptor() ([]byte, []int) { + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{16} +} + +func (x *ParseComplete) GetError() string { + if x != nil { + return x.Error + } + return "" +} + +func (x *ParseComplete) GetTemplateVariables() []*TemplateVariable { + if x != nil { + return x.TemplateVariables + } + return nil +} + +func (x *ParseComplete) GetReadme() []byte { + if x != nil { + return x.Readme + } + return nil +} + +// PlanRequest asks the provisioner to plan what resources & parameters it will create +type PlanRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` + RichParameterValues []*RichParameterValue `protobuf:"bytes,2,rep,name=rich_parameter_values,json=richParameterValues,proto3" json:"rich_parameter_values,omitempty"` + VariableValues []*VariableValue `protobuf:"bytes,3,rep,name=variable_values,json=variableValues,proto3" json:"variable_values,omitempty"` + GitAuthProviders []*GitAuthProvider `protobuf:"bytes,4,rep,name=git_auth_providers,json=gitAuthProviders,proto3" json:"git_auth_providers,omitempty"` +} + +func (x *PlanRequest) Reset() { + *x = PlanRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[17] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PlanRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PlanRequest) ProtoMessage() {} + +func (x *PlanRequest) ProtoReflect() protoreflect.Message { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[17] + 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 PlanRequest.ProtoReflect.Descriptor instead. +func (*PlanRequest) Descriptor() ([]byte, []int) { + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{17} +} + +func (x *PlanRequest) GetMetadata() *Metadata { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *PlanRequest) GetRichParameterValues() []*RichParameterValue { + if x != nil { + return x.RichParameterValues + } + return nil +} + +func (x *PlanRequest) GetVariableValues() []*VariableValue { + if x != nil { + return x.VariableValues + } + return nil +} + +func (x *PlanRequest) GetGitAuthProviders() []*GitAuthProvider { + if x != nil { + return x.GitAuthProviders + } + return nil +} + +// PlanComplete indicates a request to plan completed. +type PlanComplete struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Error string `protobuf:"bytes,1,opt,name=error,proto3" json:"error,omitempty"` + Resources []*Resource `protobuf:"bytes,2,rep,name=resources,proto3" json:"resources,omitempty"` + Parameters []*RichParameter `protobuf:"bytes,3,rep,name=parameters,proto3" json:"parameters,omitempty"` + GitAuthProviders []string `protobuf:"bytes,4,rep,name=git_auth_providers,json=gitAuthProviders,proto3" json:"git_auth_providers,omitempty"` +} + +func (x *PlanComplete) Reset() { + *x = PlanComplete{} + if protoimpl.UnsafeEnabled { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[18] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *PlanComplete) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*PlanComplete) ProtoMessage() {} + +func (x *PlanComplete) ProtoReflect() protoreflect.Message { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[18] + 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 PlanComplete.ProtoReflect.Descriptor instead. +func (*PlanComplete) Descriptor() ([]byte, []int) { + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{18} +} + +func (x *PlanComplete) GetError() string { + if x != nil { + return x.Error + } + return "" +} + +func (x *PlanComplete) GetResources() []*Resource { + if x != nil { + return x.Resources + } + return nil +} + +func (x *PlanComplete) GetParameters() []*RichParameter { + if x != nil { + return x.Parameters + } + return nil +} + +func (x *PlanComplete) GetGitAuthProviders() []string { + if x != nil { + return x.GitAuthProviders + } + return nil +} + +// ApplyRequest asks the provisioner to apply the changes. Apply MUST be preceded by a successful plan request/response +// in the same Session. The plan data is not transmitted over the wire and is cached by the provisioner in the Session. +type ApplyRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Metadata *Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"` +} + +func (x *ApplyRequest) Reset() { + *x = ApplyRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[19] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ApplyRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplyRequest) ProtoMessage() {} + +func (x *ApplyRequest) ProtoReflect() protoreflect.Message { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[19] + 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 ApplyRequest.ProtoReflect.Descriptor instead. +func (*ApplyRequest) Descriptor() ([]byte, []int) { + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{19} +} + +func (x *ApplyRequest) GetMetadata() *Metadata { + if x != nil { + return x.Metadata + } + return nil +} + +// ApplyComplete indicates a request to apply completed. +type ApplyComplete struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + State []byte `protobuf:"bytes,1,opt,name=state,proto3" json:"state,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"` + Parameters []*RichParameter `protobuf:"bytes,4,rep,name=parameters,proto3" json:"parameters,omitempty"` + GitAuthProviders []string `protobuf:"bytes,5,rep,name=git_auth_providers,json=gitAuthProviders,proto3" json:"git_auth_providers,omitempty"` +} + +func (x *ApplyComplete) Reset() { + *x = ApplyComplete{} + if protoimpl.UnsafeEnabled { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[20] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ApplyComplete) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ApplyComplete) ProtoMessage() {} + +func (x *ApplyComplete) ProtoReflect() protoreflect.Message { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[20] + 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 ApplyComplete.ProtoReflect.Descriptor instead. +func (*ApplyComplete) Descriptor() ([]byte, []int) { + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{20} +} + +func (x *ApplyComplete) GetState() []byte { + if x != nil { + return x.State + } + return nil +} + +func (x *ApplyComplete) GetError() string { + if x != nil { + return x.Error + } + return "" +} + +func (x *ApplyComplete) GetResources() []*Resource { + if x != nil { + return x.Resources + } + return nil +} + +func (x *ApplyComplete) GetParameters() []*RichParameter { + if x != nil { + return x.Parameters + } + return nil +} + +func (x *ApplyComplete) GetGitAuthProviders() []string { + if x != nil { + return x.GitAuthProviders + } + return nil +} + +// CancelRequest requests that the previous request be canceled gracefully. +type CancelRequest struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields +} + +func (x *CancelRequest) Reset() { + *x = CancelRequest{} + if protoimpl.UnsafeEnabled { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[21] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *CancelRequest) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*CancelRequest) ProtoMessage() {} + +func (x *CancelRequest) ProtoReflect() protoreflect.Message { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[21] + 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 CancelRequest.ProtoReflect.Descriptor instead. +func (*CancelRequest) Descriptor() ([]byte, []int) { + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{21} +} + +type Request struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Type: + // + // *Request_Config + // *Request_Parse + // *Request_Plan + // *Request_Apply + // *Request_Cancel + Type isRequest_Type `protobuf_oneof:"type"` +} + +func (x *Request) Reset() { + *x = Request{} + if protoimpl.UnsafeEnabled { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[22] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Request) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Request) ProtoMessage() {} + +func (x *Request) ProtoReflect() protoreflect.Message { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[22] + 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 Request.ProtoReflect.Descriptor instead. +func (*Request) Descriptor() ([]byte, []int) { + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{22} +} + +func (m *Request) GetType() isRequest_Type { + if m != nil { + return m.Type + } + return nil +} + +func (x *Request) GetConfig() *Config { + if x, ok := x.GetType().(*Request_Config); ok { + return x.Config + } + return nil +} + +func (x *Request) GetParse() *ParseRequest { + if x, ok := x.GetType().(*Request_Parse); ok { + return x.Parse + } + return nil +} + +func (x *Request) GetPlan() *PlanRequest { + if x, ok := x.GetType().(*Request_Plan); ok { + return x.Plan + } + return nil +} + +func (x *Request) GetApply() *ApplyRequest { + if x, ok := x.GetType().(*Request_Apply); ok { + return x.Apply + } + return nil +} + +func (x *Request) GetCancel() *CancelRequest { + if x, ok := x.GetType().(*Request_Cancel); ok { + return x.Cancel + } + return nil +} + +type isRequest_Type interface { + isRequest_Type() +} + +type Request_Config struct { + Config *Config `protobuf:"bytes,1,opt,name=config,proto3,oneof"` +} + +type Request_Parse struct { + Parse *ParseRequest `protobuf:"bytes,2,opt,name=parse,proto3,oneof"` +} + +type Request_Plan struct { + Plan *PlanRequest `protobuf:"bytes,3,opt,name=plan,proto3,oneof"` +} + +type Request_Apply struct { + Apply *ApplyRequest `protobuf:"bytes,4,opt,name=apply,proto3,oneof"` +} + +type Request_Cancel struct { + Cancel *CancelRequest `protobuf:"bytes,5,opt,name=cancel,proto3,oneof"` +} + +func (*Request_Config) isRequest_Type() {} + +func (*Request_Parse) isRequest_Type() {} + +func (*Request_Plan) isRequest_Type() {} + +func (*Request_Apply) isRequest_Type() {} + +func (*Request_Cancel) isRequest_Type() {} + +type Response struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + // Types that are assignable to Type: + // + // *Response_Log + // *Response_Parse + // *Response_Plan + // *Response_Apply + Type isResponse_Type `protobuf_oneof:"type"` +} + +func (x *Response) Reset() { + *x = Response{} + if protoimpl.UnsafeEnabled { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[23] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Response) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Response) ProtoMessage() {} + +func (x *Response) ProtoReflect() protoreflect.Message { + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[23] + 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 Response.ProtoReflect.Descriptor instead. +func (*Response) Descriptor() ([]byte, []int) { + return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{23} +} + +func (m *Response) GetType() isResponse_Type { + if m != nil { + return m.Type + } + return nil +} + +func (x *Response) GetLog() *Log { + if x, ok := x.GetType().(*Response_Log); ok { + return x.Log + } + return nil +} + +func (x *Response) GetParse() *ParseComplete { + if x, ok := x.GetType().(*Response_Parse); ok { + return x.Parse + } + return nil +} + +func (x *Response) GetPlan() *PlanComplete { + if x, ok := x.GetType().(*Response_Plan); ok { + return x.Plan + } + return nil +} + +func (x *Response) GetApply() *ApplyComplete { + if x, ok := x.GetType().(*Response_Apply); ok { + return x.Apply + } + return nil +} + +type isResponse_Type interface { + isResponse_Type() +} + +type Response_Log struct { + Log *Log `protobuf:"bytes,1,opt,name=log,proto3,oneof"` +} + +type Response_Parse struct { + Parse *ParseComplete `protobuf:"bytes,2,opt,name=parse,proto3,oneof"` +} + +type Response_Plan struct { + Plan *PlanComplete `protobuf:"bytes,3,opt,name=plan,proto3,oneof"` +} + +type Response_Apply struct { + Apply *ApplyComplete `protobuf:"bytes,4,opt,name=apply,proto3,oneof"` +} + +func (*Response_Log) isResponse_Type() {} + +func (*Response_Parse) isResponse_Type() {} + +func (*Response_Plan) isResponse_Type() {} + +func (*Response_Apply) isResponse_Type() {} + type Agent_Metadata struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -1407,7 +2170,7 @@ type Agent_Metadata struct { func (x *Agent_Metadata) Reset() { *x = Agent_Metadata{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[15] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[24] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1420,7 +2183,7 @@ func (x *Agent_Metadata) String() string { func (*Agent_Metadata) ProtoMessage() {} func (x *Agent_Metadata) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[15] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[24] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1485,7 +2248,7 @@ type Resource_Metadata struct { func (x *Resource_Metadata) Reset() { *x = Resource_Metadata{} if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[17] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[26] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1498,7 +2261,7 @@ func (x *Resource_Metadata) String() string { func (*Resource_Metadata) ProtoMessage() {} func (x *Resource_Metadata) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[17] + mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[26] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1542,808 +2305,6 @@ func (x *Resource_Metadata) GetIsNull() bool { return false } -type Parse_Request struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Directory string `protobuf:"bytes,1,opt,name=directory,proto3" json:"directory,omitempty"` -} - -func (x *Parse_Request) Reset() { - *x = Parse_Request{} - if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[18] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Parse_Request) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Parse_Request) ProtoMessage() {} - -func (x *Parse_Request) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[18] - 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 Parse_Request.ProtoReflect.Descriptor instead. -func (*Parse_Request) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{13, 0} -} - -func (x *Parse_Request) GetDirectory() string { - if x != nil { - return x.Directory - } - return "" -} - -type Parse_Complete struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - TemplateVariables []*TemplateVariable `protobuf:"bytes,1,rep,name=template_variables,json=templateVariables,proto3" json:"template_variables,omitempty"` -} - -func (x *Parse_Complete) Reset() { - *x = Parse_Complete{} - if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[19] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Parse_Complete) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Parse_Complete) ProtoMessage() {} - -func (x *Parse_Complete) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[19] - 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 Parse_Complete.ProtoReflect.Descriptor instead. -func (*Parse_Complete) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{13, 1} -} - -func (x *Parse_Complete) GetTemplateVariables() []*TemplateVariable { - if x != nil { - return x.TemplateVariables - } - return nil -} - -type Parse_Response struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Type: - // - // *Parse_Response_Log - // *Parse_Response_Complete - Type isParse_Response_Type `protobuf_oneof:"type"` -} - -func (x *Parse_Response) Reset() { - *x = Parse_Response{} - if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[20] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Parse_Response) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Parse_Response) ProtoMessage() {} - -func (x *Parse_Response) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[20] - 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 Parse_Response.ProtoReflect.Descriptor instead. -func (*Parse_Response) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{13, 2} -} - -func (m *Parse_Response) GetType() isParse_Response_Type { - if m != nil { - return m.Type - } - return nil -} - -func (x *Parse_Response) GetLog() *Log { - if x, ok := x.GetType().(*Parse_Response_Log); ok { - return x.Log - } - return nil -} - -func (x *Parse_Response) GetComplete() *Parse_Complete { - if x, ok := x.GetType().(*Parse_Response_Complete); ok { - return x.Complete - } - return nil -} - -type isParse_Response_Type interface { - isParse_Response_Type() -} - -type Parse_Response_Log struct { - Log *Log `protobuf:"bytes,1,opt,name=log,proto3,oneof"` -} - -type Parse_Response_Complete struct { - Complete *Parse_Complete `protobuf:"bytes,2,opt,name=complete,proto3,oneof"` -} - -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"` - WorkspaceName string `protobuf:"bytes,3,opt,name=workspace_name,json=workspaceName,proto3" json:"workspace_name,omitempty"` - WorkspaceOwner string `protobuf:"bytes,4,opt,name=workspace_owner,json=workspaceOwner,proto3" json:"workspace_owner,omitempty"` - WorkspaceId string `protobuf:"bytes,5,opt,name=workspace_id,json=workspaceId,proto3" json:"workspace_id,omitempty"` - WorkspaceOwnerId string `protobuf:"bytes,6,opt,name=workspace_owner_id,json=workspaceOwnerId,proto3" json:"workspace_owner_id,omitempty"` - WorkspaceOwnerEmail string `protobuf:"bytes,7,opt,name=workspace_owner_email,json=workspaceOwnerEmail,proto3" json:"workspace_owner_email,omitempty"` - TemplateName string `protobuf:"bytes,8,opt,name=template_name,json=templateName,proto3" json:"template_name,omitempty"` - TemplateVersion string `protobuf:"bytes,9,opt,name=template_version,json=templateVersion,proto3" json:"template_version,omitempty"` - WorkspaceOwnerOidcAccessToken string `protobuf:"bytes,10,opt,name=workspace_owner_oidc_access_token,json=workspaceOwnerOidcAccessToken,proto3" json:"workspace_owner_oidc_access_token,omitempty"` - WorkspaceOwnerSessionToken string `protobuf:"bytes,11,opt,name=workspace_owner_session_token,json=workspaceOwnerSessionToken,proto3" json:"workspace_owner_session_token,omitempty"` -} - -func (x *Provision_Metadata) Reset() { - *x = Provision_Metadata{} - if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[21] - 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[21] - 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{14, 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 -} - -func (x *Provision_Metadata) GetWorkspaceName() string { - if x != nil { - return x.WorkspaceName - } - return "" -} - -func (x *Provision_Metadata) GetWorkspaceOwner() string { - if x != nil { - return x.WorkspaceOwner - } - return "" -} - -func (x *Provision_Metadata) GetWorkspaceId() string { - if x != nil { - return x.WorkspaceId - } - return "" -} - -func (x *Provision_Metadata) GetWorkspaceOwnerId() string { - if x != nil { - return x.WorkspaceOwnerId - } - return "" -} - -func (x *Provision_Metadata) GetWorkspaceOwnerEmail() string { - if x != nil { - return x.WorkspaceOwnerEmail - } - return "" -} - -func (x *Provision_Metadata) GetTemplateName() string { - if x != nil { - return x.TemplateName - } - return "" -} - -func (x *Provision_Metadata) GetTemplateVersion() string { - if x != nil { - return x.TemplateVersion - } - return "" -} - -func (x *Provision_Metadata) GetWorkspaceOwnerOidcAccessToken() string { - if x != nil { - return x.WorkspaceOwnerOidcAccessToken - } - return "" -} - -func (x *Provision_Metadata) GetWorkspaceOwnerSessionToken() string { - if x != nil { - return x.WorkspaceOwnerSessionToken - } - return "" -} - -// Config represents execution configuration shared by both Plan and -// Apply commands. -type Provision_Config struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Directory string `protobuf:"bytes,1,opt,name=directory,proto3" json:"directory,omitempty"` - State []byte `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"` - Metadata *Provision_Metadata `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"` - ProvisionerLogLevel string `protobuf:"bytes,4,opt,name=provisioner_log_level,json=provisionerLogLevel,proto3" json:"provisioner_log_level,omitempty"` -} - -func (x *Provision_Config) Reset() { - *x = Provision_Config{} - if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[22] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Provision_Config) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Provision_Config) ProtoMessage() {} - -func (x *Provision_Config) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[22] - 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_Config.ProtoReflect.Descriptor instead. -func (*Provision_Config) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{14, 1} -} - -func (x *Provision_Config) GetDirectory() string { - if x != nil { - return x.Directory - } - return "" -} - -func (x *Provision_Config) GetState() []byte { - if x != nil { - return x.State - } - return nil -} - -func (x *Provision_Config) GetMetadata() *Provision_Metadata { - if x != nil { - return x.Metadata - } - return nil -} - -func (x *Provision_Config) GetProvisionerLogLevel() string { - if x != nil { - return x.ProvisionerLogLevel - } - return "" -} - -type Provision_Plan struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Config *Provision_Config `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` - RichParameterValues []*RichParameterValue `protobuf:"bytes,3,rep,name=rich_parameter_values,json=richParameterValues,proto3" json:"rich_parameter_values,omitempty"` - VariableValues []*VariableValue `protobuf:"bytes,4,rep,name=variable_values,json=variableValues,proto3" json:"variable_values,omitempty"` - GitAuthProviders []*GitAuthProvider `protobuf:"bytes,5,rep,name=git_auth_providers,json=gitAuthProviders,proto3" json:"git_auth_providers,omitempty"` -} - -func (x *Provision_Plan) Reset() { - *x = Provision_Plan{} - if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[23] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Provision_Plan) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Provision_Plan) ProtoMessage() {} - -func (x *Provision_Plan) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[23] - 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_Plan.ProtoReflect.Descriptor instead. -func (*Provision_Plan) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{14, 2} -} - -func (x *Provision_Plan) GetConfig() *Provision_Config { - if x != nil { - return x.Config - } - return nil -} - -func (x *Provision_Plan) GetRichParameterValues() []*RichParameterValue { - if x != nil { - return x.RichParameterValues - } - return nil -} - -func (x *Provision_Plan) GetVariableValues() []*VariableValue { - if x != nil { - return x.VariableValues - } - return nil -} - -func (x *Provision_Plan) GetGitAuthProviders() []*GitAuthProvider { - if x != nil { - return x.GitAuthProviders - } - return nil -} - -type Provision_Apply struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Config *Provision_Config `protobuf:"bytes,1,opt,name=config,proto3" json:"config,omitempty"` - Plan []byte `protobuf:"bytes,2,opt,name=plan,proto3" json:"plan,omitempty"` -} - -func (x *Provision_Apply) Reset() { - *x = Provision_Apply{} - if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[24] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Provision_Apply) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Provision_Apply) ProtoMessage() {} - -func (x *Provision_Apply) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[24] - 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_Apply.ProtoReflect.Descriptor instead. -func (*Provision_Apply) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{14, 3} -} - -func (x *Provision_Apply) GetConfig() *Provision_Config { - if x != nil { - return x.Config - } - return nil -} - -func (x *Provision_Apply) GetPlan() []byte { - if x != nil { - return x.Plan - } - return nil -} - -type Provision_Cancel struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields -} - -func (x *Provision_Cancel) Reset() { - *x = Provision_Cancel{} - if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[25] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Provision_Cancel) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Provision_Cancel) ProtoMessage() {} - -func (x *Provision_Cancel) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[25] - 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_Cancel.ProtoReflect.Descriptor instead. -func (*Provision_Cancel) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{14, 4} -} - -type Provision_Request struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Type: - // - // *Provision_Request_Plan - // *Provision_Request_Apply - // *Provision_Request_Cancel - Type isProvision_Request_Type `protobuf_oneof:"type"` -} - -func (x *Provision_Request) Reset() { - *x = Provision_Request{} - if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[26] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Provision_Request) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Provision_Request) ProtoMessage() {} - -func (x *Provision_Request) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[26] - 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_Request.ProtoReflect.Descriptor instead. -func (*Provision_Request) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{14, 5} -} - -func (m *Provision_Request) GetType() isProvision_Request_Type { - if m != nil { - return m.Type - } - return nil -} - -func (x *Provision_Request) GetPlan() *Provision_Plan { - if x, ok := x.GetType().(*Provision_Request_Plan); ok { - return x.Plan - } - return nil -} - -func (x *Provision_Request) GetApply() *Provision_Apply { - if x, ok := x.GetType().(*Provision_Request_Apply); ok { - return x.Apply - } - return nil -} - -func (x *Provision_Request) GetCancel() *Provision_Cancel { - if x, ok := x.GetType().(*Provision_Request_Cancel); ok { - return x.Cancel - } - return nil -} - -type isProvision_Request_Type interface { - isProvision_Request_Type() -} - -type Provision_Request_Plan struct { - Plan *Provision_Plan `protobuf:"bytes,1,opt,name=plan,proto3,oneof"` -} - -type Provision_Request_Apply struct { - Apply *Provision_Apply `protobuf:"bytes,2,opt,name=apply,proto3,oneof"` -} - -type Provision_Request_Cancel struct { - Cancel *Provision_Cancel `protobuf:"bytes,3,opt,name=cancel,proto3,oneof"` -} - -func (*Provision_Request_Plan) isProvision_Request_Type() {} - -func (*Provision_Request_Apply) isProvision_Request_Type() {} - -func (*Provision_Request_Cancel) isProvision_Request_Type() {} - -type Provision_Complete struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - State []byte `protobuf:"bytes,1,opt,name=state,proto3" json:"state,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"` - Parameters []*RichParameter `protobuf:"bytes,4,rep,name=parameters,proto3" json:"parameters,omitempty"` - GitAuthProviders []string `protobuf:"bytes,5,rep,name=git_auth_providers,json=gitAuthProviders,proto3" json:"git_auth_providers,omitempty"` - Plan []byte `protobuf:"bytes,6,opt,name=plan,proto3" json:"plan,omitempty"` -} - -func (x *Provision_Complete) Reset() { - *x = Provision_Complete{} - if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[27] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Provision_Complete) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Provision_Complete) ProtoMessage() {} - -func (x *Provision_Complete) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[27] - 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_Complete.ProtoReflect.Descriptor instead. -func (*Provision_Complete) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{14, 6} -} - -func (x *Provision_Complete) GetState() []byte { - if x != nil { - return x.State - } - 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 - } - return nil -} - -func (x *Provision_Complete) GetParameters() []*RichParameter { - if x != nil { - return x.Parameters - } - return nil -} - -func (x *Provision_Complete) GetGitAuthProviders() []string { - if x != nil { - return x.GitAuthProviders - } - return nil -} - -func (x *Provision_Complete) GetPlan() []byte { - if x != nil { - return x.Plan - } - return nil -} - -type Provision_Response struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - // Types that are assignable to Type: - // - // *Provision_Response_Log - // *Provision_Response_Complete - Type isProvision_Response_Type `protobuf_oneof:"type"` -} - -func (x *Provision_Response) Reset() { - *x = Provision_Response{} - if protoimpl.UnsafeEnabled { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[28] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *Provision_Response) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*Provision_Response) ProtoMessage() {} - -func (x *Provision_Response) ProtoReflect() protoreflect.Message { - mi := &file_provisionersdk_proto_provisioner_proto_msgTypes[28] - 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_Response.ProtoReflect.Descriptor instead. -func (*Provision_Response) Descriptor() ([]byte, []int) { - return file_provisionersdk_proto_provisioner_proto_rawDescGZIP(), []int{14, 7} -} - -func (m *Provision_Response) GetType() isProvision_Response_Type { - if m != nil { - return m.Type - } - return nil -} - -func (x *Provision_Response) GetLog() *Log { - if x, ok := x.GetType().(*Provision_Response_Log); ok { - return x.Log - } - return nil -} - -func (x *Provision_Response) GetComplete() *Provision_Complete { - if x, ok := x.GetType().(*Provision_Response_Complete); ok { - return x.Complete - } - return nil -} - -type isProvision_Response_Type interface { - isProvision_Response_Type() -} - -type Provision_Response_Log struct { - Log *Log `protobuf:"bytes,1,opt,name=log,proto3,oneof"` -} - -type Provision_Response_Complete struct { - Complete *Provision_Complete `protobuf:"bytes,2,opt,name=complete,proto3,oneof"` -} - -func (*Provision_Response_Log) isProvision_Response_Type() {} - -func (*Provision_Response_Complete) isProvision_Response_Type() {} - var File_provisionersdk_proto_provisioner_proto protoreflect.FileDescriptor var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ @@ -2543,154 +2504,161 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x74, 0x69, 0x76, 0x65, 0x12, 0x17, 0x0a, 0x07, 0x69, 0x73, 0x5f, 0x6e, 0x75, 0x6c, 0x6c, 0x18, - 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x4e, 0x75, 0x6c, 0x6c, 0x22, 0x85, 0x02, - 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, 0x5e, 0x0a, 0x08, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x4c, 0x0a, 0x12, - 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, - 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, - 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x11, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, - 0x65, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, - 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, 0x91, 0x0d, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x1a, 0xae, 0x04, 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, 0x12, 0x25, 0x0a, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, - 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, - 0x73, 0x70, 0x61, 0x63, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x77, 0x6f, 0x72, - 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x0e, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, - 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, - 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, - 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, - 0x09, 0x52, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, - 0x72, 0x49, 0x64, 0x12, 0x32, 0x0a, 0x15, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, - 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x07, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x13, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, - 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x65, 0x6d, 0x70, 0x6c, - 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, - 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x10, - 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, - 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, - 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x48, 0x0a, 0x21, 0x77, 0x6f, 0x72, 0x6b, 0x73, - 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x6f, 0x69, 0x64, 0x63, 0x5f, - 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x0a, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x1d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, - 0x65, 0x72, 0x4f, 0x69, 0x64, 0x63, 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, - 0x6e, 0x12, 0x41, 0x0a, 0x1d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, - 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x73, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, - 0x65, 0x6e, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1a, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, - 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, - 0x6f, 0x6b, 0x65, 0x6e, 0x1a, 0xad, 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 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, 0x14, 0x0a, - 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, - 0x61, 0x74, 0x65, 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, 0x32, 0x0a, 0x15, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x5f, - 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x13, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x4c, - 0x65, 0x76, 0x65, 0x6c, 0x1a, 0xa9, 0x02, 0x0a, 0x04, 0x50, 0x6c, 0x61, 0x6e, 0x12, 0x35, 0x0a, - 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 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, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, - 0x6e, 0x66, 0x69, 0x67, 0x12, 0x53, 0x0a, 0x15, 0x72, 0x69, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, - 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, - 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, - 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x72, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, - 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x43, 0x0a, 0x0f, 0x76, 0x61, 0x72, - 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x06, 0x69, 0x73, 0x4e, 0x75, 0x6c, 0x6c, 0x22, 0xae, 0x04, + 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, 0x12, 0x25, 0x0a, 0x0e, + 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4e, + 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, + 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x77, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x12, 0x21, 0x0a, 0x0c, + 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x05, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x49, 0x64, 0x12, + 0x2c, 0x0a, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, + 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x10, 0x77, 0x6f, 0x72, + 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x49, 0x64, 0x12, 0x32, 0x0a, + 0x15, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, + 0x5f, 0x65, 0x6d, 0x61, 0x69, 0x6c, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x77, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x45, 0x6d, 0x61, 0x69, + 0x6c, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x6e, 0x61, + 0x6d, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, + 0x74, 0x65, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x10, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, + 0x74, 0x65, 0x5f, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0f, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x65, 0x72, 0x73, 0x69, 0x6f, + 0x6e, 0x12, 0x48, 0x0a, 0x21, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, + 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x6f, 0x69, 0x64, 0x63, 0x5f, 0x61, 0x63, 0x63, 0x65, 0x73, 0x73, + 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x52, 0x1d, 0x77, 0x6f, + 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, 0x65, 0x72, 0x4f, 0x69, 0x64, 0x63, + 0x41, 0x63, 0x63, 0x65, 0x73, 0x73, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x41, 0x0a, 0x1d, 0x77, + 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x5f, 0x6f, 0x77, 0x6e, 0x65, 0x72, 0x5f, 0x73, + 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x0b, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x1a, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x4f, 0x77, 0x6e, + 0x65, 0x72, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x54, 0x6f, 0x6b, 0x65, 0x6e, 0x22, 0x8a, + 0x01, 0x0a, 0x06, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x12, 0x36, 0x0a, 0x17, 0x74, 0x65, 0x6d, + 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x61, 0x72, 0x63, + 0x68, 0x69, 0x76, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x15, 0x74, 0x65, 0x6d, 0x70, + 0x6c, 0x61, 0x74, 0x65, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x41, 0x72, 0x63, 0x68, 0x69, 0x76, + 0x65, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, + 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x32, 0x0a, 0x15, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x5f, 0x6c, 0x6f, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x13, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x22, 0x0e, 0x0a, 0x0c, 0x50, + 0x61, 0x72, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x8b, 0x01, 0x0a, 0x0d, + 0x50, 0x61, 0x72, 0x73, 0x65, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, + 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, 0x72, + 0x72, 0x6f, 0x72, 0x12, 0x4c, 0x0a, 0x12, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, + 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x65, + 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x11, + 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, + 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, + 0x0c, 0x52, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x22, 0xa6, 0x02, 0x0a, 0x0b, 0x50, 0x6c, + 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, + 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x53, 0x0a, 0x15, + 0x72, 0x69, 0x63, 0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, + 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, + 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x72, 0x69, + 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, + 0x73, 0x12, 0x43, 0x0a, 0x0f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, + 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, + 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x4a, 0x0a, 0x12, 0x67, 0x69, 0x74, 0x5f, 0x61, 0x75, + 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x2e, 0x47, 0x69, 0x74, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, + 0x52, 0x10, 0x67, 0x69, 0x74, 0x41, 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, + 0x72, 0x73, 0x22, 0xc3, 0x01, 0x0a, 0x0c, 0x50, 0x6c, 0x61, 0x6e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x74, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x01, 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, 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, 0x3a, + 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, - 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, - 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x4a, - 0x0a, 0x12, 0x67, 0x69, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x47, 0x69, 0x74, 0x41, 0x75, 0x74, 0x68, - 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x52, 0x10, 0x67, 0x69, 0x74, 0x41, 0x75, 0x74, - 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x4a, 0x04, 0x08, 0x02, 0x10, 0x03, - 0x1a, 0x52, 0x0a, 0x05, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x35, 0x0a, 0x06, 0x63, 0x6f, 0x6e, - 0x66, 0x69, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 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, 0x6e, 0x66, 0x69, 0x67, 0x52, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, - 0x12, 0x12, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, - 0x70, 0x6c, 0x61, 0x6e, 0x1a, 0x08, 0x0a, 0x06, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x1a, 0xb3, - 0x01, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x04, 0x70, 0x6c, - 0x61, 0x6e, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x34, 0x0a, - 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, - 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x48, 0x00, 0x52, 0x05, 0x61, 0x70, - 0x70, 0x6c, 0x79, 0x12, 0x37, 0x0a, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x18, 0x03, 0x20, - 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, - 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x43, 0x61, 0x6e, 0x63, - 0x65, 0x6c, 0x48, 0x00, 0x52, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x42, 0x06, 0x0a, 0x04, - 0x74, 0x79, 0x70, 0x65, 0x1a, 0xe9, 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, 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, 0x12, 0x3a, 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, - 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, - 0x65, 0x72, 0x52, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2c, - 0x0a, 0x12, 0x67, 0x69, 0x74, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x64, 0x65, 0x72, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x67, 0x69, 0x74, 0x41, - 0x75, 0x74, 0x68, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x12, 0x12, 0x0a, 0x04, - 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, - 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, 0x3b, 0x0a, 0x0f, 0x41, 0x70, - 0x70, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x09, 0x0a, - 0x05, 0x4f, 0x57, 0x4e, 0x45, 0x52, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x41, 0x55, 0x54, 0x48, - 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x50, - 0x55, 0x42, 0x4c, 0x49, 0x43, 0x10, 0x02, 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, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x53, 0x54, 0x52, 0x4f, 0x59, 0x10, 0x02, - 0x32, 0xa3, 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, 0x50, 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, 0x28, 0x01, 0x30, 0x01, 0x42, 0x30, 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, - 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, - 0x2f, 0x76, 0x32, 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, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, 0x0a, + 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x67, 0x69, + 0x74, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x67, 0x69, 0x74, 0x41, 0x75, 0x74, 0x68, 0x50, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x22, 0x41, 0x0a, 0x0c, 0x41, 0x70, 0x70, 0x6c, + 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x31, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, + 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0xda, 0x01, 0x0a, 0x0d, + 0x41, 0x70, 0x70, 0x6c, 0x79, 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, 0x12, 0x3a, + 0x0a, 0x0a, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x18, 0x04, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x52, 0x0a, + 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x73, 0x12, 0x2c, 0x0a, 0x12, 0x67, 0x69, + 0x74, 0x5f, 0x61, 0x75, 0x74, 0x68, 0x5f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, + 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x10, 0x67, 0x69, 0x74, 0x41, 0x75, 0x74, 0x68, 0x50, + 0x72, 0x6f, 0x76, 0x69, 0x64, 0x65, 0x72, 0x73, 0x22, 0x0f, 0x0a, 0x0d, 0x43, 0x61, 0x6e, 0x63, + 0x65, 0x6c, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x22, 0x8c, 0x02, 0x0a, 0x07, 0x52, 0x65, + 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x2d, 0x0a, 0x06, 0x63, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x18, + 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x2e, 0x43, 0x6f, 0x6e, 0x66, 0x69, 0x67, 0x48, 0x00, 0x52, 0x06, 0x63, 0x6f, + 0x6e, 0x66, 0x69, 0x67, 0x12, 0x31, 0x0a, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x18, 0x02, 0x20, + 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, + 0x52, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x12, 0x2e, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, + 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x6c, 0x61, 0x6e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, + 0x00, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x12, 0x31, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x70, 0x70, 0x6c, 0x79, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, + 0x74, 0x48, 0x00, 0x52, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x12, 0x34, 0x0a, 0x06, 0x63, 0x61, + 0x6e, 0x63, 0x65, 0x6c, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x43, 0x61, 0x6e, 0x63, 0x65, 0x6c, 0x52, + 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x48, 0x00, 0x52, 0x06, 0x63, 0x61, 0x6e, 0x63, 0x65, 0x6c, + 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0xd1, 0x01, 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, 0x32, 0x0a, 0x05, 0x70, + 0x61, 0x72, 0x73, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x43, 0x6f, + 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x05, 0x70, 0x61, 0x72, 0x73, 0x65, 0x12, + 0x2f, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x19, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x6c, 0x61, 0x6e, + 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x04, 0x70, 0x6c, 0x61, 0x6e, + 0x12, 0x32, 0x0a, 0x05, 0x61, 0x70, 0x70, 0x6c, 0x79, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x70, + 0x70, 0x6c, 0x79, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x05, 0x61, + 0x70, 0x70, 0x6c, 0x79, 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, 0x3b, 0x0a, + 0x0f, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, + 0x12, 0x09, 0x0a, 0x05, 0x4f, 0x57, 0x4e, 0x45, 0x52, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x41, + 0x55, 0x54, 0x48, 0x45, 0x4e, 0x54, 0x49, 0x43, 0x41, 0x54, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0a, + 0x0a, 0x06, 0x50, 0x55, 0x42, 0x4c, 0x49, 0x43, 0x10, 0x02, 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, 0x12, 0x0b, 0x0a, 0x07, 0x44, 0x45, 0x53, 0x54, 0x52, 0x4f, + 0x59, 0x10, 0x02, 0x32, 0x49, 0x0a, 0x0b, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, + 0x65, 0x72, 0x12, 0x3a, 0x0a, 0x07, 0x53, 0x65, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x71, 0x75, + 0x65, 0x73, 0x74, 0x1a, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x2e, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x28, 0x01, 0x30, 0x01, 0x42, 0x30, + 0x5a, 0x2e, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x76, 0x32, 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 ( @@ -2706,7 +2674,7 @@ func file_provisionersdk_proto_provisioner_proto_rawDescGZIP() []byte { } var file_provisionersdk_proto_provisioner_proto_enumTypes = make([]protoimpl.EnumInfo, 3) -var file_provisionersdk_proto_provisioner_proto_msgTypes = make([]protoimpl.MessageInfo, 29) +var file_provisionersdk_proto_provisioner_proto_msgTypes = make([]protoimpl.MessageInfo, 27) var file_provisionersdk_proto_provisioner_proto_goTypes = []interface{}{ (LogLevel)(0), // 0: provisioner.LogLevel (AppSharingLevel)(0), // 1: provisioner.AppSharingLevel @@ -2724,59 +2692,58 @@ var file_provisionersdk_proto_provisioner_proto_goTypes = []interface{}{ (*App)(nil), // 13: provisioner.App (*Healthcheck)(nil), // 14: provisioner.Healthcheck (*Resource)(nil), // 15: provisioner.Resource - (*Parse)(nil), // 16: provisioner.Parse - (*Provision)(nil), // 17: provisioner.Provision - (*Agent_Metadata)(nil), // 18: provisioner.Agent.Metadata - nil, // 19: provisioner.Agent.EnvEntry - (*Resource_Metadata)(nil), // 20: provisioner.Resource.Metadata - (*Parse_Request)(nil), // 21: provisioner.Parse.Request - (*Parse_Complete)(nil), // 22: provisioner.Parse.Complete - (*Parse_Response)(nil), // 23: provisioner.Parse.Response - (*Provision_Metadata)(nil), // 24: provisioner.Provision.Metadata - (*Provision_Config)(nil), // 25: provisioner.Provision.Config - (*Provision_Plan)(nil), // 26: provisioner.Provision.Plan - (*Provision_Apply)(nil), // 27: provisioner.Provision.Apply - (*Provision_Cancel)(nil), // 28: provisioner.Provision.Cancel - (*Provision_Request)(nil), // 29: provisioner.Provision.Request - (*Provision_Complete)(nil), // 30: provisioner.Provision.Complete - (*Provision_Response)(nil), // 31: provisioner.Provision.Response + (*Metadata)(nil), // 16: provisioner.Metadata + (*Config)(nil), // 17: provisioner.Config + (*ParseRequest)(nil), // 18: provisioner.ParseRequest + (*ParseComplete)(nil), // 19: provisioner.ParseComplete + (*PlanRequest)(nil), // 20: provisioner.PlanRequest + (*PlanComplete)(nil), // 21: provisioner.PlanComplete + (*ApplyRequest)(nil), // 22: provisioner.ApplyRequest + (*ApplyComplete)(nil), // 23: provisioner.ApplyComplete + (*CancelRequest)(nil), // 24: provisioner.CancelRequest + (*Request)(nil), // 25: provisioner.Request + (*Response)(nil), // 26: provisioner.Response + (*Agent_Metadata)(nil), // 27: provisioner.Agent.Metadata + nil, // 28: provisioner.Agent.EnvEntry + (*Resource_Metadata)(nil), // 29: provisioner.Resource.Metadata } var file_provisionersdk_proto_provisioner_proto_depIdxs = []int32{ 5, // 0: provisioner.RichParameter.options:type_name -> provisioner.RichParameterOption 0, // 1: provisioner.Log.level:type_name -> provisioner.LogLevel - 19, // 2: provisioner.Agent.env:type_name -> provisioner.Agent.EnvEntry + 28, // 2: provisioner.Agent.env:type_name -> provisioner.Agent.EnvEntry 13, // 3: provisioner.Agent.apps:type_name -> provisioner.App - 18, // 4: provisioner.Agent.metadata:type_name -> provisioner.Agent.Metadata + 27, // 4: provisioner.Agent.metadata:type_name -> provisioner.Agent.Metadata 14, // 5: provisioner.App.healthcheck:type_name -> provisioner.Healthcheck 1, // 6: provisioner.App.sharing_level:type_name -> provisioner.AppSharingLevel 12, // 7: provisioner.Resource.agents:type_name -> provisioner.Agent - 20, // 8: provisioner.Resource.metadata:type_name -> provisioner.Resource.Metadata - 4, // 9: provisioner.Parse.Complete.template_variables:type_name -> provisioner.TemplateVariable - 9, // 10: provisioner.Parse.Response.log:type_name -> provisioner.Log - 22, // 11: provisioner.Parse.Response.complete:type_name -> provisioner.Parse.Complete - 2, // 12: provisioner.Provision.Metadata.workspace_transition:type_name -> provisioner.WorkspaceTransition - 24, // 13: provisioner.Provision.Config.metadata:type_name -> provisioner.Provision.Metadata - 25, // 14: provisioner.Provision.Plan.config:type_name -> provisioner.Provision.Config - 7, // 15: provisioner.Provision.Plan.rich_parameter_values:type_name -> provisioner.RichParameterValue - 8, // 16: provisioner.Provision.Plan.variable_values:type_name -> provisioner.VariableValue - 11, // 17: provisioner.Provision.Plan.git_auth_providers:type_name -> provisioner.GitAuthProvider - 25, // 18: provisioner.Provision.Apply.config:type_name -> provisioner.Provision.Config - 26, // 19: provisioner.Provision.Request.plan:type_name -> provisioner.Provision.Plan - 27, // 20: provisioner.Provision.Request.apply:type_name -> provisioner.Provision.Apply - 28, // 21: provisioner.Provision.Request.cancel:type_name -> provisioner.Provision.Cancel - 15, // 22: provisioner.Provision.Complete.resources:type_name -> provisioner.Resource - 6, // 23: provisioner.Provision.Complete.parameters:type_name -> provisioner.RichParameter - 9, // 24: provisioner.Provision.Response.log:type_name -> provisioner.Log - 30, // 25: provisioner.Provision.Response.complete:type_name -> provisioner.Provision.Complete - 21, // 26: provisioner.Provisioner.Parse:input_type -> provisioner.Parse.Request - 29, // 27: provisioner.Provisioner.Provision:input_type -> provisioner.Provision.Request - 23, // 28: provisioner.Provisioner.Parse:output_type -> provisioner.Parse.Response - 31, // 29: provisioner.Provisioner.Provision:output_type -> provisioner.Provision.Response - 28, // [28:30] is the sub-list for method output_type - 26, // [26:28] is the sub-list for method input_type - 26, // [26:26] is the sub-list for extension type_name - 26, // [26:26] is the sub-list for extension extendee - 0, // [0:26] is the sub-list for field type_name + 29, // 8: provisioner.Resource.metadata:type_name -> provisioner.Resource.Metadata + 2, // 9: provisioner.Metadata.workspace_transition:type_name -> provisioner.WorkspaceTransition + 4, // 10: provisioner.ParseComplete.template_variables:type_name -> provisioner.TemplateVariable + 16, // 11: provisioner.PlanRequest.metadata:type_name -> provisioner.Metadata + 7, // 12: provisioner.PlanRequest.rich_parameter_values:type_name -> provisioner.RichParameterValue + 8, // 13: provisioner.PlanRequest.variable_values:type_name -> provisioner.VariableValue + 11, // 14: provisioner.PlanRequest.git_auth_providers:type_name -> provisioner.GitAuthProvider + 15, // 15: provisioner.PlanComplete.resources:type_name -> provisioner.Resource + 6, // 16: provisioner.PlanComplete.parameters:type_name -> provisioner.RichParameter + 16, // 17: provisioner.ApplyRequest.metadata:type_name -> provisioner.Metadata + 15, // 18: provisioner.ApplyComplete.resources:type_name -> provisioner.Resource + 6, // 19: provisioner.ApplyComplete.parameters:type_name -> provisioner.RichParameter + 17, // 20: provisioner.Request.config:type_name -> provisioner.Config + 18, // 21: provisioner.Request.parse:type_name -> provisioner.ParseRequest + 20, // 22: provisioner.Request.plan:type_name -> provisioner.PlanRequest + 22, // 23: provisioner.Request.apply:type_name -> provisioner.ApplyRequest + 24, // 24: provisioner.Request.cancel:type_name -> provisioner.CancelRequest + 9, // 25: provisioner.Response.log:type_name -> provisioner.Log + 19, // 26: provisioner.Response.parse:type_name -> provisioner.ParseComplete + 21, // 27: provisioner.Response.plan:type_name -> provisioner.PlanComplete + 23, // 28: provisioner.Response.apply:type_name -> provisioner.ApplyComplete + 25, // 29: provisioner.Provisioner.Session:input_type -> provisioner.Request + 26, // 30: provisioner.Provisioner.Session:output_type -> provisioner.Response + 30, // [30:31] is the sub-list for method output_type + 29, // [29:30] is the sub-list for method input_type + 29, // [29:29] is the sub-list for extension type_name + 29, // [29:29] is the sub-list for extension extendee + 0, // [0:29] is the sub-list for field type_name } func init() { file_provisionersdk_proto_provisioner_proto_init() } @@ -2942,7 +2909,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Parse); i { + switch v := v.(*Metadata); i { case 0: return &v.state case 1: @@ -2954,7 +2921,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); i { + switch v := v.(*Config); i { case 0: return &v.state case 1: @@ -2966,7 +2933,19 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Agent_Metadata); i { + switch v := v.(*ParseRequest); 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[16].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ParseComplete); i { case 0: return &v.state case 1: @@ -2978,7 +2957,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Resource_Metadata); i { + switch v := v.(*PlanRequest); i { case 0: return &v.state case 1: @@ -2990,7 +2969,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Parse_Request); i { + switch v := v.(*PlanComplete); i { case 0: return &v.state case 1: @@ -3002,7 +2981,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Parse_Complete); i { + switch v := v.(*ApplyRequest); i { case 0: return &v.state case 1: @@ -3014,7 +2993,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Parse_Response); i { + switch v := v.(*ApplyComplete); i { case 0: return &v.state case 1: @@ -3026,7 +3005,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Provision_Metadata); i { + switch v := v.(*CancelRequest); i { case 0: return &v.state case 1: @@ -3038,7 +3017,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Provision_Config); i { + switch v := v.(*Request); i { case 0: return &v.state case 1: @@ -3050,7 +3029,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[23].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Provision_Plan); i { + switch v := v.(*Response); i { case 0: return &v.state case 1: @@ -3062,19 +3041,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[24].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Provision_Apply); 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[25].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Provision_Cancel); i { + switch v := v.(*Agent_Metadata); i { case 0: return &v.state case 1: @@ -3086,31 +3053,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { } } file_provisionersdk_proto_provisioner_proto_msgTypes[26].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Provision_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[27].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[28].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*Provision_Response); i { + switch v := v.(*Resource_Metadata); i { case 0: return &v.state case 1: @@ -3127,18 +3070,18 @@ func file_provisionersdk_proto_provisioner_proto_init() { (*Agent_Token)(nil), (*Agent_InstanceId)(nil), } - file_provisionersdk_proto_provisioner_proto_msgTypes[20].OneofWrappers = []interface{}{ - (*Parse_Response_Log)(nil), - (*Parse_Response_Complete)(nil), + file_provisionersdk_proto_provisioner_proto_msgTypes[22].OneofWrappers = []interface{}{ + (*Request_Config)(nil), + (*Request_Parse)(nil), + (*Request_Plan)(nil), + (*Request_Apply)(nil), + (*Request_Cancel)(nil), } - file_provisionersdk_proto_provisioner_proto_msgTypes[26].OneofWrappers = []interface{}{ - (*Provision_Request_Plan)(nil), - (*Provision_Request_Apply)(nil), - (*Provision_Request_Cancel)(nil), - } - file_provisionersdk_proto_provisioner_proto_msgTypes[28].OneofWrappers = []interface{}{ - (*Provision_Response_Log)(nil), - (*Provision_Response_Complete)(nil), + file_provisionersdk_proto_provisioner_proto_msgTypes[23].OneofWrappers = []interface{}{ + (*Response_Log)(nil), + (*Response_Parse)(nil), + (*Response_Plan)(nil), + (*Response_Apply)(nil), } type x struct{} out := protoimpl.TypeBuilder{ @@ -3146,7 +3089,7 @@ func file_provisionersdk_proto_provisioner_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_provisionersdk_proto_provisioner_proto_rawDesc, NumEnums: 3, - NumMessages: 29, + NumMessages: 27, NumExtensions: 0, NumServices: 1, }, diff --git a/provisionersdk/proto/provisioner.proto b/provisionersdk/proto/provisioner.proto index 789735782f..5670fbde26 100644 --- a/provisionersdk/proto/provisioner.proto +++ b/provisionersdk/proto/provisioner.proto @@ -82,8 +82,8 @@ message InstanceIdentityAuth { } message GitAuthProvider { - string id = 1; - string access_token = 2; + string id = 1; + string access_token = 2; } // Agent represents a running agent on the workspace. @@ -110,15 +110,15 @@ message Agent { string token = 9; string instance_id = 10; } - int32 connection_timeout_seconds = 11; - string troubleshooting_url = 12; - string motd_file = 13; - // Field 14 was bool login_before_ready = 14, now removed. - int32 startup_script_timeout_seconds = 15; - string shutdown_script = 16; - int32 shutdown_script_timeout_seconds = 17; + int32 connection_timeout_seconds = 11; + string troubleshooting_url = 12; + string motd_file = 13; + // Field 14 was bool login_before_ready = 14, now removed. + int32 startup_script_timeout_seconds = 15; + string shutdown_script = 16; + int32 shutdown_script_timeout_seconds = 17; repeated Metadata metadata = 18; - string startup_script_behavior = 19; + string startup_script_behavior = 19; } enum AppSharingLevel { @@ -168,96 +168,111 @@ message Resource { int32 daily_cost = 8; } -// Parse consumes source-code from a directory to produce inputs. -message Parse { - message Request { - string directory = 1; - } - message Complete { - reserved 2; - - repeated TemplateVariable template_variables = 1; - } - message Response { - oneof type { - Log log = 1; - Complete complete = 2; - } - } -} - +// WorkspaceTransition is the desired outcome of a build enum WorkspaceTransition { START = 0; STOP = 1; DESTROY = 2; } -// Provision consumes source-code from a directory to produce resources. -// Exactly one of Plan or Apply must be provided in a single session. -message Provision { - message Metadata { - string coder_url = 1; - WorkspaceTransition workspace_transition = 2; - string workspace_name = 3; - string workspace_owner = 4; - string workspace_id = 5; - string workspace_owner_id = 6; - string workspace_owner_email = 7; - string template_name = 8; - string template_version = 9; - string workspace_owner_oidc_access_token = 10; - string workspace_owner_session_token = 11; - } +// Metadata is information about a workspace used in the execution of a build +message Metadata { + string coder_url = 1; + WorkspaceTransition workspace_transition = 2; + string workspace_name = 3; + string workspace_owner = 4; + string workspace_id = 5; + string workspace_owner_id = 6; + string workspace_owner_email = 7; + string template_name = 8; + string template_version = 9; + string workspace_owner_oidc_access_token = 10; + string workspace_owner_session_token = 11; +} - // Config represents execution configuration shared by both Plan and - // Apply commands. - message Config { - string directory = 1; - bytes state = 2; - Metadata metadata = 3; +// Config represents execution configuration shared by all subsequent requests in the Session +message Config { + // template_source_archive is a tar of the template source files + bytes template_source_archive = 1; + // state is the provisioner state (if any) + bytes state = 2; + string provisioner_log_level = 3; +} - string provisioner_log_level = 4; - } +// ParseRequest consumes source-code to produce inputs. +message ParseRequest { +} - message Plan { - reserved 2; +// ParseComplete indicates a request to parse completed. +message ParseComplete { + string error = 1; + repeated TemplateVariable template_variables = 2; + bytes readme = 3; +} +// PlanRequest asks the provisioner to plan what resources & parameters it will create +message PlanRequest { + Metadata metadata = 1; + repeated RichParameterValue rich_parameter_values = 2; + repeated VariableValue variable_values = 3; + repeated GitAuthProvider git_auth_providers = 4; +} + +// PlanComplete indicates a request to plan completed. +message PlanComplete { + string error = 1; + repeated Resource resources = 2; + repeated RichParameter parameters = 3; + repeated string git_auth_providers = 4; +} + +// ApplyRequest asks the provisioner to apply the changes. Apply MUST be preceded by a successful plan request/response +// in the same Session. The plan data is not transmitted over the wire and is cached by the provisioner in the Session. +message ApplyRequest { + Metadata metadata = 1; +} + +// ApplyComplete indicates a request to apply completed. +message ApplyComplete { + bytes state = 1; + string error = 2; + repeated Resource resources = 3; + repeated RichParameter parameters = 4; + repeated string git_auth_providers = 5; +} + +// CancelRequest requests that the previous request be canceled gracefully. +message CancelRequest {} + +message Request { + oneof type { Config config = 1; - repeated RichParameterValue rich_parameter_values = 3; - repeated VariableValue variable_values = 4; - repeated GitAuthProvider git_auth_providers = 5; + ParseRequest parse = 2; + PlanRequest plan = 3; + ApplyRequest apply = 4; + CancelRequest cancel = 5; } +} - message Apply { - Config config = 1; - bytes plan = 2; - } - - message Cancel {} - message Request { - oneof type { - Plan plan = 1; - Apply apply = 2; - Cancel cancel = 3; - } - } - message Complete { - bytes state = 1; - string error = 2; - repeated Resource resources = 3; - repeated RichParameter parameters = 4; - repeated string git_auth_providers = 5; - bytes plan = 6; - } - message Response { - oneof type { - Log log = 1; - Complete complete = 2; - } +message Response { + oneof type { + Log log = 1; + ParseComplete parse = 2; + PlanComplete plan = 3; + ApplyComplete apply = 4; } } service Provisioner { - rpc Parse(Parse.Request) returns (stream Parse.Response); - rpc Provision(stream Provision.Request) returns (stream Provision.Response); + // Session represents provisioning a single template import or workspace. The daemon always sends Config followed + // by one of the requests (ParseRequest, PlanRequest, ApplyRequest). The provisioner should respond with a stream + // of zero or more Logs, followed by the corresponding complete message (ParseComplete, PlanComplete, + // ApplyComplete). The daemon may then send a new request. A request to apply MUST be preceded by a request plan, + // and the provisioner should store the plan data on the Session after a successful plan, so that the daemon may + // request an apply. If the daemon closes the Session without an apply, the plan data may be safely discarded. + // + // The daemon may send a CancelRequest, asynchronously to ask the provisioner to cancel the previous ParseRequest, + // PlanRequest, or ApplyRequest. The provisioner MUST reply with a complete message corresponding to the request + // that was canceled. If the provisioner has already completed the request, it may ignore the CancelRequest. + rpc Session(stream Request) returns (stream Response); } diff --git a/provisionersdk/proto/provisioner_drpc.pb.go b/provisionersdk/proto/provisioner_drpc.pb.go index d8b40060cd..de310e779d 100644 --- a/provisionersdk/proto/provisioner_drpc.pb.go +++ b/provisionersdk/proto/provisioner_drpc.pb.go @@ -38,8 +38,7 @@ func (drpcEncoding_File_provisionersdk_proto_provisioner_proto) JSONUnmarshal(bu type DRPCProvisionerClient interface { DRPCConn() drpc.Conn - Parse(ctx context.Context, in *Parse_Request) (DRPCProvisioner_ParseClient, error) - Provision(ctx context.Context) (DRPCProvisioner_ProvisionClient, error) + Session(ctx context.Context) (DRPCProvisioner_SessionClient, error) } type drpcProvisionerClient struct { @@ -52,123 +51,69 @@ func NewDRPCProvisionerClient(cc drpc.Conn) DRPCProvisionerClient { func (c *drpcProvisionerClient) DRPCConn() drpc.Conn { return c.cc } -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{}) +func (c *drpcProvisionerClient) Session(ctx context.Context) (DRPCProvisioner_SessionClient, error) { + stream, err := c.cc.NewStream(ctx, "/provisioner.Provisioner/Session", drpcEncoding_File_provisionersdk_proto_provisioner_proto{}) if err != nil { return nil, err } - x := &drpcProvisioner_ParseClient{stream} - if err := x.MsgSend(in, drpcEncoding_File_provisionersdk_proto_provisioner_proto{}); err != nil { - return nil, err - } - if err := x.CloseSend(); err != nil { - return nil, err - } + x := &drpcProvisioner_SessionClient{stream} return x, nil } -type DRPCProvisioner_ParseClient interface { +type DRPCProvisioner_SessionClient interface { drpc.Stream - Recv() (*Parse_Response, error) + Send(*Request) error + Recv() (*Response, error) } -type drpcProvisioner_ParseClient struct { +type drpcProvisioner_SessionClient struct { drpc.Stream } -func (x *drpcProvisioner_ParseClient) GetStream() drpc.Stream { +func (x *drpcProvisioner_SessionClient) GetStream() drpc.Stream { return x.Stream } -func (x *drpcProvisioner_ParseClient) Recv() (*Parse_Response, error) { - m := new(Parse_Response) - if err := x.MsgRecv(m, drpcEncoding_File_provisionersdk_proto_provisioner_proto{}); err != nil { - return nil, err - } - return m, nil -} - -func (x *drpcProvisioner_ParseClient) RecvMsg(m *Parse_Response) error { - return x.MsgRecv(m, drpcEncoding_File_provisionersdk_proto_provisioner_proto{}) -} - -func (c *drpcProvisionerClient) Provision(ctx context.Context) (DRPCProvisioner_ProvisionClient, error) { - stream, err := c.cc.NewStream(ctx, "/provisioner.Provisioner/Provision", drpcEncoding_File_provisionersdk_proto_provisioner_proto{}) - if err != nil { - return nil, err - } - x := &drpcProvisioner_ProvisionClient{stream} - return x, nil -} - -type DRPCProvisioner_ProvisionClient interface { - drpc.Stream - Send(*Provision_Request) error - Recv() (*Provision_Response, error) -} - -type drpcProvisioner_ProvisionClient struct { - drpc.Stream -} - -func (x *drpcProvisioner_ProvisionClient) GetStream() drpc.Stream { - return x.Stream -} - -func (x *drpcProvisioner_ProvisionClient) Send(m *Provision_Request) error { +func (x *drpcProvisioner_SessionClient) Send(m *Request) error { return x.MsgSend(m, drpcEncoding_File_provisionersdk_proto_provisioner_proto{}) } -func (x *drpcProvisioner_ProvisionClient) Recv() (*Provision_Response, error) { - m := new(Provision_Response) +func (x *drpcProvisioner_SessionClient) Recv() (*Response, error) { + m := new(Response) if err := x.MsgRecv(m, drpcEncoding_File_provisionersdk_proto_provisioner_proto{}); err != nil { return nil, err } return m, nil } -func (x *drpcProvisioner_ProvisionClient) RecvMsg(m *Provision_Response) error { +func (x *drpcProvisioner_SessionClient) RecvMsg(m *Response) error { return x.MsgRecv(m, drpcEncoding_File_provisionersdk_proto_provisioner_proto{}) } type DRPCProvisionerServer interface { - Parse(*Parse_Request, DRPCProvisioner_ParseStream) error - Provision(DRPCProvisioner_ProvisionStream) error + Session(DRPCProvisioner_SessionStream) error } type DRPCProvisionerUnimplementedServer struct{} -func (s *DRPCProvisionerUnimplementedServer) Parse(*Parse_Request, DRPCProvisioner_ParseStream) error { - return drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) -} - -func (s *DRPCProvisionerUnimplementedServer) Provision(DRPCProvisioner_ProvisionStream) error { +func (s *DRPCProvisionerUnimplementedServer) Session(DRPCProvisioner_SessionStream) error { return drpcerr.WithCode(errors.New("Unimplemented"), drpcerr.Unimplemented) } type DRPCProvisionerDescription struct{} -func (DRPCProvisionerDescription) NumMethods() int { return 2 } +func (DRPCProvisionerDescription) NumMethods() int { return 1 } func (DRPCProvisionerDescription) Method(n int) (string, drpc.Encoding, drpc.Receiver, interface{}, bool) { switch n { case 0: - return "/provisioner.Provisioner/Parse", drpcEncoding_File_provisionersdk_proto_provisioner_proto{}, + return "/provisioner.Provisioner/Session", drpcEncoding_File_provisionersdk_proto_provisioner_proto{}, func(srv interface{}, ctx context.Context, in1, in2 interface{}) (drpc.Message, error) { return nil, srv.(DRPCProvisionerServer). - Parse( - in1.(*Parse_Request), - &drpcProvisioner_ParseStream{in2.(drpc.Stream)}, + Session( + &drpcProvisioner_SessionStream{in1.(drpc.Stream)}, ) - }, DRPCProvisionerServer.Parse, true - case 1: - 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). - Provision( - &drpcProvisioner_ProvisionStream{in1.(drpc.Stream)}, - ) - }, DRPCProvisionerServer.Provision, true + }, DRPCProvisionerServer.Session, true default: return "", nil, nil, nil, false } @@ -178,41 +123,28 @@ func DRPCRegisterProvisioner(mux drpc.Mux, impl DRPCProvisionerServer) error { return mux.Register(impl, DRPCProvisionerDescription{}) } -type DRPCProvisioner_ParseStream interface { +type DRPCProvisioner_SessionStream interface { drpc.Stream - Send(*Parse_Response) error + Send(*Response) error + Recv() (*Request, error) } -type drpcProvisioner_ParseStream struct { +type drpcProvisioner_SessionStream struct { drpc.Stream } -func (x *drpcProvisioner_ParseStream) Send(m *Parse_Response) error { +func (x *drpcProvisioner_SessionStream) Send(m *Response) error { return x.MsgSend(m, drpcEncoding_File_provisionersdk_proto_provisioner_proto{}) } -type DRPCProvisioner_ProvisionStream interface { - drpc.Stream - Send(*Provision_Response) error - Recv() (*Provision_Request, error) -} - -type drpcProvisioner_ProvisionStream struct { - drpc.Stream -} - -func (x *drpcProvisioner_ProvisionStream) Send(m *Provision_Response) error { - return x.MsgSend(m, drpcEncoding_File_provisionersdk_proto_provisioner_proto{}) -} - -func (x *drpcProvisioner_ProvisionStream) Recv() (*Provision_Request, error) { - m := new(Provision_Request) +func (x *drpcProvisioner_SessionStream) Recv() (*Request, error) { + m := new(Request) if err := x.MsgRecv(m, drpcEncoding_File_provisionersdk_proto_provisioner_proto{}); err != nil { return nil, err } return m, nil } -func (x *drpcProvisioner_ProvisionStream) RecvMsg(m *Provision_Request) error { +func (x *drpcProvisioner_SessionStream) RecvMsg(m *Request) error { return x.MsgRecv(m, drpcEncoding_File_provisionersdk_proto_provisioner_proto{}) } diff --git a/provisionersdk/serve.go b/provisionersdk/serve.go index ea3364b605..924c7ad013 100644 --- a/provisionersdk/serve.go +++ b/provisionersdk/serve.go @@ -13,6 +13,8 @@ import ( "storj.io/drpc/drpcmux" "storj.io/drpc/drpcserver" + "cdr.dev/slog" + "github.com/coder/coder/v2/coderd/tracing" "github.com/coder/coder/v2/provisionersdk/proto" ) @@ -20,11 +22,19 @@ import ( // ServeOptions are configurations to serve a provisioner. type ServeOptions struct { // Conn specifies a custom transport to serve the dRPC connection. - Listener net.Listener + Listener net.Listener + Logger slog.Logger + WorkDirectory string +} + +type Server interface { + Parse(s *Session, r *proto.ParseRequest, canceledOrComplete <-chan struct{}) *proto.ParseComplete + Plan(s *Session, r *proto.PlanRequest, canceledOrComplete <-chan struct{}) *proto.PlanComplete + Apply(s *Session, r *proto.ApplyRequest, canceledOrComplete <-chan struct{}) *proto.ApplyComplete } // Serve starts a dRPC connection for the provisioner and transport provided. -func Serve(ctx context.Context, server proto.DRPCProvisionerServer, options *ServeOptions) error { +func Serve(ctx context.Context, server Server, options *ServeOptions) error { if options == nil { options = &ServeOptions{} } @@ -45,11 +55,22 @@ func Serve(ctx context.Context, server proto.DRPCProvisionerServer, options *Ser }() options.Listener = stdio } + if options.WorkDirectory == "" { + var err error + options.WorkDirectory, err = os.MkdirTemp("", "coderprovisioner") + if err != nil { + return xerrors.Errorf("failed to init temp work dir: %w", err) + } + } // dRPC is a drop-in replacement for gRPC with less generated code, and faster transports. // See: https://www.storj.io/blog/introducing-drpc-our-replacement-for-grpc mux := drpcmux.New() - err := proto.DRPCRegisterProvisioner(mux, server) + ps := &protoServer{ + server: server, + opts: *options, + } + err := proto.DRPCRegisterProvisioner(mux, ps) if err != nil { return xerrors.Errorf("register provisioner: %w", err) } diff --git a/provisionersdk/serve_test.go b/provisionersdk/serve_test.go index dedf891889..baa5d2ba62 100644 --- a/provisionersdk/serve_test.go +++ b/provisionersdk/serve_test.go @@ -7,7 +7,6 @@ import ( "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.uber.org/goleak" - "storj.io/drpc/drpcerr" "github.com/coder/coder/v2/provisionersdk" "github.com/coder/coder/v2/provisionersdk/proto" @@ -28,17 +27,37 @@ func TestProvisionerSDK(t *testing.T) { ctx, cancelFunc := context.WithCancel(context.Background()) defer cancelFunc() go func() { - err := provisionersdk.Serve(ctx, &proto.DRPCProvisionerUnimplementedServer{}, &provisionersdk.ServeOptions{ - Listener: server, + err := provisionersdk.Serve(ctx, unimplementedServer{}, &provisionersdk.ServeOptions{ + Listener: server, + WorkDirectory: t.TempDir(), }) assert.NoError(t, err) }() api := proto.NewDRPCProvisionerClient(client) - stream, err := api.Parse(context.Background(), &proto.Parse_Request{}) + s, err := api.Session(ctx) require.NoError(t, err) - _, err = stream.Recv() - require.Equal(t, drpcerr.Unimplemented, int(drpcerr.Code(err))) + err = s.Send(&proto.Request{Type: &proto.Request_Config{Config: &proto.Config{}}}) + require.NoError(t, err) + + err = s.Send(&proto.Request{Type: &proto.Request_Parse{Parse: &proto.ParseRequest{}}}) + require.NoError(t, err) + msg, err := s.Recv() + require.NoError(t, err) + require.Equal(t, "unimplemented", msg.GetParse().GetError()) + + err = s.Send(&proto.Request{Type: &proto.Request_Plan{Plan: &proto.PlanRequest{}}}) + require.NoError(t, err) + msg, err = s.Recv() + require.NoError(t, err) + // Plan has no error so that we're allowed to run Apply + require.Equal(t, "", msg.GetPlan().GetError()) + + err = s.Send(&proto.Request{Type: &proto.Request_Apply{Apply: &proto.ApplyRequest{}}}) + require.NoError(t, err) + msg, err = s.Recv() + require.NoError(t, err) + require.Equal(t, "unimplemented", msg.GetApply().GetError()) }) t.Run("ServeClosedPipe", func(t *testing.T) { @@ -47,9 +66,24 @@ func TestProvisionerSDK(t *testing.T) { _ = client.Close() _ = server.Close() - err := provisionersdk.Serve(context.Background(), &proto.DRPCProvisionerUnimplementedServer{}, &provisionersdk.ServeOptions{ - Listener: server, + err := provisionersdk.Serve(context.Background(), unimplementedServer{}, &provisionersdk.ServeOptions{ + Listener: server, + WorkDirectory: t.TempDir(), }) require.NoError(t, err) }) } + +type unimplementedServer struct{} + +func (unimplementedServer) Parse(_ *provisionersdk.Session, _ *proto.ParseRequest, _ <-chan struct{}) *proto.ParseComplete { + return &proto.ParseComplete{Error: "unimplemented"} +} + +func (unimplementedServer) Plan(_ *provisionersdk.Session, _ *proto.PlanRequest, _ <-chan struct{}) *proto.PlanComplete { + return &proto.PlanComplete{} +} + +func (unimplementedServer) Apply(_ *provisionersdk.Session, _ *proto.ApplyRequest, _ <-chan struct{}) *proto.ApplyComplete { + return &proto.ApplyComplete{Error: "unimplemented"} +} diff --git a/provisionersdk/session.go b/provisionersdk/session.go new file mode 100644 index 0000000000..dfcd981ce7 --- /dev/null +++ b/provisionersdk/session.go @@ -0,0 +1,318 @@ +package provisionersdk + +import ( + "archive/tar" + "bytes" + "context" + "fmt" + "io" + "os" + "path/filepath" + "strings" + "time" + + "github.com/google/uuid" + "golang.org/x/xerrors" + + "cdr.dev/slog" + "github.com/coder/coder/v2/provisionersdk/proto" +) + +// ReadmeFile is the location we look for to extract documentation from template +// versions. +const ReadmeFile = "README.md" + +// protoServer is a wrapper that translates the dRPC protocol into a Session with method calls into the Server. +type protoServer struct { + server Server + opts ServeOptions +} + +func (p *protoServer) Session(stream proto.DRPCProvisioner_SessionStream) error { + sessID := uuid.New().String() + s := &Session{ + Logger: p.opts.Logger.With(slog.F("session_id", sessID)), + stream: stream, + server: p.server, + } + sessDir := fmt.Sprintf("Session%s", sessID) + s.WorkDirectory = filepath.Join(p.opts.WorkDirectory, sessDir) + err := os.MkdirAll(s.WorkDirectory, 0o700) + if err != nil { + return xerrors.Errorf("create work directory %q: %w", s.WorkDirectory, err) + } + defer func() { + var err error + // Cleanup the work directory after execution. + for attempt := 0; attempt < 5; attempt++ { + err = os.RemoveAll(s.WorkDirectory) + if err != nil { + // On Windows, open files cannot be removed. + // When the provisioner daemon is shutting down, + // it may take a few milliseconds for processes to exit. + // See: https://github.com/golang/go/issues/50510 + s.Logger.Debug(s.Context(), "failed to clean work directory; trying again", slog.Error(err)) + time.Sleep(250 * time.Millisecond) + continue + } + s.Logger.Debug(s.Context(), "cleaned up work directory") + return + } + s.Logger.Error(s.Context(), "failed to clean up work directory after multiple attempts", + slog.F("path", s.WorkDirectory), slog.Error(err)) + }() + req, err := stream.Recv() + if err != nil { + return xerrors.Errorf("receive config: %w", err) + } + config := req.GetConfig() + if config == nil { + return xerrors.New("first request must be Config") + } + s.Config = config + if s.Config.ProvisionerLogLevel != "" { + s.logLevel = proto.LogLevel_value[strings.ToUpper(s.Config.ProvisionerLogLevel)] + } + + err = s.extractArchive() + if err != nil { + return xerrors.Errorf("extract archive: %w", err) + } + return s.handleRequests() +} + +func (s *Session) requestReader(done <-chan struct{}) <-chan *proto.Request { + ch := make(chan *proto.Request) + go func() { + defer close(ch) + for { + req, err := s.stream.Recv() + if err != nil { + s.Logger.Info(s.Context(), "recv done on Session", slog.Error(err)) + return + } + select { + case ch <- req: + continue + case <-done: + return + } + } + }() + return ch +} + +func (s *Session) handleRequests() error { + done := make(chan struct{}) + defer close(done) + requests := s.requestReader(done) + planned := false + for req := range requests { + if req.GetCancel() != nil { + s.Logger.Warn(s.Context(), "ignoring cancel before request or after complete") + continue + } + resp := &proto.Response{} + if parse := req.GetParse(); parse != nil { + r := &request[*proto.ParseRequest, *proto.ParseComplete]{ + req: parse, + session: s, + serverFn: s.server.Parse, + cancels: requests, + } + complete, err := r.do() + if err != nil { + return err + } + // Handle README centrally, so that individual provisioners don't need to mess with it. + readme, err := os.ReadFile(filepath.Join(s.WorkDirectory, ReadmeFile)) + if err == nil { + complete.Readme = readme + } else { + s.Logger.Debug(s.Context(), "failed to parse readme (missing ok)", slog.Error(err)) + } + resp.Type = &proto.Response_Parse{Parse: complete} + } + if plan := req.GetPlan(); plan != nil { + r := &request[*proto.PlanRequest, *proto.PlanComplete]{ + req: plan, + session: s, + serverFn: s.server.Plan, + cancels: requests, + } + complete, err := r.do() + if err != nil { + return err + } + resp.Type = &proto.Response_Plan{Plan: complete} + if complete.Error == "" { + planned = true + } + } + if apply := req.GetApply(); apply != nil { + if !planned { + return xerrors.New("cannot apply before successful plan") + } + r := &request[*proto.ApplyRequest, *proto.ApplyComplete]{ + req: apply, + session: s, + serverFn: s.server.Apply, + cancels: requests, + } + complete, err := r.do() + if err != nil { + return err + } + resp.Type = &proto.Response_Apply{Apply: complete} + } + err := s.stream.Send(resp) + if err != nil { + return xerrors.Errorf("send response: %w", err) + } + } + return nil +} + +type Session struct { + Logger slog.Logger + WorkDirectory string + Config *proto.Config + + server Server + stream proto.DRPCProvisioner_SessionStream + logLevel int32 +} + +func (s *Session) Context() context.Context { + return s.stream.Context() +} + +func (s *Session) extractArchive() error { + ctx := s.Context() + + s.Logger.Info(ctx, "unpacking template source archive", + slog.F("size_bytes", len(s.Config.TemplateSourceArchive)), + ) + + reader := tar.NewReader(bytes.NewBuffer(s.Config.TemplateSourceArchive)) + // for safety, nil out the reference on Config, since the reader now owns it. + s.Config.TemplateSourceArchive = nil + for { + header, err := reader.Next() + if err != nil { + if xerrors.Is(err, io.EOF) { + break + } + return xerrors.Errorf("read template source archive: %w", err) + } + // Security: don't untar absolute or relative paths, as this can allow a malicious tar to overwrite + // files outside the workdir. + if !filepath.IsLocal(header.Name) { + return xerrors.Errorf("refusing to extract to non-local path") + } + // nolint: gosec + headerPath := filepath.Join(s.WorkDirectory, header.Name) + if !strings.HasPrefix(headerPath, filepath.Clean(s.WorkDirectory)) { + return xerrors.New("tar attempts to target relative upper directory") + } + mode := header.FileInfo().Mode() + if mode == 0 { + mode = 0o600 + } + switch header.Typeflag { + case tar.TypeDir: + err = os.MkdirAll(headerPath, mode) + if err != nil { + return xerrors.Errorf("mkdir %q: %w", headerPath, err) + } + s.Logger.Debug(context.Background(), "extracted directory", + slog.F("path", headerPath), + slog.F("mode", fmt.Sprintf("%O", mode))) + case tar.TypeReg: + file, err := os.OpenFile(headerPath, os.O_CREATE|os.O_RDWR, mode) + if err != nil { + return xerrors.Errorf("create file %q (mode %s): %w", headerPath, mode, err) + } + // Max file size of 10MiB. + size, err := io.CopyN(file, reader, 10<<20) + if xerrors.Is(err, io.EOF) { + err = nil + } + if err != nil { + _ = file.Close() + return xerrors.Errorf("copy file %q: %w", headerPath, err) + } + err = file.Close() + if err != nil { + return xerrors.Errorf("close file %q: %s", headerPath, err) + } + s.Logger.Debug(context.Background(), "extracted file", + slog.F("size_bytes", size), + slog.F("path", headerPath), + slog.F("mode", mode), + ) + } + } + return nil +} + +func (s *Session) ProvisionLog(level proto.LogLevel, output string) { + if int32(level) < s.logLevel { + return + } + + err := s.stream.Send(&proto.Response{Type: &proto.Response_Log{Log: &proto.Log{ + Level: level, + Output: output, + }}}) + if err != nil { + s.Logger.Error(s.Context(), "failed to transmit log", + slog.F("level", level), slog.F("output", output)) + } +} + +type pRequest interface { + *proto.ParseRequest | *proto.PlanRequest | *proto.ApplyRequest +} + +type pComplete interface { + *proto.ParseComplete | *proto.PlanComplete | *proto.ApplyComplete +} + +// request processes a single request call to the Server and returns its complete result, while also processing cancel +// requests from the daemon. Provisioner implementations read from canceledOrComplete to be asynchronously informed +// of cancel. +type request[R pRequest, C pComplete] struct { + req R + session *Session + cancels <-chan *proto.Request + serverFn func(*Session, R, <-chan struct{}) C +} + +func (r *request[R, C]) do() (C, error) { + canceledOrComplete := make(chan struct{}) + result := make(chan C) + go func() { + c := r.serverFn(r.session, r.req, canceledOrComplete) + result <- c + }() + select { + case req := <-r.cancels: + close(canceledOrComplete) + // wait for server to complete the request, even though we have canceled, + // so that we can't start a new request, and so that if the job was close + // to completion and the cancel was ignored, we return to complete. + c := <-result + // verify we got a cancel instead of another request or closed channel --- which is an error! + if req.GetCancel() != nil { + return c, nil + } + if req == nil { + return c, xerrors.New("got nil while old request still processing") + } + return c, xerrors.Errorf("got new request %T while old request still processing", req.Type) + case c := <-result: + close(canceledOrComplete) + return c, nil + } +} diff --git a/provisionersdk/transport.go b/provisionersdk/transport.go index 19730d3bf0..f5df895d64 100644 --- a/provisionersdk/transport.go +++ b/provisionersdk/transport.go @@ -19,7 +19,7 @@ const ( MaxMessageSize = 4 << 20 ) -// MultiplexedConn returns a multiplexed dRPC connection from a yamux session. +// MultiplexedConn returns a multiplexed dRPC connection from a yamux Session. func MultiplexedConn(session *yamux.Session) drpc.Conn { return &multiplexedDRPC{session} } diff --git a/scaletest/agentconn/run_test.go b/scaletest/agentconn/run_test.go index e9697ddede..4d3ffb8d0d 100644 --- a/scaletest/agentconn/run_test.go +++ b/scaletest/agentconn/run_test.go @@ -231,10 +231,10 @@ func setupRunnerTest(t *testing.T) (client *codersdk.Client, agentID uuid.UUID) authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", diff --git a/scaletest/createworkspaces/run_test.go b/scaletest/createworkspaces/run_test.go index b1d871cefd..b69297f622 100644 --- a/scaletest/createworkspaces/run_test.go +++ b/scaletest/createworkspaces/run_test.go @@ -48,10 +48,10 @@ func Test_Runner(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{ { - Type: &proto.Provision_Response_Log{ + Type: &proto.Response_Log{ Log: &proto.Log{ Level: proto.LogLevel_INFO, Output: "hello from logs", @@ -59,8 +59,8 @@ func Test_Runner(t *testing.T) { }, }, { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{ { Name: "example", @@ -170,10 +170,10 @@ func Test_Runner(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{ { - Type: &proto.Provision_Response_Log{Log: &proto.Log{}}, + Type: &proto.Response_Log{Log: &proto.Log{}}, }, }, }) @@ -282,10 +282,10 @@ func Test_Runner(t *testing.T) { authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{ { - Type: &proto.Provision_Response_Log{ + Type: &proto.Response_Log{ Log: &proto.Log{ Level: proto.LogLevel_INFO, Output: "hello from logs", @@ -293,8 +293,8 @@ func Test_Runner(t *testing.T) { }, }, { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{ { Name: "example", @@ -407,11 +407,11 @@ func Test_Runner(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{ { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Error: "test error", }, }, diff --git a/scaletest/reconnectingpty/run_test.go b/scaletest/reconnectingpty/run_test.go index 8b45f9e015..81de3dcfb9 100644 --- a/scaletest/reconnectingpty/run_test.go +++ b/scaletest/reconnectingpty/run_test.go @@ -252,10 +252,10 @@ func setupRunnerTest(t *testing.T) (client *codersdk.Client, agentID uuid.UUID) authToken := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", diff --git a/scaletest/workspacebuild/run_test.go b/scaletest/workspacebuild/run_test.go index 2b50c95bda..c07b10f809 100644 --- a/scaletest/workspacebuild/run_test.go +++ b/scaletest/workspacebuild/run_test.go @@ -45,10 +45,10 @@ func Test_Runner(t *testing.T) { authToken3 := uuid.NewString() version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{ { - Type: &proto.Provision_Response_Log{ + Type: &proto.Response_Log{ Log: &proto.Log{ Level: proto.LogLevel_INFO, Output: "hello from logs", @@ -56,8 +56,8 @@ func Test_Runner(t *testing.T) { }, }, { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{ { Name: "example1", @@ -199,11 +199,11 @@ func Test_Runner(t *testing.T) { version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{ { - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Error: "test error", }, }, diff --git a/scaletest/workspacetraffic/run_test.go b/scaletest/workspacetraffic/run_test.go index 4077a266aa..3086309104 100644 --- a/scaletest/workspacetraffic/run_test.go +++ b/scaletest/workspacetraffic/run_test.go @@ -41,10 +41,10 @@ func TestRun(t *testing.T) { agentName = "agent" version = coderdtest.CreateTemplateVersion(t, client, firstUser.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", @@ -154,10 +154,10 @@ func TestRun(t *testing.T) { agentName = "agent" version = coderdtest.CreateTemplateVersion(t, client, firstUser.OrganizationID, &echo.Responses{ Parse: echo.ParseComplete, - ProvisionPlan: echo.ProvisionComplete, - ProvisionApply: []*proto.Provision_Response{{ - Type: &proto.Provision_Response_Complete{ - Complete: &proto.Provision_Complete{ + ProvisionPlan: echo.PlanComplete, + ProvisionApply: []*proto.Response{{ + Type: &proto.Response_Apply{ + Apply: &proto.ApplyComplete{ Resources: []*proto.Resource{{ Name: "example", Type: "aws_instance", diff --git a/site/e2e/helpers.ts b/site/e2e/helpers.ts index 6525fa3b01..aa0e2e32eb 100644 --- a/site/e2e/helpers.ts +++ b/site/e2e/helpers.ts @@ -8,10 +8,10 @@ import { Agent, App, AppSharingLevel, - Parse_Complete, - Parse_Response, - Provision_Complete, - Provision_Response, + Response, + ParseComplete, + PlanComplete, + ApplyComplete, Resource, RichParameter, } from "./provisionerGenerated" @@ -337,11 +337,11 @@ type RecursivePartial = { interface EchoProvisionerResponses { // parse is for observing any Terraform variables - parse?: RecursivePartial[] + parse?: RecursivePartial[] // plan occurs when the template is imported - plan?: RecursivePartial[] + plan?: RecursivePartial[] // apply occurs when the workspace is built - apply?: RecursivePartial[] + apply?: RecursivePartial[] } // createTemplateVersionTar consumes a series of echo provisioner protobufs and @@ -353,109 +353,133 @@ const createTemplateVersionTar = async ( responses = {} } if (!responses.parse) { - responses.parse = [{}] + responses.parse = [ + { + parse: {}, + }, + ] } if (!responses.apply) { - responses.apply = [{}] + responses.apply = [ + { + apply: {}, + }, + ] } if (!responses.plan) { - responses.plan = responses.apply + responses.plan = responses.apply.map((response) => { + if (response.log) { + return response + } + return { + plan: { + error: response.apply?.error ?? "", + resources: response.apply?.resources ?? [], + parameters: response.apply?.parameters ?? [], + gitAuthProviders: response.apply?.gitAuthProviders ?? [], + }, + } + }) } const tar = new TarWriter() responses.parse.forEach((response, index) => { - response.complete = { + response.parse = { templateVariables: [], - ...response.complete, - } as Parse_Complete + error: "", + readme: new Uint8Array(), + ...response.parse, + } as ParseComplete tar.addFile( `${index}.parse.protobuf`, - Parse_Response.encode(response as Parse_Response).finish(), + Response.encode(response as Response).finish(), ) }) - const fillProvisionResponse = ( - response: RecursivePartial, - ) => { - response.complete = { + const fillResource = (resource: RecursivePartial) => { + if (resource.agents) { + resource.agents = resource.agents?.map( + (agent: RecursivePartial) => { + if (agent.apps) { + agent.apps = agent.apps?.map((app: RecursivePartial) => { + return { + command: "", + displayName: "example", + external: false, + icon: "", + sharingLevel: AppSharingLevel.PUBLIC, + slug: "example", + subdomain: false, + url: "", + ...app, + } as App + }) + } + return { + apps: [], + architecture: "amd64", + connectionTimeoutSeconds: 300, + directory: "", + env: {}, + id: randomUUID(), + metadata: [], + motdFile: "", + name: "dev", + operatingSystem: "linux", + shutdownScript: "", + shutdownScriptTimeoutSeconds: 0, + startupScript: "", + startupScriptBehavior: "", + startupScriptTimeoutSeconds: 300, + troubleshootingUrl: "", + token: randomUUID(), + ...agent, + } as Agent + }, + ) + } + return { + agents: [], + dailyCost: 0, + hide: false, + icon: "", + instanceType: "", + metadata: [], + name: "dev", + type: "echo", + ...resource, + } as Resource + } + + responses.apply.forEach((response, index) => { + response.apply = { error: "", state: new Uint8Array(), resources: [], parameters: [], gitAuthProviders: [], - plan: new Uint8Array(), - ...response.complete, - } as Provision_Complete - response.complete.resources = response.complete.resources?.map( - (resource) => { - if (resource.agents) { - resource.agents = resource.agents?.map((agent) => { - if (agent.apps) { - agent.apps = agent.apps?.map((app) => { - return { - command: "", - displayName: "example", - external: false, - icon: "", - sharingLevel: AppSharingLevel.PUBLIC, - slug: "example", - subdomain: false, - url: "", - ...app, - } as App - }) - } - return { - apps: [], - architecture: "amd64", - connectionTimeoutSeconds: 300, - directory: "", - env: {}, - id: randomUUID(), - metadata: [], - motdFile: "", - name: "dev", - operatingSystem: "linux", - shutdownScript: "", - shutdownScriptTimeoutSeconds: 0, - startupScript: "", - startupScriptBehavior: "", - startupScriptTimeoutSeconds: 300, - troubleshootingUrl: "", - token: randomUUID(), - ...agent, - } as Agent - }) - } - return { - agents: [], - dailyCost: 0, - hide: false, - icon: "", - instanceType: "", - metadata: [], - name: "dev", - type: "echo", - ...resource, - } as Resource - }, - ) - } - - responses.apply.forEach((response, index) => { - fillProvisionResponse(response) + ...response.apply, + } as ApplyComplete + response.apply.resources = response.apply.resources?.map(fillResource) tar.addFile( - `${index}.provision.apply.protobuf`, - Provision_Response.encode(response as Provision_Response).finish(), + `${index}.apply.protobuf`, + Response.encode(response as Response).finish(), ) }) responses.plan.forEach((response, index) => { - fillProvisionResponse(response) + response.plan = { + error: "", + resources: [], + parameters: [], + gitAuthProviders: [], + ...response.plan, + } as PlanComplete + response.plan.resources = response.plan.resources?.map(fillResource) tar.addFile( - `${index}.provision.plan.protobuf`, - Provision_Response.encode(response as Provision_Response).finish(), + `${index}.plan.protobuf`, + Response.encode(response as Response).finish(), ) }) const tarFile = await tar.write() @@ -512,16 +536,21 @@ export const echoResponsesWithParameters = ( richParameters: RichParameter[], ): EchoProvisionerResponses => { return { + parse: [ + { + parse: {}, + }, + ], plan: [ { - complete: { + plan: { parameters: richParameters, }, }, ], apply: [ { - complete: { + apply: { resources: [ { name: "example", diff --git a/site/e2e/provisionerGenerated.ts b/site/e2e/provisionerGenerated.ts index 66b6c222c9..d79d5b4222 100644 --- a/site/e2e/provisionerGenerated.ts +++ b/site/e2e/provisionerGenerated.ts @@ -21,6 +21,7 @@ export enum AppSharingLevel { UNRECOGNIZED = -1, } +/** WorkspaceTransition is the desired outcome of a build */ export enum WorkspaceTransition { START = 0, STOP = 1, @@ -177,29 +178,8 @@ export interface Resource_Metadata { isNull: boolean } -/** Parse consumes source-code from a directory to produce inputs. */ -export interface Parse {} - -export interface Parse_Request { - directory: string -} - -export interface Parse_Complete { - templateVariables: TemplateVariable[] -} - -export interface Parse_Response { - log?: Log | undefined - complete?: Parse_Complete | undefined -} - -/** - * Provision consumes source-code from a directory to produce resources. - * Exactly one of Plan or Apply must be provided in a single session. - */ -export interface Provision {} - -export interface Provision_Metadata { +/** Metadata is information about a workspace used in the execution of a build */ +export interface Metadata { coderUrl: string workspaceTransition: WorkspaceTransition workspaceName: string @@ -213,49 +193,74 @@ export interface Provision_Metadata { workspaceOwnerSessionToken: string } -/** - * Config represents execution configuration shared by both Plan and - * Apply commands. - */ -export interface Provision_Config { - directory: string +/** Config represents execution configuration shared by all subsequent requests in the Session */ +export interface Config { + /** template_source_archive is a tar of the template source files */ + templateSourceArchive: Uint8Array + /** state is the provisioner state (if any) */ state: Uint8Array - metadata: Provision_Metadata | undefined provisionerLogLevel: string } -export interface Provision_Plan { - config: Provision_Config | undefined +/** ParseRequest consumes source-code to produce inputs. */ +export interface ParseRequest {} + +/** ParseComplete indicates a request to parse completed. */ +export interface ParseComplete { + error: string + templateVariables: TemplateVariable[] + readme: Uint8Array +} + +/** PlanRequest asks the provisioner to plan what resources & parameters it will create */ +export interface PlanRequest { + metadata: Metadata | undefined richParameterValues: RichParameterValue[] variableValues: VariableValue[] gitAuthProviders: GitAuthProvider[] } -export interface Provision_Apply { - config: Provision_Config | undefined - plan: Uint8Array +/** PlanComplete indicates a request to plan completed. */ +export interface PlanComplete { + error: string + resources: Resource[] + parameters: RichParameter[] + gitAuthProviders: string[] } -export interface Provision_Cancel {} - -export interface Provision_Request { - plan?: Provision_Plan | undefined - apply?: Provision_Apply | undefined - cancel?: Provision_Cancel | undefined +/** + * ApplyRequest asks the provisioner to apply the changes. Apply MUST be preceded by a successful plan request/response + * in the same Session. The plan data is not transmitted over the wire and is cached by the provisioner in the Session. + */ +export interface ApplyRequest { + metadata: Metadata | undefined } -export interface Provision_Complete { +/** ApplyComplete indicates a request to apply completed. */ +export interface ApplyComplete { state: Uint8Array error: string resources: Resource[] parameters: RichParameter[] gitAuthProviders: string[] - plan: Uint8Array } -export interface Provision_Response { +/** CancelRequest requests that the previous request be canceled gracefully. */ +export interface CancelRequest {} + +export interface Request { + config?: Config | undefined + parse?: ParseRequest | undefined + plan?: PlanRequest | undefined + apply?: ApplyRequest | undefined + cancel?: CancelRequest | undefined +} + +export interface Response { log?: Log | undefined - complete?: Provision_Complete | undefined + parse?: ParseComplete | undefined + plan?: PlanComplete | undefined + apply?: ApplyComplete | undefined } export const Empty = { @@ -648,60 +653,9 @@ export const Resource_Metadata = { }, } -export const Parse = { - encode(_: Parse, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - return writer - }, -} - -export const Parse_Request = { +export const Metadata = { encode( - message: Parse_Request, - writer: _m0.Writer = _m0.Writer.create(), - ): _m0.Writer { - if (message.directory !== "") { - writer.uint32(10).string(message.directory) - } - return writer - }, -} - -export const Parse_Complete = { - encode( - message: Parse_Complete, - writer: _m0.Writer = _m0.Writer.create(), - ): _m0.Writer { - for (const v of message.templateVariables) { - TemplateVariable.encode(v!, writer.uint32(10).fork()).ldelim() - } - return writer - }, -} - -export const Parse_Response = { - encode( - message: Parse_Response, - writer: _m0.Writer = _m0.Writer.create(), - ): _m0.Writer { - if (message.log !== undefined) { - Log.encode(message.log, writer.uint32(10).fork()).ldelim() - } - if (message.complete !== undefined) { - Parse_Complete.encode(message.complete, writer.uint32(18).fork()).ldelim() - } - return writer - }, -} - -export const Provision = { - encode(_: Provision, writer: _m0.Writer = _m0.Writer.create()): _m0.Writer { - return writer - }, -} - -export const Provision_Metadata = { - encode( - message: Provision_Metadata, + message: Metadata, writer: _m0.Writer = _m0.Writer.create(), ): _m0.Writer { if (message.coderUrl !== "") { @@ -741,96 +695,108 @@ export const Provision_Metadata = { }, } -export const Provision_Config = { +export const Config = { encode( - message: Provision_Config, + message: Config, writer: _m0.Writer = _m0.Writer.create(), ): _m0.Writer { - if (message.directory !== "") { - writer.uint32(10).string(message.directory) + if (message.templateSourceArchive.length !== 0) { + writer.uint32(10).bytes(message.templateSourceArchive) } if (message.state.length !== 0) { writer.uint32(18).bytes(message.state) } - if (message.metadata !== undefined) { - Provision_Metadata.encode( - message.metadata, - writer.uint32(26).fork(), - ).ldelim() - } if (message.provisionerLogLevel !== "") { - writer.uint32(34).string(message.provisionerLogLevel) + writer.uint32(26).string(message.provisionerLogLevel) } return writer }, } -export const Provision_Plan = { +export const ParseRequest = { encode( - message: Provision_Plan, + _: ParseRequest, writer: _m0.Writer = _m0.Writer.create(), ): _m0.Writer { - if (message.config !== undefined) { - Provision_Config.encode(message.config, writer.uint32(10).fork()).ldelim() + return writer + }, +} + +export const ParseComplete = { + encode( + message: ParseComplete, + writer: _m0.Writer = _m0.Writer.create(), + ): _m0.Writer { + if (message.error !== "") { + writer.uint32(10).string(message.error) + } + for (const v of message.templateVariables) { + TemplateVariable.encode(v!, writer.uint32(18).fork()).ldelim() + } + if (message.readme.length !== 0) { + writer.uint32(26).bytes(message.readme) + } + return writer + }, +} + +export const PlanRequest = { + encode( + message: PlanRequest, + writer: _m0.Writer = _m0.Writer.create(), + ): _m0.Writer { + if (message.metadata !== undefined) { + Metadata.encode(message.metadata, writer.uint32(10).fork()).ldelim() } for (const v of message.richParameterValues) { - RichParameterValue.encode(v!, writer.uint32(26).fork()).ldelim() + RichParameterValue.encode(v!, writer.uint32(18).fork()).ldelim() } for (const v of message.variableValues) { - VariableValue.encode(v!, writer.uint32(34).fork()).ldelim() + VariableValue.encode(v!, writer.uint32(26).fork()).ldelim() } for (const v of message.gitAuthProviders) { - GitAuthProvider.encode(v!, writer.uint32(42).fork()).ldelim() + GitAuthProvider.encode(v!, writer.uint32(34).fork()).ldelim() } return writer }, } -export const Provision_Apply = { +export const PlanComplete = { encode( - message: Provision_Apply, + message: PlanComplete, writer: _m0.Writer = _m0.Writer.create(), ): _m0.Writer { - if (message.config !== undefined) { - Provision_Config.encode(message.config, writer.uint32(10).fork()).ldelim() + if (message.error !== "") { + writer.uint32(10).string(message.error) } - if (message.plan.length !== 0) { - writer.uint32(18).bytes(message.plan) + for (const v of message.resources) { + Resource.encode(v!, writer.uint32(18).fork()).ldelim() + } + for (const v of message.parameters) { + RichParameter.encode(v!, writer.uint32(26).fork()).ldelim() + } + for (const v of message.gitAuthProviders) { + writer.uint32(34).string(v!) } return writer }, } -export const Provision_Cancel = { +export const ApplyRequest = { encode( - _: Provision_Cancel, + message: ApplyRequest, writer: _m0.Writer = _m0.Writer.create(), ): _m0.Writer { - return writer - }, -} - -export const Provision_Request = { - encode( - message: Provision_Request, - writer: _m0.Writer = _m0.Writer.create(), - ): _m0.Writer { - if (message.plan !== undefined) { - Provision_Plan.encode(message.plan, writer.uint32(10).fork()).ldelim() - } - if (message.apply !== undefined) { - Provision_Apply.encode(message.apply, writer.uint32(18).fork()).ldelim() - } - if (message.cancel !== undefined) { - Provision_Cancel.encode(message.cancel, writer.uint32(26).fork()).ldelim() + if (message.metadata !== undefined) { + Metadata.encode(message.metadata, writer.uint32(10).fork()).ldelim() } return writer }, } -export const Provision_Complete = { +export const ApplyComplete = { encode( - message: Provision_Complete, + message: ApplyComplete, writer: _m0.Writer = _m0.Writer.create(), ): _m0.Writer { if (message.state.length !== 0) { @@ -848,34 +814,76 @@ export const Provision_Complete = { for (const v of message.gitAuthProviders) { writer.uint32(42).string(v!) } - if (message.plan.length !== 0) { - writer.uint32(50).bytes(message.plan) + return writer + }, +} + +export const CancelRequest = { + encode( + _: CancelRequest, + writer: _m0.Writer = _m0.Writer.create(), + ): _m0.Writer { + return writer + }, +} + +export const Request = { + encode( + message: Request, + writer: _m0.Writer = _m0.Writer.create(), + ): _m0.Writer { + if (message.config !== undefined) { + Config.encode(message.config, writer.uint32(10).fork()).ldelim() + } + if (message.parse !== undefined) { + ParseRequest.encode(message.parse, writer.uint32(18).fork()).ldelim() + } + if (message.plan !== undefined) { + PlanRequest.encode(message.plan, writer.uint32(26).fork()).ldelim() + } + if (message.apply !== undefined) { + ApplyRequest.encode(message.apply, writer.uint32(34).fork()).ldelim() + } + if (message.cancel !== undefined) { + CancelRequest.encode(message.cancel, writer.uint32(42).fork()).ldelim() } return writer }, } -export const Provision_Response = { +export const Response = { encode( - message: Provision_Response, + message: Response, writer: _m0.Writer = _m0.Writer.create(), ): _m0.Writer { if (message.log !== undefined) { Log.encode(message.log, writer.uint32(10).fork()).ldelim() } - if (message.complete !== undefined) { - Provision_Complete.encode( - message.complete, - writer.uint32(18).fork(), - ).ldelim() + if (message.parse !== undefined) { + ParseComplete.encode(message.parse, writer.uint32(18).fork()).ldelim() + } + if (message.plan !== undefined) { + PlanComplete.encode(message.plan, writer.uint32(26).fork()).ldelim() + } + if (message.apply !== undefined) { + ApplyComplete.encode(message.apply, writer.uint32(34).fork()).ldelim() } return writer }, } export interface Provisioner { - Parse(request: Parse_Request): Observable - Provision( - request: Observable, - ): Observable + /** + * Session represents provisioning a single template import or workspace. The daemon always sends Config followed + * by one of the requests (ParseRequest, PlanRequest, ApplyRequest). The provisioner should respond with a stream + * of zero or more Logs, followed by the corresponding complete message (ParseComplete, PlanComplete, + * ApplyComplete). The daemon may then send a new request. A request to apply MUST be preceded by a request plan, + * and the provisioner should store the plan data on the Session after a successful plan, so that the daemon may + * request an apply. If the daemon closes the Session without an apply, the plan data may be safely discarded. + * + * The daemon may send a CancelRequest, asynchronously to ask the provisioner to cancel the previous ParseRequest, + * PlanRequest, or ApplyRequest. The provisioner MUST reply with a complete message corresponding to the request + * that was canceled. If the provisioner has already completed the request, it may ignore the CancelRequest. + */ + Session(request: Observable): Observable } diff --git a/site/e2e/tests/app.spec.ts b/site/e2e/tests/app.spec.ts index b3646fbac1..aa69475dc8 100644 --- a/site/e2e/tests/app.spec.ts +++ b/site/e2e/tests/app.spec.ts @@ -20,7 +20,7 @@ test("app", async ({ context, page }) => { const template = await createTemplate(page, { apply: [ { - complete: { + apply: { resources: [ { agents: [ diff --git a/site/e2e/tests/createWorkspace.spec.ts b/site/e2e/tests/createWorkspace.spec.ts index 10630e2f46..1effc01976 100644 --- a/site/e2e/tests/createWorkspace.spec.ts +++ b/site/e2e/tests/createWorkspace.spec.ts @@ -21,7 +21,7 @@ test("create workspace", async ({ page }) => { const template = await createTemplate(page, { apply: [ { - complete: { + apply: { resources: [ { name: "example", diff --git a/site/e2e/tests/outdatedAgent.spec.ts b/site/e2e/tests/outdatedAgent.spec.ts index 2b88ea7111..e10c3f6edb 100644 --- a/site/e2e/tests/outdatedAgent.spec.ts +++ b/site/e2e/tests/outdatedAgent.spec.ts @@ -15,7 +15,7 @@ test("ssh with agent " + agentVersion, async ({ page }) => { const template = await createTemplate(page, { apply: [ { - complete: { + apply: { resources: [ { agents: [ diff --git a/site/e2e/tests/outdatedCLI.spec.ts b/site/e2e/tests/outdatedCLI.spec.ts index ab143bad27..1b09fccf5e 100644 --- a/site/e2e/tests/outdatedCLI.spec.ts +++ b/site/e2e/tests/outdatedCLI.spec.ts @@ -15,7 +15,7 @@ test("ssh with client " + clientVersion, async ({ page }) => { const template = await createTemplate(page, { apply: [ { - complete: { + apply: { resources: [ { agents: [ diff --git a/site/e2e/tests/webTerminal.spec.ts b/site/e2e/tests/webTerminal.spec.ts index 492634b293..8869d352d3 100644 --- a/site/e2e/tests/webTerminal.spec.ts +++ b/site/e2e/tests/webTerminal.spec.ts @@ -7,7 +7,7 @@ test("web terminal", async ({ context, page }) => { const template = await createTemplate(page, { apply: [ { - complete: { + apply: { resources: [ { agents: [