diff --git a/cli/cliui/parameter.go b/cli/cliui/parameter.go index 28e0c08e785ce..e19e09671dada 100644 --- a/cli/cliui/parameter.go +++ b/cli/cliui/parameter.go @@ -60,3 +60,56 @@ func ParameterSchema(cmd *cobra.Command, parameterSchema codersdk.ParameterSchem return value, nil } + +func RichParameter(cmd *cobra.Command, templateVersionParameter codersdk.TemplateVersionParameter) (string, error) { + _, _ = fmt.Fprintln(cmd.OutOrStdout(), Styles.Bold.Render(templateVersionParameter.Name)) + if templateVersionParameter.Description != "" { + _, _ = fmt.Fprintln(cmd.OutOrStdout(), " "+strings.TrimSpace(strings.Join(strings.Split(templateVersionParameter.Description, "\n"), "\n "))+"\n") + } + + // TODO Implement full validation and show descriptions. + var err error + var value string + if len(templateVersionParameter.Options) > 0 { + // Move the cursor up a single line for nicer display! + _, _ = fmt.Fprint(cmd.OutOrStdout(), "\033[1A") + value, err = Select(cmd, SelectOptions{ + Options: templateVersionParameterOptionValues(templateVersionParameter), + Default: templateVersionParameter.DefaultValue, + HideSearch: true, + }) + if err == nil { + _, _ = fmt.Fprintln(cmd.OutOrStdout()) + _, _ = fmt.Fprintln(cmd.OutOrStdout(), " "+Styles.Prompt.String()+Styles.Field.Render(value)) + } + } else { + text := "Enter a value" + if templateVersionParameter.DefaultValue != "" { + text += fmt.Sprintf(" (default: %q)", templateVersionParameter.DefaultValue) + } + text += ":" + + value, err = Prompt(cmd, PromptOptions{ + Text: Styles.Bold.Render(text), + }) + value = strings.TrimSpace(value) + } + if err != nil { + return "", err + } + + // If they didn't specify anything, use the default value if set. + if len(templateVersionParameter.Options) == 0 && value == "" { + value = templateVersionParameter.DefaultValue + } + + return value, nil +} + +func templateVersionParameterOptionValues(param codersdk.TemplateVersionParameter) []string { + var options []string + for _, opt := range param.Options { + options = append(options, opt.Value) + } + return options +} diff --git a/cli/create.go b/cli/create.go index 854ba78565c51..2c4d20e3a74e2 100644 --- a/cli/create.go +++ b/cli/create.go @@ -17,11 +17,12 @@ import ( func create() *cobra.Command { var ( - parameterFile string - templateName string - startAt string - stopAfter time.Duration - workspaceName string + parameterFile string + richParameterFile string + templateName string + startAt string + stopAfter time.Duration + workspaceName string ) cmd := &cobra.Command{ Annotations: workspaceCommand, @@ -121,11 +122,12 @@ func create() *cobra.Command { schedSpec = ptr.Ref(sched.String()) } - parameters, err := prepWorkspaceBuild(cmd, client, prepWorkspaceBuildArgs{ - Template: template, - ExistingParams: []codersdk.Parameter{}, - ParameterFile: parameterFile, - NewWorkspaceName: workspaceName, + buildParams, err := prepWorkspaceBuild(cmd, client, prepWorkspaceBuildArgs{ + Template: template, + ExistingParams: []codersdk.Parameter{}, + ParameterFile: parameterFile, + RichParameterFile: richParameterFile, + NewWorkspaceName: workspaceName, }) if err != nil { return err @@ -140,11 +142,12 @@ func create() *cobra.Command { } workspace, err := client.CreateWorkspace(cmd.Context(), organization.ID, codersdk.Me, codersdk.CreateWorkspaceRequest{ - TemplateID: template.ID, - Name: workspaceName, - AutostartSchedule: schedSpec, - TTLMillis: ptr.Ref(stopAfter.Milliseconds()), - ParameterValues: parameters, + TemplateID: template.ID, + Name: workspaceName, + AutostartSchedule: schedSpec, + TTLMillis: ptr.Ref(stopAfter.Milliseconds()), + ParameterValues: buildParams.parameters, + RichParameterValues: buildParams.richParameters, }) if err != nil { return err @@ -163,26 +166,40 @@ func create() *cobra.Command { cliui.AllowSkipPrompt(cmd) cliflag.StringVarP(cmd.Flags(), &templateName, "template", "t", "CODER_TEMPLATE_NAME", "", "Specify a template name.") cliflag.StringVarP(cmd.Flags(), ¶meterFile, "parameter-file", "", "CODER_PARAMETER_FILE", "", "Specify a file path with parameter values.") + cliflag.StringVarP(cmd.Flags(), &richParameterFile, "rich-parameter-file", "", "CODER_RICH_PARAMETER_FILE", "", "Specify a file path with values for rich parameters defined in the template.") cliflag.StringVarP(cmd.Flags(), &startAt, "start-at", "", "CODER_WORKSPACE_START_AT", "", "Specify the workspace autostart schedule. Check `coder schedule start --help` for the syntax.") cliflag.DurationVarP(cmd.Flags(), &stopAfter, "stop-after", "", "CODER_WORKSPACE_STOP_AFTER", 8*time.Hour, "Specify a duration after which the workspace should shut down (e.g. 8h).") return cmd } type prepWorkspaceBuildArgs struct { - Template codersdk.Template - ExistingParams []codersdk.Parameter - ParameterFile string - NewWorkspaceName string + Template codersdk.Template + ExistingParams []codersdk.Parameter + ParameterFile string + ExistingRichParams []codersdk.WorkspaceBuildParameter + RichParameterFile string + NewWorkspaceName string + + UpdateWorkspace bool +} + +type buildParameters struct { + // Parameters contains legacy parameters stored in /parameters. + parameters []codersdk.CreateParameterRequest + // Rich parameters stores values for build parameters annotated with description, icon, type, etc. + richParameters []codersdk.WorkspaceBuildParameter } // prepWorkspaceBuild will ensure a workspace build will succeed on the latest template version. -// Any missing params will be prompted to the user. -func prepWorkspaceBuild(cmd *cobra.Command, client *codersdk.Client, args prepWorkspaceBuildArgs) ([]codersdk.CreateParameterRequest, error) { +// Any missing params will be prompted to the user. It supports legacy and rich parameters. +func prepWorkspaceBuild(cmd *cobra.Command, client *codersdk.Client, args prepWorkspaceBuildArgs) (*buildParameters, error) { ctx := cmd.Context() templateVersion, err := client.TemplateVersion(ctx, args.Template.ActiveVersionID) if err != nil { return nil, err } + + // Legacy parameters parameterSchemas, err := client.TemplateVersionSchema(ctx, templateVersion.ID) if err != nil { return nil, err @@ -200,7 +217,7 @@ func prepWorkspaceBuild(cmd *cobra.Command, client *codersdk.Client, args prepWo } } disclaimerPrinted := false - parameters := make([]codersdk.CreateParameterRequest, 0) + legacyParameters := make([]codersdk.CreateParameterRequest, 0) PromptParamLoop: for _, parameterSchema := range parameterSchemas { if !parameterSchema.AllowOverrideSource { @@ -227,19 +244,76 @@ PromptParamLoop: return nil, err } - parameters = append(parameters, codersdk.CreateParameterRequest{ + legacyParameters = append(legacyParameters, codersdk.CreateParameterRequest{ Name: parameterSchema.Name, SourceValue: parameterValue, SourceScheme: codersdk.ParameterSourceSchemeData, DestinationScheme: parameterSchema.DefaultDestinationScheme, }) } - _, _ = fmt.Fprintln(cmd.OutOrStdout()) + + if disclaimerPrinted { + _, _ = fmt.Fprintln(cmd.OutOrStdout()) + } + + // Rich parameters + templateVersionParameters, err := client.TemplateVersionRichParameters(cmd.Context(), templateVersion.ID) + if err != nil { + return nil, xerrors.Errorf("get template version rich parameters: %w", err) + } + + parameterMapFromFile = map[string]string{} + useParamFile = false + if args.RichParameterFile != "" { + useParamFile = true + _, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Paragraph.Render("Attempting to read the variables from the rich parameter file.")+"\r\n") + parameterMapFromFile, err = createParameterMapFromFile(args.RichParameterFile) + if err != nil { + return nil, err + } + } + disclaimerPrinted = false + richParameters := make([]codersdk.WorkspaceBuildParameter, 0) +PromptRichParamLoop: + for _, templateVersionParameter := range templateVersionParameters { + if !disclaimerPrinted { + _, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Paragraph.Render("This template has customizable parameters. Values can be changed after create, but may have unintended side effects (like data loss).")+"\r\n") + disclaimerPrinted = true + } + + // Param file is all or nothing + if !useParamFile { + for _, e := range args.ExistingRichParams { + if e.Name == templateVersionParameter.Name { + // If the param already exists, we do not need to prompt it again. + // The workspace scope will reuse params for each build. + continue PromptRichParamLoop + } + } + } + + if args.UpdateWorkspace && !templateVersionParameter.Mutable { + _, _ = fmt.Fprintln(cmd.OutOrStdout(), cliui.Styles.Warn.Render(fmt.Sprintf(`Parameter %q is not mutable, so can't be customized after workspace creation.`, templateVersionParameter.Name))) + continue + } + + parameterValue, err := getWorkspaceBuildParameterValueFromMapOrInput(cmd, parameterMapFromFile, templateVersionParameter) + if err != nil { + return nil, err + } + + richParameters = append(richParameters, *parameterValue) + } + + if disclaimerPrinted { + _, _ = fmt.Fprintln(cmd.OutOrStdout()) + } // Run a dry-run with the given parameters to check correctness dryRun, err := client.CreateTemplateVersionDryRun(cmd.Context(), templateVersion.ID, codersdk.CreateTemplateVersionDryRunRequest{ - WorkspaceName: args.NewWorkspaceName, - ParameterValues: parameters, + WorkspaceName: args.NewWorkspaceName, + ParameterValues: legacyParameters, + RichParameterValues: richParameters, }) if err != nil { return nil, xerrors.Errorf("begin workspace dry-run: %w", err) @@ -279,5 +353,8 @@ PromptParamLoop: return nil, err } - return parameters, nil + return &buildParameters{ + parameters: legacyParameters, + richParameters: richParameters, + }, nil } diff --git a/cli/create_test.go b/cli/create_test.go index 616ec3775d854..03552dbd9bd43 100644 --- a/cli/create_test.go +++ b/cli/create_test.go @@ -321,6 +321,124 @@ func TestCreate(t *testing.T) { }) } +func TestCreateWithRichParameters(t *testing.T) { + t.Parallel() + + const ( + firstParameterName = "first_parameter" + firstParameterDescription = "This is first parameter" + firstParameterValue = "1" + + secondParameterName = "second_parameter" + secondParameterDescription = "This is second parameter" + secondParameterValue = "2" + + immutableParameterName = "third_parameter" + immutableParameterDescription = "This is not mutable parameter" + immutableParameterValue = "3" + ) + + 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, Description: secondParameterDescription, Mutable: true}, + {Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false}, + }, + }, + }, + }}, + ProvisionApply: []*proto.Provision_Response{{ + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{}, + }, + }}, + } + + t.Run("InputParameters", func(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, echoResponses) + coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + + cmd, root := clitest.New(t, "create", "my-workspace", "--template", template.Name) + clitest.SetupConfig(t, client, root) + doneChan := make(chan struct{}) + pty := ptytest.New(t) + cmd.SetIn(pty.Input()) + cmd.SetOut(pty.Output()) + go func() { + defer close(doneChan) + err := cmd.Execute() + assert.NoError(t, err) + }() + + matches := []string{ + firstParameterDescription, firstParameterValue, + secondParameterDescription, secondParameterValue, + immutableParameterDescription, immutableParameterValue, + "Confirm create?", "yes", + } + for i := 0; i < len(matches); i += 2 { + match := matches[i] + value := matches[i+1] + pty.ExpectMatch(match) + pty.WriteLine(value) + } + <-doneChan + }) + + t.Run("RichParametersFile", func(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, echoResponses) + coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + + tempDir := t.TempDir() + removeTmpDirUntilSuccessAfterTest(t, tempDir) + parameterFile, _ := os.CreateTemp(tempDir, "testParameterFile*.yaml") + _, _ = parameterFile.WriteString( + firstParameterName + ": " + firstParameterValue + "\n" + + secondParameterName + ": " + secondParameterValue + "\n" + + immutableParameterName + ": " + immutableParameterValue) + cmd, root := clitest.New(t, "create", "my-workspace", "--template", template.Name, "--rich-parameter-file", parameterFile.Name()) + clitest.SetupConfig(t, client, root) + + doneChan := make(chan struct{}) + pty := ptytest.New(t) + cmd.SetIn(pty.Input()) + cmd.SetOut(pty.Output()) + go func() { + defer close(doneChan) + err := cmd.Execute() + assert.NoError(t, err) + }() + + matches := []string{ + "Confirm create?", "yes", + } + for i := 0; i < len(matches); i += 2 { + match := matches[i] + value := matches[i+1] + pty.ExpectMatch(match) + pty.WriteLine(value) + } + <-doneChan + }) +} + func createTestParseResponseWithDefault(defaultValue string) []*proto.Parse_Response { return []*proto.Parse_Response{{ Type: &proto.Parse_Response_Complete{ diff --git a/cli/parameter.go b/cli/parameter.go index 3fe065b057e9a..127ac58cf5cd5 100644 --- a/cli/parameter.go +++ b/cli/parameter.go @@ -3,11 +3,10 @@ package cli import ( "os" + "github.com/spf13/cobra" "golang.org/x/xerrors" "gopkg.in/yaml.v3" - "github.com/spf13/cobra" - "github.com/coder/coder/cli/cliui" "github.com/coder/coder/codersdk" ) @@ -58,3 +57,27 @@ func getParameterValueFromMapOrInput(cmd *cobra.Command, parameterMap map[string } return parameterValue, nil } + +func getWorkspaceBuildParameterValueFromMapOrInput(cmd *cobra.Command, parameterMap map[string]string, templateVersionParameter codersdk.TemplateVersionParameter) (*codersdk.WorkspaceBuildParameter, error) { + var parameterValue string + var err error + if parameterMap != nil { + var ok bool + parameterValue, ok = parameterMap[templateVersionParameter.Name] + if !ok { + parameterValue, err = cliui.RichParameter(cmd, templateVersionParameter) + if err != nil { + return nil, err + } + } + } else { + parameterValue, err = cliui.RichParameter(cmd, templateVersionParameter) + if err != nil { + return nil, err + } + } + return &codersdk.WorkspaceBuildParameter{ + Name: templateVersionParameter.Name, + Value: parameterValue, + }, nil +} diff --git a/cli/testdata/coder_create_--help.golden b/cli/testdata/coder_create_--help.golden index 1d4d1ea2bf25a..52aaff8d1a053 100644 --- a/cli/testdata/coder_create_--help.golden +++ b/cli/testdata/coder_create_--help.golden @@ -7,6 +7,9 @@ Flags: -h, --help help for create --parameter-file string Specify a file path with parameter values. Consumes $CODER_PARAMETER_FILE + --rich-parameter-file string Specify a file path with values for rich + parameters defined in the template. + Consumes $CODER_RICH_PARAMETER_FILE --start-at coder schedule start --help Specify the workspace autostart schedule. Check coder schedule start --help for the syntax. Consumes $CODER_WORKSPACE_START_AT diff --git a/cli/testdata/coder_update_--help.golden b/cli/testdata/coder_update_--help.golden index b6c46a328b24e..3f037ec8348e8 100644 --- a/cli/testdata/coder_update_--help.golden +++ b/cli/testdata/coder_update_--help.golden @@ -4,11 +4,14 @@ Usage: coder update [flags] Flags: - --always-prompt Always prompt all parameters. Does not pull parameter values - from existing workspace - -h, --help help for update - --parameter-file string Specify a file path with parameter values. - Consumes $CODER_PARAMETER_FILE + --always-prompt Always prompt all parameters. Does not pull parameter + values from existing workspace + -h, --help help for update + --parameter-file string Specify a file path with parameter values. + Consumes $CODER_PARAMETER_FILE + --rich-parameter-file string Specify a file path with values for rich parameters + defined in the template. + Consumes $CODER_RICH_PARAMETER_FILE Global Flags: --global-config coder Path to the global coder config directory. diff --git a/cli/update.go b/cli/update.go index d419cac9389c4..9e23ee73569dd 100644 --- a/cli/update.go +++ b/cli/update.go @@ -11,8 +11,9 @@ import ( func update() *cobra.Command { var ( - parameterFile string - alwaysPrompt bool + parameterFile string + richParameterFile string + alwaysPrompt bool ) cmd := &cobra.Command{ @@ -39,27 +40,37 @@ func update() *cobra.Command { } var existingParams []codersdk.Parameter + var existingRichParams []codersdk.WorkspaceBuildParameter if !alwaysPrompt { existingParams, err = client.Parameters(cmd.Context(), codersdk.ParameterWorkspace, workspace.ID) if err != nil { return nil } + + existingRichParams, err = client.WorkspaceBuildParameters(cmd.Context(), workspace.LatestBuild.ID) + if err != nil { + return nil + } } - parameters, err := prepWorkspaceBuild(cmd, client, prepWorkspaceBuildArgs{ - Template: template, - ExistingParams: existingParams, - ParameterFile: parameterFile, - NewWorkspaceName: workspace.Name, + buildParams, err := prepWorkspaceBuild(cmd, client, prepWorkspaceBuildArgs{ + Template: template, + ExistingParams: existingParams, + ParameterFile: parameterFile, + ExistingRichParams: existingRichParams, + RichParameterFile: richParameterFile, + NewWorkspaceName: workspace.Name, + UpdateWorkspace: true, }) if err != nil { return nil } build, err := client.CreateWorkspaceBuild(cmd.Context(), workspace.ID, codersdk.CreateWorkspaceBuildRequest{ - TemplateVersionID: template.ActiveVersionID, - Transition: workspace.LatestBuild.Transition, - ParameterValues: parameters, + TemplateVersionID: template.ActiveVersionID, + Transition: workspace.LatestBuild.Transition, + ParameterValues: buildParams.parameters, + RichParameterValues: buildParams.richParameters, }) if err != nil { return err @@ -82,5 +93,6 @@ func update() *cobra.Command { cmd.Flags().BoolVar(&alwaysPrompt, "always-prompt", false, "Always prompt all parameters. Does not pull parameter values from existing workspace") cliflag.StringVarP(cmd.Flags(), ¶meterFile, "parameter-file", "", "CODER_PARAMETER_FILE", "", "Specify a file path with parameter values.") + cliflag.StringVarP(cmd.Flags(), &richParameterFile, "rich-parameter-file", "", "CODER_RICH_PARAMETER_FILE", "", "Specify a file path with values for rich parameters defined in the template.") return cmd } diff --git a/cli/update_test.go b/cli/update_test.go index 73a30544d5ef6..250e768d48580 100644 --- a/cli/update_test.go +++ b/cli/update_test.go @@ -3,6 +3,7 @@ package cli_test import ( "context" "fmt" + "os" "testing" "github.com/stretchr/testify/assert" @@ -12,6 +13,7 @@ import ( "github.com/coder/coder/coderd/coderdtest" "github.com/coder/coder/codersdk" "github.com/coder/coder/provisioner/echo" + "github.com/coder/coder/provisionersdk/proto" "github.com/coder/coder/pty/ptytest" ) @@ -139,3 +141,94 @@ func TestUpdate(t *testing.T) { <-doneChan }) } + +func TestUpdateWithRichParameters(t *testing.T) { + t.Parallel() + + const ( + firstParameterName = "first_parameter" + firstParameterDescription = "This is first parameter" + firstParameterValue = "1" + + secondParameterName = "second_parameter" + secondParameterDescription = "This is second parameter" + secondParameterValue = "2" + + immutableParameterName = "immutable_parameter" + immutableParameterDescription = "This is not mutable parameter" + immutableParameterValue = "3" + ) + + 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}, + }, + }, + }, + }}, + ProvisionApply: []*proto.Provision_Response{{ + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{}, + }, + }}, + } + + t.Run("ImmutableCannotBeCustomized", func(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, echoResponses) + coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + + tempDir := t.TempDir() + removeTmpDirUntilSuccessAfterTest(t, tempDir) + parameterFile, _ := os.CreateTemp(tempDir, "testParameterFile*.yaml") + _, _ = parameterFile.WriteString( + firstParameterName + ": " + firstParameterValue + "\n" + + immutableParameterName + ": " + immutableParameterValue + "\n" + + secondParameterName + ": " + secondParameterValue) + + cmd, root := clitest.New(t, "create", "my-workspace", "--template", template.Name, "--rich-parameter-file", parameterFile.Name(), "-y") + clitest.SetupConfig(t, client, root) + err := cmd.Execute() + assert.NoError(t, err) + + cmd, root = clitest.New(t, "update", "my-workspace", "--always-prompt") + clitest.SetupConfig(t, client, root) + + doneChan := make(chan struct{}) + pty := ptytest.New(t) + cmd.SetIn(pty.Input()) + cmd.SetOut(pty.Output()) + go func() { + defer close(doneChan) + err := cmd.Execute() + assert.NoError(t, err) + }() + + matches := []string{ + firstParameterDescription, firstParameterValue, + fmt.Sprintf("Parameter %q is not mutable, so can't be customized after workspace creation.", immutableParameterName), "", + secondParameterDescription, secondParameterValue, + } + for i := 0; i < len(matches); i += 2 { + match := matches[i] + value := matches[i+1] + pty.ExpectMatch(match) + if value != "" { + pty.WriteLine(value) + } + } + <-doneChan + }) +} diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 1ec2452a6da59..c7b08e9ac0e3e 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -5519,6 +5519,12 @@ const docTemplate = `{ "$ref": "#/definitions/codersdk.CreateParameterRequest" } }, + "rich_parameter_values": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.WorkspaceBuildParameter" + } + }, "workspace_name": { "type": "string" } diff --git a/coderd/apidoc/swagger.json b/coderd/apidoc/swagger.json index 33dfd90093f52..23ef9e49cfd53 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -4889,6 +4889,12 @@ "$ref": "#/definitions/codersdk.CreateParameterRequest" } }, + "rich_parameter_values": { + "type": "array", + "items": { + "$ref": "#/definitions/codersdk.WorkspaceBuildParameter" + } + }, "workspace_name": { "type": "string" } diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index ebed06dd1b5bc..9f5ffa68f0e0a 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -235,7 +235,8 @@ func (server *Server) AcquireJob(ctx context.Context, _ *proto.Empty) (*proto.Ac protoJob.Type = &proto.AcquiredJob_TemplateDryRun_{ TemplateDryRun: &proto.AcquiredJob_TemplateDryRun{ - ParameterValues: protoParameters, + ParameterValues: protoParameters, + RichParameterValues: convertRichParameterValues(input.RichParameterValues), Metadata: &sdkproto.Provision_Metadata{ CoderUrl: server.AccessURL.String(), WorkspaceName: input.WorkspaceName, @@ -1175,9 +1176,10 @@ type WorkspaceProvisionJob struct { // TemplateVersionDryRunJob is the payload for the "template_version_dry_run" job type. type TemplateVersionDryRunJob struct { - TemplateVersionID uuid.UUID `json:"template_version_id"` - WorkspaceName string `json:"workspace_name"` - ParameterValues []database.ParameterValue `json:"parameter_values"` + TemplateVersionID uuid.UUID `json:"template_version_id"` + WorkspaceName string `json:"workspace_name"` + ParameterValues []database.ParameterValue `json:"parameter_values"` + RichParameterValues []database.WorkspaceBuildParameter `json:"rich_parameter_values"` } // ProvisionerJobLogsNotifyMessage is the payload published on diff --git a/coderd/templateversions.go b/coderd/templateversions.go index dc4fd16b401b6..b4fcddaf6ac54 100644 --- a/coderd/templateversions.go +++ b/coderd/templateversions.go @@ -362,12 +362,22 @@ func (api *API) postTemplateVersionDryRun(rw http.ResponseWriter, r *http.Reques } } + richParameterValues := make([]database.WorkspaceBuildParameter, len(req.RichParameterValues)) + for i, v := range req.RichParameterValues { + richParameterValues[i] = database.WorkspaceBuildParameter{ + WorkspaceBuildID: uuid.Nil, + Name: v.Name, + Value: v.Value, + } + } + // Marshal template version dry-run job with the parameters from the // request. input, err := json.Marshal(provisionerdserver.TemplateVersionDryRunJob{ - TemplateVersionID: templateVersion.ID, - WorkspaceName: req.WorkspaceName, - ParameterValues: parameterValues, + TemplateVersionID: templateVersion.ID, + WorkspaceName: req.WorkspaceName, + ParameterValues: parameterValues, + RichParameterValues: richParameterValues, }) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index f62b82a07b63a..b663ec729042f 100644 --- a/coderd/workspacebuilds.go +++ b/coderd/workspacebuilds.go @@ -377,11 +377,6 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { state = createBuild.ProvisionerState } - var parameters []codersdk.WorkspaceBuildParameter - if createBuild.RichParameterValues != nil { - parameters = createBuild.RichParameterValues - } - if createBuild.Orphan { if createBuild.Transition != codersdk.WorkspaceTransitionDelete { httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ @@ -454,21 +449,42 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { state = priorHistory.ProvisionerState } - if parameters == nil { - buildParameters, err := api.Database.GetWorkspaceBuildParameters(ctx, priorHistory.ID) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error fetching prior workspace build parameters.", - Detail: err.Error(), - }) - return + templateVersionParameters, err := api.Database.GetTemplateVersionParameters(ctx, createBuild.TemplateVersionID) + if err != nil { + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Internal error fetching template version parameters.", + Detail: err.Error(), + }) + return + } + + lastBuildParameters, err := api.Database.GetWorkspaceBuildParameters(ctx, priorHistory.ID) + if err != nil { + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Internal error fetching prior workspace build parameters.", + Detail: err.Error(), + }) + return + } + apiLastBuildParameters := convertWorkspaceBuildParameters(lastBuildParameters) + + var parameters []codersdk.WorkspaceBuildParameter + for _, templateVersionParameter := range templateVersionParameters { + // Check if parameter value is in request + if buildParameter, found := findWorkspaceBuildParameter(createBuild.RichParameterValues, templateVersionParameter.Name); found { + if !templateVersionParameter.Mutable { + httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ + Message: fmt.Sprintf("Parameter %q is mutable, so it can't be updated after creating workspace.", templateVersionParameter.Name), + }) + return + } + parameters = append(parameters, *buildParameter) + continue } - parameters = make([]codersdk.WorkspaceBuildParameter, 0, len(buildParameters)) - for _, param := range buildParameters { - parameters = append(parameters, codersdk.WorkspaceBuildParameter{ - Name: param.Name, - Value: param.Value, - }) + + // Check if parameter is defined in previous build + if buildParameter, found := findWorkspaceBuildParameter(apiLastBuildParameters, templateVersionParameter.Name); found { + parameters = append(parameters, *buildParameter) } } @@ -567,7 +583,7 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { Value: values, }) if err != nil { - return xerrors.Errorf("insert workspace build parameter: %w", err) + return xerrors.Errorf("insert workspace build parameters: %w", err) } return nil @@ -1171,3 +1187,12 @@ func convertWorkspaceBuildParameters(parameters []database.WorkspaceBuildParamet } return apiParameters } + +func findWorkspaceBuildParameter(params []codersdk.WorkspaceBuildParameter, parameterName string) (*codersdk.WorkspaceBuildParameter, bool) { + for _, p := range params { + if p.Name == parameterName { + return &p, true + } + } + return nil, false +} diff --git a/coderd/workspacebuilds_test.go b/coderd/workspacebuilds_test.go index b3b446e55f36b..bbdec82b4a30d 100644 --- a/coderd/workspacebuilds_test.go +++ b/coderd/workspacebuilds_test.go @@ -644,11 +644,16 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) { secondParameterName = "second_parameter" secondParameterDescription = "This is second parameter" secondParameterValue = "2" + + immutableParameterName = "immutable_parameter" + immutableParameterDescription = "This is immutable parameter" + immutableParameterValue = "3" ) initialBuildParameters := []codersdk.WorkspaceBuildParameter{ {Name: firstParameterName, Value: firstParameterValue}, {Name: secondParameterName, Value: secondParameterValue}, + {Name: immutableParameterName, Value: immutableParameterValue}, } echoResponses := &echo.Responses{ @@ -658,8 +663,9 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) { Type: &proto.Provision_Response_Complete{ Complete: &proto.Provision_Complete{ Parameters: []*proto.RichParameter{ - {Name: firstParameterName, Description: firstParameterDescription}, - {Name: secondParameterName, Description: secondParameterDescription}, + {Name: firstParameterName, Description: firstParameterDescription, Mutable: true}, + {Name: secondParameterName, Description: secondParameterDescription, Mutable: true}, + {Name: immutableParameterName, Description: immutableParameterDescription, Mutable: false}, }, }, }, @@ -705,7 +711,12 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) { workspaceBuildParameters, err := client.WorkspaceBuildParameters(ctx, nextWorkspaceBuild.ID) require.NoError(t, err) - require.ElementsMatch(t, nextBuildParameters, workspaceBuildParameters) + + expected := append(nextBuildParameters, codersdk.WorkspaceBuildParameter{ + Name: immutableParameterName, + Value: immutableParameterValue, + }) + require.ElementsMatch(t, expected, workspaceBuildParameters) }) t.Run("UsePreviousParameterValues", func(t *testing.T) { t.Parallel() @@ -738,4 +749,34 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) { require.NoError(t, err) require.ElementsMatch(t, initialBuildParameters, workspaceBuildParameters) }) + + t.Run("DoNotModifyImmutables", func(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, echoResponses) + coderdtest.AwaitTemplateVersionJob(t, client, version.ID) + + template := coderdtest.CreateTemplate(t, client, user.OrganizationID, version.ID) + workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) { + cwr.RichParameterValues = initialBuildParameters + }) + + workspaceBuild := coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID) + require.Equal(t, codersdk.WorkspaceStatusRunning, workspaceBuild.Status) + + // Update build parameters + ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong) + defer cancel() + + nextBuildParameters := []codersdk.WorkspaceBuildParameter{ + {Name: immutableParameterName, Value: "BAD"}, + } + _, err := client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ + Transition: codersdk.WorkspaceTransitionStart, + RichParameterValues: nextBuildParameters, + }) + require.Error(t, err) + }) } diff --git a/codersdk/templateversions.go b/codersdk/templateversions.go index c3198934db094..442e85b4e7d25 100644 --- a/codersdk/templateversions.go +++ b/codersdk/templateversions.go @@ -143,8 +143,9 @@ func (c *Client) TemplateVersionLogsAfter(ctx context.Context, version uuid.UUID // CreateTemplateVersionDryRunRequest defines the request parameters for // CreateTemplateVersionDryRun. type CreateTemplateVersionDryRunRequest struct { - WorkspaceName string `json:"workspace_name"` - ParameterValues []CreateParameterRequest `json:"parameter_values"` + WorkspaceName string `json:"workspace_name"` + ParameterValues []CreateParameterRequest `json:"parameter_values"` + RichParameterValues []WorkspaceBuildParameter `json:"rich_parameter_values"` } // CreateTemplateVersionDryRun begins a dry-run provisioner job against the diff --git a/docs/api/schemas.md b/docs/api/schemas.md index d242e8bd22fae..8b86ca483f088 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -760,16 +760,23 @@ CreateParameterRequest is a structure used to create a new parameter value for a "source_value": "string" } ], + "rich_parameter_values": [ + { + "name": "string", + "value": "string" + } + ], "workspace_name": "string" } ``` ### Properties -| Name | Type | Required | Restrictions | Description | -| ------------------ | --------------------------------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------- | -| `parameter_values` | array of [codersdk.CreateParameterRequest](#codersdkcreateparameterrequest) | false | | Parameter values is a structure used to create a new parameter value for a scope.] | -| `workspace_name` | string | false | | | +| Name | Type | Required | Restrictions | Description | +| ----------------------- | ----------------------------------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------- | +| `parameter_values` | array of [codersdk.CreateParameterRequest](#codersdkcreateparameterrequest) | false | | Parameter values is a structure used to create a new parameter value for a scope.] | +| `rich_parameter_values` | array of [codersdk.WorkspaceBuildParameter](#codersdkworkspacebuildparameter) | false | | | +| `workspace_name` | string | false | | | ## codersdk.CreateTestAuditLogRequest diff --git a/docs/api/templates.md b/docs/api/templates.md index 6a2b81d49b973..670ef9f14d931 100644 --- a/docs/api/templates.md +++ b/docs/api/templates.md @@ -406,6 +406,12 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa "source_value": "string" } ], + "rich_parameter_values": [ + { + "name": "string", + "value": "string" + } + ], "workspace_name": "string" } ``` @@ -1291,6 +1297,12 @@ curl -X POST http://coder-server:8080/api/v2/templateversions/{templateversion}/ "source_value": "string" } ], + "rich_parameter_values": [ + { + "name": "string", + "value": "string" + } + ], "workspace_name": "string" } ``` diff --git a/provisioner/terraform/provision.go b/provisioner/terraform/provision.go index a267085126f76..5df40e6807d3f 100644 --- a/provisioner/terraform/provision.go +++ b/provisioner/terraform/provision.go @@ -12,6 +12,7 @@ import ( "github.com/coder/coder/provisionersdk" "github.com/coder/coder/provisionersdk/proto" + "github.com/coder/terraform-provider-coder/provider" ) // Provision executes `terraform apply` or `terraform plan` for dry runs. @@ -138,7 +139,7 @@ func (s *server) Provision(stream proto.DRPCProvisioner_ProvisionStream) error { } s.logger.Debug(ctx, "ran initialization") - env, err := provisionEnv(config, request.GetPlan().GetParameterValues()) + env, err := provisionEnv(config, request.GetPlan().GetParameterValues(), request.GetPlan().GetRichParameterValues()) if err != nil { return err } @@ -204,7 +205,7 @@ func planVars(plan *proto.Provision_Plan) ([]string, error) { return vars, nil } -func provisionEnv(config *proto.Provision_Config, params []*proto.ParameterValue) ([]string, error) { +func provisionEnv(config *proto.Provision_Config, params []*proto.ParameterValue, richParams []*proto.RichParameterValue) ([]string, error) { env := safeEnviron() env = append(env, "CODER_AGENT_URL="+config.Metadata.CoderUrl, @@ -228,6 +229,9 @@ func provisionEnv(config *proto.Provision_Config, params []*proto.ParameterValue return nil, xerrors.Errorf("unsupported parameter type %q for %q", param.DestinationScheme, param.Name) } } + for _, param := range richParams { + env = append(env, provider.ParameterEnvironmentVariable(param.Name)+"="+param.Value) + } return env, nil } diff --git a/provisioner/terraform/provision_test.go b/provisioner/terraform/provision_test.go index a90bbacdffd3b..9eebb422db5da 100644 --- a/provisioner/terraform/provision_test.go +++ b/provisioner/terraform/provision_test.go @@ -320,6 +320,49 @@ func TestProvision(t *testing.T) { }, ErrorContains: "unsupported parameter type", }, + { + Name: "rich-parameter-with-value", + Files: map[string]string{ + "main.tf": `terraform { + required_providers { + coder = { + source = "coder/coder" + version = "0.6.6" + } + } + } + + data "coder_parameter" "example" { + name = "Example" + type = "string" + default = "foobar" + } + + resource "null_resource" "example" { + triggers = { + misc = "${data.coder_parameter.example.value}" + } + }`, + }, + Request: &proto.Provision_Plan{ + RichParameterValues: []*proto.RichParameterValue{ + { + Name: "Example", + Value: "foobaz", + }, + }, + }, + Response: &proto.Provision_Response{ + Type: &proto.Provision_Response_Complete{ + Complete: &proto.Provision_Complete{ + Resources: []*proto.Resource{{ + Name: "example", + Type: "null_resource", + }}, + }, + }, + }, + }, } for _, testCase := range testCases { diff --git a/provisionerd/proto/provisionerd.pb.go b/provisionerd/proto/provisionerd.pb.go index 4ce8743ab4070..a8b741d89987e 100644 --- a/provisionerd/proto/provisionerd.pb.go +++ b/provisionerd/proto/provisionerd.pb.go @@ -924,8 +924,9 @@ type AcquiredJob_TemplateDryRun struct { sizeCache protoimpl.SizeCache unknownFields protoimpl.UnknownFields - ParameterValues []*proto.ParameterValue `protobuf:"bytes,1,rep,name=parameter_values,json=parameterValues,proto3" json:"parameter_values,omitempty"` - Metadata *proto.Provision_Metadata `protobuf:"bytes,2,opt,name=metadata,proto3" json:"metadata,omitempty"` + ParameterValues []*proto.ParameterValue `protobuf:"bytes,1,rep,name=parameter_values,json=parameterValues,proto3" json:"parameter_values,omitempty"` + RichParameterValues []*proto.RichParameterValue `protobuf:"bytes,2,rep,name=rich_parameter_values,json=richParameterValues,proto3" json:"rich_parameter_values,omitempty"` + Metadata *proto.Provision_Metadata `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"` } func (x *AcquiredJob_TemplateDryRun) Reset() { @@ -967,6 +968,13 @@ func (x *AcquiredJob_TemplateDryRun) GetParameterValues() []*proto.ParameterValu return nil } +func (x *AcquiredJob_TemplateDryRun) GetRichParameterValues() []*proto.RichParameterValue { + if x != nil { + return x.RichParameterValues + } + return nil +} + func (x *AcquiredJob_TemplateDryRun) GetMetadata() *proto.Provision_Metadata { if x != nil { return x.Metadata @@ -1271,7 +1279,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, 0x81, 0x08, 0x0a, 0x0b, 0x41, 0x63, 0x71, 0x75, 0x69, + 0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0xd6, 0x08, 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, @@ -1325,156 +1333,161 @@ var file_provisionerd_proto_provisionerd_proto_rawDesc = []byte{ 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, 0x1a, 0x95, 0x01, 0x0a, 0x0e, 0x54, + 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x1a, 0xea, 0x01, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x44, 0x72, 0x79, 0x52, 0x75, 0x6e, 0x12, 0x46, 0x0a, 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, - 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, - 0x61, 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, - 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x86, 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, 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, 0xaa, 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, 0xd3, 0x01, 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, 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, 0xb3, 0x01, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, - 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, - 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, - 0x25, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, - 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x4c, 0x6f, 0x67, - 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x49, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, - 0x74, 0x65, 0x72, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, - 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, - 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, - 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, - 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x0c, 0x52, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x22, 0x77, 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, 0x46, 0x0a, 0x10, 0x70, 0x61, + 0x61, 0x6c, 0x75, 0x65, 0x73, 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, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, - 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, - 0x65, 0x73, 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, 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, 0x2b, 0x5a, - 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, - 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x33, + 0x20, 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, 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, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, + 0x86, 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, 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, 0xaa, 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, 0xd3, 0x01, 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, 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, 0xb3, 0x01, 0x0a, 0x10, 0x55, 0x70, 0x64, + 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, + 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, + 0x6f, 0x62, 0x49, 0x64, 0x12, 0x25, 0x0a, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, + 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x64, 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x04, 0x6c, 0x6f, 0x67, 0x73, 0x12, 0x49, 0x0a, 0x11, 0x70, + 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, + 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x63, + 0x68, 0x65, 0x6d, 0x61, 0x52, 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, + 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, 0x61, 0x64, 0x6d, 0x65, 0x22, 0x77, + 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, + 0x46, 0x0a, 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, + 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, + 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, + 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 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, 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, 0x2b, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, + 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -1539,27 +1552,28 @@ var file_provisionerd_proto_provisionerd_proto_depIdxs = []int32{ 23, // 16: provisionerd.AcquiredJob.WorkspaceBuild.metadata:type_name -> provisioner.Provision.Metadata 23, // 17: provisionerd.AcquiredJob.TemplateImport.metadata:type_name -> provisioner.Provision.Metadata 21, // 18: provisionerd.AcquiredJob.TemplateDryRun.parameter_values:type_name -> provisioner.ParameterValue - 23, // 19: provisionerd.AcquiredJob.TemplateDryRun.metadata:type_name -> provisioner.Provision.Metadata - 24, // 20: provisionerd.CompletedJob.WorkspaceBuild.resources:type_name -> provisioner.Resource - 24, // 21: provisionerd.CompletedJob.TemplateImport.start_resources:type_name -> provisioner.Resource - 24, // 22: provisionerd.CompletedJob.TemplateImport.stop_resources:type_name -> provisioner.Resource - 25, // 23: provisionerd.CompletedJob.TemplateImport.rich_parameters:type_name -> provisioner.RichParameter - 24, // 24: provisionerd.CompletedJob.TemplateDryRun.resources:type_name -> provisioner.Resource - 1, // 25: provisionerd.ProvisionerDaemon.AcquireJob:input_type -> provisionerd.Empty - 8, // 26: provisionerd.ProvisionerDaemon.CommitQuota:input_type -> provisionerd.CommitQuotaRequest - 6, // 27: provisionerd.ProvisionerDaemon.UpdateJob:input_type -> provisionerd.UpdateJobRequest - 3, // 28: provisionerd.ProvisionerDaemon.FailJob:input_type -> provisionerd.FailedJob - 4, // 29: provisionerd.ProvisionerDaemon.CompleteJob:input_type -> provisionerd.CompletedJob - 2, // 30: provisionerd.ProvisionerDaemon.AcquireJob:output_type -> provisionerd.AcquiredJob - 9, // 31: provisionerd.ProvisionerDaemon.CommitQuota:output_type -> provisionerd.CommitQuotaResponse - 7, // 32: provisionerd.ProvisionerDaemon.UpdateJob:output_type -> provisionerd.UpdateJobResponse - 1, // 33: provisionerd.ProvisionerDaemon.FailJob:output_type -> provisionerd.Empty - 1, // 34: provisionerd.ProvisionerDaemon.CompleteJob:output_type -> provisionerd.Empty - 30, // [30:35] is the sub-list for method output_type - 25, // [25:30] is the sub-list for method input_type - 25, // [25:25] is the sub-list for extension type_name - 25, // [25:25] is the sub-list for extension extendee - 0, // [0:25] is the sub-list for field type_name + 22, // 19: provisionerd.AcquiredJob.TemplateDryRun.rich_parameter_values:type_name -> provisioner.RichParameterValue + 23, // 20: provisionerd.AcquiredJob.TemplateDryRun.metadata:type_name -> provisioner.Provision.Metadata + 24, // 21: provisionerd.CompletedJob.WorkspaceBuild.resources:type_name -> provisioner.Resource + 24, // 22: provisionerd.CompletedJob.TemplateImport.start_resources:type_name -> provisioner.Resource + 24, // 23: provisionerd.CompletedJob.TemplateImport.stop_resources:type_name -> provisioner.Resource + 25, // 24: provisionerd.CompletedJob.TemplateImport.rich_parameters:type_name -> provisioner.RichParameter + 24, // 25: provisionerd.CompletedJob.TemplateDryRun.resources:type_name -> provisioner.Resource + 1, // 26: provisionerd.ProvisionerDaemon.AcquireJob:input_type -> provisionerd.Empty + 8, // 27: provisionerd.ProvisionerDaemon.CommitQuota:input_type -> provisionerd.CommitQuotaRequest + 6, // 28: provisionerd.ProvisionerDaemon.UpdateJob:input_type -> provisionerd.UpdateJobRequest + 3, // 29: provisionerd.ProvisionerDaemon.FailJob:input_type -> provisionerd.FailedJob + 4, // 30: provisionerd.ProvisionerDaemon.CompleteJob:input_type -> provisionerd.CompletedJob + 2, // 31: provisionerd.ProvisionerDaemon.AcquireJob:output_type -> provisionerd.AcquiredJob + 9, // 32: provisionerd.ProvisionerDaemon.CommitQuota:output_type -> provisionerd.CommitQuotaResponse + 7, // 33: provisionerd.ProvisionerDaemon.UpdateJob:output_type -> provisionerd.UpdateJobResponse + 1, // 34: provisionerd.ProvisionerDaemon.FailJob:output_type -> provisionerd.Empty + 1, // 35: provisionerd.ProvisionerDaemon.CompleteJob:output_type -> provisionerd.Empty + 31, // [31:36] is the sub-list for method output_type + 26, // [26:31] 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 } func init() { file_provisionerd_proto_provisionerd_proto_init() } diff --git a/provisionerd/proto/provisionerd.proto b/provisionerd/proto/provisionerd.proto index 66555ef53e09a..8b9ec5f8ab31c 100644 --- a/provisionerd/proto/provisionerd.proto +++ b/provisionerd/proto/provisionerd.proto @@ -24,7 +24,8 @@ message AcquiredJob { } message TemplateDryRun { repeated provisioner.ParameterValue parameter_values = 1; - provisioner.Provision.Metadata metadata = 2; + repeated provisioner.RichParameterValue rich_parameter_values = 2; + provisioner.Provision.Metadata metadata = 3; } string job_id = 1; diff --git a/provisionerd/runner/runner.go b/provisionerd/runner/runner.go index 060ea9273ffe5..2ccf63c71c4cf 100644 --- a/provisionerd/runner/runner.go +++ b/provisionerd/runner/runner.go @@ -427,6 +427,7 @@ func (r *Runner) do(ctx context.Context) (*proto.CompletedJob, *proto.FailedJob) r.logger.Debug(context.Background(), "acquired job is template dry-run", slog.F("workspace_name", jobType.TemplateDryRun.Metadata.WorkspaceName), slog.F("parameters", jobType.TemplateDryRun.ParameterValues), + slog.F("rich_parameter_values", jobType.TemplateDryRun.RichParameterValues), ) return r.runTemplateDryRun(ctx) case *proto.AcquiredJob_WorkspaceBuild_: @@ -646,9 +647,15 @@ func (r *Runner) runTemplateImportParse(ctx context.Context) ([]*sdkproto.Parame } // 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. +// 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, values []*sdkproto.ParameterValue, metadata *sdkproto.Provision_Metadata) ([]*sdkproto.Resource, []*sdkproto.RichParameter, error) { + return r.runTemplateImportProvisionWithRichParameters(ctx, values, 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, values []*sdkproto.ParameterValue, richParameterValues []*sdkproto.RichParameterValue, metadata *sdkproto.Provision_Metadata) ([]*sdkproto.Resource, []*sdkproto.RichParameter, error) { ctx, span := r.startTrace(ctx, tracing.FuncName()) defer span.End() @@ -685,7 +692,8 @@ func (r *Runner) runTemplateImportProvision(ctx context.Context, values []*sdkpr Directory: r.workDirectory, Metadata: metadata, }, - ParameterValues: values, + ParameterValues: values, + RichParameterValues: richParameterValues, }, }, }) @@ -767,8 +775,9 @@ func (r *Runner) runTemplateDryRun(ctx context.Context) (*proto.CompletedJob, *p } // Run the template import provision task since it's already a dry run. - resources, _, err := r.runTemplateImportProvision(ctx, + resources, _, err := r.runTemplateImportProvisionWithRichParameters(ctx, r.job.GetTemplateDryRun().GetParameterValues(), + r.job.GetTemplateDryRun().GetRichParameterValues(), metadata, ) if err != nil { @@ -941,8 +950,9 @@ func (r *Runner) runWorkspaceBuild(ctx context.Context) (*proto.CompletedJob, *p completedPlan, failed := r.buildWorkspace(ctx, "Planning infrastructure", &sdkproto.Provision_Request{ Type: &sdkproto.Provision_Request_Plan{ Plan: &sdkproto.Provision_Plan{ - Config: config, - ParameterValues: r.job.GetWorkspaceBuild().ParameterValues, + Config: config, + ParameterValues: r.job.GetWorkspaceBuild().ParameterValues, + RichParameterValues: r.job.GetWorkspaceBuild().RichParameterValues, }, }, }) diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index 26bf9a9de44c1..6fd81556aae37 100644 --- a/site/src/api/typesGenerated.ts +++ b/site/src/api/typesGenerated.ts @@ -188,6 +188,7 @@ export interface CreateTemplateRequest { export interface CreateTemplateVersionDryRunRequest { readonly workspace_name: string readonly parameter_values: CreateParameterRequest[] + readonly rich_parameter_values: WorkspaceBuildParameter[] } // From codersdk/organizations.go