From df9ddf38c299b17d5bfda3d120efcf28dacc22f7 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Wed, 18 Jan 2023 11:42:53 +0100 Subject: [PATCH 01/34] WIP --- cli/create.go | 70 ++++++++++++++++++------- cli/testdata/coder_create_--help.golden | 3 ++ cli/testdata/coder_update_--help.golden | 13 +++-- cli/update.go | 31 +++++++---- 4 files changed, 84 insertions(+), 33 deletions(-) diff --git a/cli/create.go b/cli/create.go index 854ba78565c51..1af0ef05385c4 100644 --- a/cli/create.go +++ b/cli/create.go @@ -1,6 +1,7 @@ package cli import ( + "context" "fmt" "io" "time" @@ -17,11 +18,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,7 +123,7 @@ func create() *cobra.Command { schedSpec = ptr.Ref(sched.String()) } - parameters, err := prepWorkspaceBuild(cmd, client, prepWorkspaceBuildArgs{ + buildParams, err := prepWorkspaceBuild(cmd, client, prepWorkspaceBuildArgs{ Template: template, ExistingParams: []codersdk.Parameter{}, ParameterFile: parameterFile, @@ -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,54 @@ 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 +} + +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 } + + legacyParameters, err := prepLegacyParameters(ctx, cmd, client, templateVersion, args) + if err != nil { + return nil, err + } + + richParameters, err := prepRichParameters() + if err != nil { + return nil, err + } + + return &buildParameters{ + parameters: legacyParameters, + richParameters: richParameters, + }, nil +} + +func prepLegacyParameters(ctx context.Context, cmd *cobra.Command, client *codersdk.Client, templateVersion codersdk.TemplateVersion, args prepWorkspaceBuildArgs) ([]codersdk.CreateParameterRequest, error) { parameterSchemas, err := client.TemplateVersionSchema(ctx, templateVersion.ID) if err != nil { return nil, err @@ -278,6 +309,9 @@ PromptParamLoop: if err != nil { return nil, err } - return parameters, nil } + +func prepRichParameters() ([]codersdk.WorkspaceBuildParameter, error) { + return nil, 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..7ecdbd1bc850f 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,36 @@ 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, }) 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 +92,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 } From e8e2e5328bbed8c38538190de6af150543f703fa Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Wed, 18 Jan 2023 13:24:51 +0100 Subject: [PATCH 02/34] WIP --- cli/cliui/parameter.go | 53 ++++++++++++++++++++++++++++ cli/create.go | 78 ++++++++++++++++++++++++++++-------------- cli/parameter.go | 27 +++++++++++++-- 3 files changed, 131 insertions(+), 27 deletions(-) diff --git a/cli/cliui/parameter.go b/cli/cliui/parameter.go index 28e0c08e785ce..2519b7cc48e50 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(parameter codersdk.TemplateVersionParameter) []string { + var options []string + for _, opt := range parameter.Options { + options = append(options, opt.Value) + } + return options +} diff --git a/cli/create.go b/cli/create.go index 1af0ef05385c4..b1fec6eb19446 100644 --- a/cli/create.go +++ b/cli/create.go @@ -1,7 +1,6 @@ package cli import ( - "context" "fmt" "io" "time" @@ -197,23 +196,7 @@ func prepWorkspaceBuild(cmd *cobra.Command, client *codersdk.Client, args prepWo return nil, err } - legacyParameters, err := prepLegacyParameters(ctx, cmd, client, templateVersion, args) - if err != nil { - return nil, err - } - - richParameters, err := prepRichParameters() - if err != nil { - return nil, err - } - - return &buildParameters{ - parameters: legacyParameters, - richParameters: richParameters, - }, nil -} - -func prepLegacyParameters(ctx context.Context, cmd *cobra.Command, client *codersdk.Client, templateVersion codersdk.TemplateVersion, args prepWorkspaceBuildArgs) ([]codersdk.CreateParameterRequest, error) { + // Legacy parameters parameterSchemas, err := client.TemplateVersionSchema(ctx, templateVersion.ID) if err != nil { return nil, err @@ -231,7 +214,7 @@ func prepLegacyParameters(ctx context.Context, cmd *cobra.Command, client *coder } } disclaimerPrinted := false - parameters := make([]codersdk.CreateParameterRequest, 0) + legacyParameters := make([]codersdk.CreateParameterRequest, 0) PromptParamLoop: for _, parameterSchema := range parameterSchemas { if !parameterSchema.AllowOverrideSource { @@ -258,7 +241,7 @@ PromptParamLoop: return nil, err } - parameters = append(parameters, codersdk.CreateParameterRequest{ + legacyParameters = append(legacyParameters, codersdk.CreateParameterRequest{ Name: parameterSchema.Name, SourceValue: parameterValue, SourceScheme: codersdk.ParameterSourceSchemeData, @@ -267,10 +250,55 @@ PromptParamLoop: } _, _ = 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", err) + } + + parameterMapFromFile = map[string]string{} + useParamFile = false + if args.ParameterFile != "" { + 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.ParameterFile) + 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.ExistingParams { + 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 + } + } + } + + parameterValue, err := getWorkspaceBuildParameterValueFromMapOrInput(cmd, parameterMapFromFile, templateVersionParameter) + if err != nil { + return nil, err + } + + richParameters = append(richParameters, *parameterValue) + } + // 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, + ParameterValues: legacyParameters, + // TODO RichParameterValues }) if err != nil { return nil, xerrors.Errorf("begin workspace dry-run: %w", err) @@ -309,9 +337,9 @@ PromptParamLoop: if err != nil { return nil, err } - return parameters, nil -} -func prepRichParameters() ([]codersdk.WorkspaceBuildParameter, error) { - return nil, nil + return &buildParameters{ + parameters: legacyParameters, + richParameters: richParameters, + }, nil } 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 +} From cfe5521603bfbbee3dda4991cecce80957dbffa3 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Wed, 18 Jan 2023 17:05:59 +0100 Subject: [PATCH 03/34] CLI: handle workspace build parameters --- cli/cliui/parameter.go | 1 + coderd/workspacebuilds.go | 2 +- provisioner/terraform/provision.go | 8 +++-- provisioner/terraform/provision_test.go | 43 +++++++++++++++++++++++++ provisionerd/runner/runner.go | 5 +-- 5 files changed, 54 insertions(+), 5 deletions(-) diff --git a/cli/cliui/parameter.go b/cli/cliui/parameter.go index 2519b7cc48e50..5ba37f6609620 100644 --- a/cli/cliui/parameter.go +++ b/cli/cliui/parameter.go @@ -68,6 +68,7 @@ func RichParameter(cmd *cobra.Command, templateVersionParameter codersdk.Templat } // TODO Implement full validation and show descriptions. + // TODO Is mutable? var err error var value string if len(templateVersionParameter.Options) > 0 { diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index f62b82a07b63a..25dbf5dae0870 100644 --- a/coderd/workspacebuilds.go +++ b/coderd/workspacebuilds.go @@ -567,7 +567,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 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/runner/runner.go b/provisionerd/runner/runner.go index 060ea9273ffe5..f5b6df17f82a4 100644 --- a/provisionerd/runner/runner.go +++ b/provisionerd/runner/runner.go @@ -941,8 +941,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, }, }, }) From 74315b22b9f7b5e550956889fa978517fdf38e30 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Wed, 18 Jan 2023 17:33:41 +0100 Subject: [PATCH 04/34] fix: golintci --- cli/cliui/parameter.go | 4 ++-- cli/create.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/cliui/parameter.go b/cli/cliui/parameter.go index 5ba37f6609620..6f0923a6c0984 100644 --- a/cli/cliui/parameter.go +++ b/cli/cliui/parameter.go @@ -107,9 +107,9 @@ func RichParameter(cmd *cobra.Command, templateVersionParameter codersdk.Templat return value, nil } -func templateVersionParameterOptionValues(parameter codersdk.TemplateVersionParameter) []string { +func templateVersionParameterOptionValues(param codersdk.TemplateVersionParameter) []string { var options []string - for _, opt := range parameter.Options { + for _, opt := range param.Options { options = append(options, opt.Value) } return options diff --git a/cli/create.go b/cli/create.go index b1fec6eb19446..631fd5b77fda3 100644 --- a/cli/create.go +++ b/cli/create.go @@ -253,7 +253,7 @@ PromptParamLoop: // Rich parameters templateVersionParameters, err := client.TemplateVersionRichParameters(cmd.Context(), templateVersion.ID) if err != nil { - return nil, xerrors.Errorf("get template version rich parameters", err) + return nil, xerrors.Errorf("get template version rich parameters: %w", err) } parameterMapFromFile = map[string]string{} From 90b5e357a5762be324c94c3d99610a793671b6a5 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Thu, 19 Jan 2023 11:15:12 +0100 Subject: [PATCH 05/34] Fix: dry run --- cli/create.go | 6 +- coderd/apidoc/docs.go | 6 + coderd/apidoc/swagger.json | 6 + .../provisionerdserver/provisionerdserver.go | 10 +- coderd/templateversions.go | 16 +- codersdk/templateversions.go | 5 +- docs/api/schemas.md | 15 +- docs/api/templates.md | 12 + provisionerd/proto/provisionerd.pb.go | 359 +++++++++--------- provisionerd/proto/provisionerd.proto | 3 +- provisionerd/proto/provisionerd_drpc.pb.go | 2 +- provisionerd/runner/runner.go | 17 +- site/src/api/typesGenerated.ts | 1 + 13 files changed, 262 insertions(+), 196 deletions(-) diff --git a/cli/create.go b/cli/create.go index 631fd5b77fda3..a82c02096b9cd 100644 --- a/cli/create.go +++ b/cli/create.go @@ -296,9 +296,9 @@ PromptRichParamLoop: // 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: legacyParameters, - // TODO RichParameterValues + WorkspaceName: args.NewWorkspaceName, + ParameterValues: legacyParameters, + RichParameterValues: richParameters, }) if err != nil { return nil, xerrors.Errorf("begin workspace dry-run: %w", err) diff --git a/coderd/apidoc/docs.go b/coderd/apidoc/docs.go index 177c4230c94a1..8584b89fc803f 100644 --- a/coderd/apidoc/docs.go +++ b/coderd/apidoc/docs.go @@ -5491,6 +5491,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 b9a34ede0b0f3..97b951341f36f 100644 --- a/coderd/apidoc/swagger.json +++ b/coderd/apidoc/swagger.json @@ -4865,6 +4865,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/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 7993145e3295b..2764683a0a90a 100644 --- a/docs/api/schemas.md +++ b/docs/api/schemas.md @@ -762,16 +762,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 b271184929b48..074cec89d84d6 100644 --- a/docs/api/templates.md +++ b/docs/api/templates.md @@ -408,6 +408,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" } ``` @@ -1293,6 +1299,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/provisionerd/proto/provisionerd.pb.go b/provisionerd/proto/provisionerd.pb.go index 4ce8743ab4070..8af6507b3986d 100644 --- a/provisionerd/proto/provisionerd.pb.go +++ b/provisionerd/proto/provisionerd.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.26.0 -// protoc v3.21.5 +// protoc-gen-go v1.28.1 +// protoc v3.21.6 // source: provisionerd/proto/provisionerd.proto package proto @@ -119,7 +119,6 @@ type AcquiredJob struct { UserName string `protobuf:"bytes,4,opt,name=user_name,json=userName,proto3" json:"user_name,omitempty"` TemplateSourceArchive []byte `protobuf:"bytes,5,opt,name=template_source_archive,json=templateSourceArchive,proto3" json:"template_source_archive,omitempty"` // Types that are assignable to Type: - // // *AcquiredJob_WorkspaceBuild_ // *AcquiredJob_TemplateImport_ // *AcquiredJob_TemplateDryRun_ @@ -251,7 +250,6 @@ type FailedJob struct { JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"` Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` // Types that are assignable to Type: - // // *FailedJob_WorkspaceBuild_ // *FailedJob_TemplateImport_ // *FailedJob_TemplateDryRun_ @@ -362,7 +360,6 @@ type CompletedJob struct { JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"` // Types that are assignable to Type: - // // *CompletedJob_WorkspaceBuild_ // *CompletedJob_TemplateImport_ // *CompletedJob_TemplateDryRun_ @@ -514,7 +511,7 @@ func (x *Log) GetLevel() proto.LogLevel { if x != nil { return x.Level } - return proto.LogLevel_TRACE + return proto.LogLevel(0) } func (x *Log) GetCreatedAt() int64 { @@ -924,8 +921,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 +965,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 +1276,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 +1330,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 +1549,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/proto/provisionerd_drpc.pb.go b/provisionerd/proto/provisionerd_drpc.pb.go index 6d73176475490..058af595809b8 100644 --- a/provisionerd/proto/provisionerd_drpc.pb.go +++ b/provisionerd/proto/provisionerd_drpc.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-go-drpc. DO NOT EDIT. -// protoc-gen-go-drpc version: v0.0.26 +// protoc-gen-go-drpc version: (devel) // source: provisionerd/proto/provisionerd.proto package proto diff --git a/provisionerd/runner/runner.go b/provisionerd/runner/runner.go index f5b6df17f82a4..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 { diff --git a/site/src/api/typesGenerated.ts b/site/src/api/typesGenerated.ts index f5d1728a9e9d6..61bbe2ad1c766 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 From 34db76e58422158e18dac5e274519b9f7bd6c3a4 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Thu, 19 Jan 2023 11:39:45 +0100 Subject: [PATCH 06/34] fix --- provisionerd/proto/provisionerd.pb.go | 9 ++++++--- provisionerd/proto/provisionerd_drpc.pb.go | 2 +- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/provisionerd/proto/provisionerd.pb.go b/provisionerd/proto/provisionerd.pb.go index 8af6507b3986d..a8b741d89987e 100644 --- a/provisionerd/proto/provisionerd.pb.go +++ b/provisionerd/proto/provisionerd.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.28.1 -// protoc v3.21.6 +// protoc-gen-go v1.26.0 +// protoc v3.21.5 // source: provisionerd/proto/provisionerd.proto package proto @@ -119,6 +119,7 @@ type AcquiredJob struct { UserName string `protobuf:"bytes,4,opt,name=user_name,json=userName,proto3" json:"user_name,omitempty"` TemplateSourceArchive []byte `protobuf:"bytes,5,opt,name=template_source_archive,json=templateSourceArchive,proto3" json:"template_source_archive,omitempty"` // Types that are assignable to Type: + // // *AcquiredJob_WorkspaceBuild_ // *AcquiredJob_TemplateImport_ // *AcquiredJob_TemplateDryRun_ @@ -250,6 +251,7 @@ type FailedJob struct { JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"` Error string `protobuf:"bytes,2,opt,name=error,proto3" json:"error,omitempty"` // Types that are assignable to Type: + // // *FailedJob_WorkspaceBuild_ // *FailedJob_TemplateImport_ // *FailedJob_TemplateDryRun_ @@ -360,6 +362,7 @@ type CompletedJob struct { JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"` // Types that are assignable to Type: + // // *CompletedJob_WorkspaceBuild_ // *CompletedJob_TemplateImport_ // *CompletedJob_TemplateDryRun_ @@ -511,7 +514,7 @@ func (x *Log) GetLevel() proto.LogLevel { if x != nil { return x.Level } - return proto.LogLevel(0) + return proto.LogLevel_TRACE } func (x *Log) GetCreatedAt() int64 { diff --git a/provisionerd/proto/provisionerd_drpc.pb.go b/provisionerd/proto/provisionerd_drpc.pb.go index 058af595809b8..6d73176475490 100644 --- a/provisionerd/proto/provisionerd_drpc.pb.go +++ b/provisionerd/proto/provisionerd_drpc.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-go-drpc. DO NOT EDIT. -// protoc-gen-go-drpc version: (devel) +// protoc-gen-go-drpc version: v0.0.26 // source: provisionerd/proto/provisionerd.proto package proto From a78f798b9c542ea2176a8076f7b60192612ae411 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Thu, 19 Jan 2023 12:48:47 +0100 Subject: [PATCH 07/34] CLI: is mutable --- cli/cliui/parameter.go | 1 - cli/create.go | 11 +++++++++-- cli/update.go | 1 + coderd/workspacebuilds.go | 1 + 4 files changed, 11 insertions(+), 3 deletions(-) diff --git a/cli/cliui/parameter.go b/cli/cliui/parameter.go index 6f0923a6c0984..e19e09671dada 100644 --- a/cli/cliui/parameter.go +++ b/cli/cliui/parameter.go @@ -68,7 +68,6 @@ func RichParameter(cmd *cobra.Command, templateVersionParameter codersdk.Templat } // TODO Implement full validation and show descriptions. - // TODO Is mutable? var err error var value string if len(templateVersionParameter.Options) > 0 { diff --git a/cli/create.go b/cli/create.go index a82c02096b9cd..918698f8c1cf4 100644 --- a/cli/create.go +++ b/cli/create.go @@ -178,6 +178,8 @@ type prepWorkspaceBuildArgs struct { ExistingRichParams []codersdk.WorkspaceBuildParameter RichParameterFile string NewWorkspaceName string + + UpdateWorkspace bool } type buildParameters struct { @@ -261,7 +263,7 @@ PromptParamLoop: if args.ParameterFile != "" { 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.ParameterFile) + parameterMapFromFile, err = createParameterMapFromFile(args.RichParameterFile) if err != nil { return nil, err } @@ -277,7 +279,7 @@ PromptRichParamLoop: // Param file is all or nothing if !useParamFile { - for _, e := range args.ExistingParams { + 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. @@ -286,6 +288,11 @@ 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 diff --git a/cli/update.go b/cli/update.go index 7ecdbd1bc850f..9e23ee73569dd 100644 --- a/cli/update.go +++ b/cli/update.go @@ -60,6 +60,7 @@ func update() *cobra.Command { ExistingRichParams: existingRichParams, RichParameterFile: richParameterFile, NewWorkspaceName: workspace.Name, + UpdateWorkspace: true, }) if err != nil { return nil diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index 25dbf5dae0870..8864e484cb171 100644 --- a/coderd/workspacebuilds.go +++ b/coderd/workspacebuilds.go @@ -455,6 +455,7 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { } if parameters == nil { + // TODO Is mutable? buildParameters, err := api.Database.GetWorkspaceBuildParameters(ctx, priorHistory.ID) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ From 7e6ddca14bc169533cde9386ac2bb712df22ec5e Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Thu, 19 Jan 2023 15:17:34 +0100 Subject: [PATCH 08/34] coderd: mutable --- coderd/workspacebuilds.go | 65 +++++++++++++++++++++++----------- coderd/workspacebuilds_test.go | 47 ++++++++++++++++++++++-- 2 files changed, 89 insertions(+), 23 deletions(-) diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index 8864e484cb171..86b5961e905ed 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,22 +449,43 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { state = priorHistory.ProvisionerState } - if parameters == nil { - // TODO Is mutable? - 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) } } @@ -1172,3 +1188,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..c362d21765564 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 mutable 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) + }) } From b55e40281ed38e5b1e122f4fdfd5b94e03c987f3 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Thu, 19 Jan 2023 15:19:59 +0100 Subject: [PATCH 09/34] fix: golanci --- coderd/workspacebuilds.go | 1 - 1 file changed, 1 deletion(-) diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index 86b5961e905ed..b663ec729042f 100644 --- a/coderd/workspacebuilds.go +++ b/coderd/workspacebuilds.go @@ -456,7 +456,6 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { Detail: err.Error(), }) return - } lastBuildParameters, err := api.Database.GetWorkspaceBuildParameters(ctx, priorHistory.ID) From f6dee95a8c0cff8cc4b8fe1e8bcb97796d03f93e Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Thu, 19 Jan 2023 15:49:19 +0100 Subject: [PATCH 10/34] fix: richParameterFile --- cli/create.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/create.go b/cli/create.go index 918698f8c1cf4..84dce3a0d17fc 100644 --- a/cli/create.go +++ b/cli/create.go @@ -260,7 +260,7 @@ PromptParamLoop: parameterMapFromFile = map[string]string{} useParamFile = false - if args.ParameterFile != "" { + 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) From f46cf48f9635e65a49ea4426cc74e3b38d143066 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Thu, 19 Jan 2023 17:10:04 +0100 Subject: [PATCH 11/34] CLI: create unit tests --- cli/create.go | 9 +-- cli/create_test.go | 118 +++++++++++++++++++++++++++++++++ coderd/workspacebuilds_test.go | 2 +- 3 files changed, 124 insertions(+), 5 deletions(-) diff --git a/cli/create.go b/cli/create.go index 84dce3a0d17fc..a5cf49048cf19 100644 --- a/cli/create.go +++ b/cli/create.go @@ -123,10 +123,11 @@ func create() *cobra.Command { } buildParams, err := prepWorkspaceBuild(cmd, client, prepWorkspaceBuildArgs{ - Template: template, - ExistingParams: []codersdk.Parameter{}, - ParameterFile: parameterFile, - NewWorkspaceName: workspaceName, + Template: template, + ExistingParams: []codersdk.Parameter{}, + ParameterFile: parameterFile, + RichParameterFile: richParameterFile, + NewWorkspaceName: workspaceName, }) if err != nil { return err diff --git a/cli/create_test.go b/cli/create_test.go index 616ec3775d854..3465ea1414fb5 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 = "immutable_parameter" + immutableParameterDescription = "This is 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/coderd/workspacebuilds_test.go b/coderd/workspacebuilds_test.go index c362d21765564..bbdec82b4a30d 100644 --- a/coderd/workspacebuilds_test.go +++ b/coderd/workspacebuilds_test.go @@ -646,7 +646,7 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) { secondParameterValue = "2" immutableParameterName = "immutable_parameter" - immutableParameterDescription = "This is mutable parameter" + immutableParameterDescription = "This is immutable parameter" immutableParameterValue = "3" ) From 40a4aa03eb584d7eeb94b5f74a0c36bf87b7f10a Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Thu, 19 Jan 2023 18:52:50 +0100 Subject: [PATCH 12/34] CLI: update test --- cli/update_test.go | 91 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/cli/update_test.go b/cli/update_test.go index 73a30544d5ef6..ed933c3d914d3 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,92 @@ 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 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("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" + + secondParameterName + ": " + secondParameterValue + "\n" + + immutableParameterName + ": " + immutableParameterValue) + + 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, + secondParameterDescription, secondParameterValue, + fmt.Sprintf("Parameter %q is not mutable, so can't be customized after workspace creation.", immutableParameterName), "yes", + } + for i := 0; i < len(matches); i += 2 { + match := matches[i] + value := matches[i+1] + pty.ExpectMatch(match) + pty.WriteLine(value) + } + <-doneChan + }) +} From 1af7b9a78faaa6959f64f35dee8212a003192263 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Thu, 19 Jan 2023 19:10:14 +0100 Subject: [PATCH 13/34] Fix --- cli/create.go | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/cli/create.go b/cli/create.go index a5cf49048cf19..2c4d20e3a74e2 100644 --- a/cli/create.go +++ b/cli/create.go @@ -251,7 +251,10 @@ PromptParamLoop: DestinationScheme: parameterSchema.DefaultDestinationScheme, }) } - _, _ = fmt.Fprintln(cmd.OutOrStdout()) + + if disclaimerPrinted { + _, _ = fmt.Fprintln(cmd.OutOrStdout()) + } // Rich parameters templateVersionParameters, err := client.TemplateVersionRichParameters(cmd.Context(), templateVersion.ID) @@ -302,6 +305,10 @@ PromptRichParamLoop: 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, From 8c989ee3adac6578bb28a910805f4ce0d0a51d93 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 20 Jan 2023 08:42:07 +0100 Subject: [PATCH 14/34] fix: order --- cli/update_test.go | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/cli/update_test.go b/cli/update_test.go index ed933c3d914d3..90e32b92c0262 100644 --- a/cli/update_test.go +++ b/cli/update_test.go @@ -167,8 +167,8 @@ func TestUpdateWithRichParameters(t *testing.T) { 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}, + {Name: secondParameterName, Description: secondParameterDescription, Mutable: true}, }, }, }, @@ -195,8 +195,8 @@ func TestUpdateWithRichParameters(t *testing.T) { parameterFile, _ := os.CreateTemp(tempDir, "testParameterFile*.yaml") _, _ = parameterFile.WriteString( firstParameterName + ": " + firstParameterValue + "\n" + - secondParameterName + ": " + secondParameterValue + "\n" + - immutableParameterName + ": " + immutableParameterValue) + 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) @@ -218,14 +218,16 @@ func TestUpdateWithRichParameters(t *testing.T) { matches := []string{ firstParameterDescription, firstParameterValue, + fmt.Sprintf("Parameter %q is not mutable, so can't be customized after workspace creation.", immutableParameterName), "", secondParameterDescription, secondParameterValue, - fmt.Sprintf("Parameter %q is not mutable, so can't be customized after workspace creation.", immutableParameterName), "yes", } for i := 0; i < len(matches); i += 2 { match := matches[i] value := matches[i+1] pty.ExpectMatch(match) - pty.WriteLine(value) + if value != "" { + pty.WriteLine(value) + } } <-doneChan }) From 6dbd044f5a7c628c50d5b4b9773eff4db918d631 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 20 Jan 2023 09:06:43 +0100 Subject: [PATCH 15/34] fix --- cli/create_test.go | 4 ++-- cli/update_test.go | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/cli/create_test.go b/cli/create_test.go index 3465ea1414fb5..03552dbd9bd43 100644 --- a/cli/create_test.go +++ b/cli/create_test.go @@ -333,8 +333,8 @@ func TestCreateWithRichParameters(t *testing.T) { secondParameterDescription = "This is second parameter" secondParameterValue = "2" - immutableParameterName = "immutable_parameter" - immutableParameterDescription = "This is mutable parameter" + immutableParameterName = "third_parameter" + immutableParameterDescription = "This is not mutable parameter" immutableParameterValue = "3" ) diff --git a/cli/update_test.go b/cli/update_test.go index 90e32b92c0262..250e768d48580 100644 --- a/cli/update_test.go +++ b/cli/update_test.go @@ -155,7 +155,7 @@ func TestUpdateWithRichParameters(t *testing.T) { secondParameterValue = "2" immutableParameterName = "immutable_parameter" - immutableParameterDescription = "This is mutable parameter" + immutableParameterDescription = "This is not mutable parameter" immutableParameterValue = "3" ) From 125d8616de78cfec6b3973e31453815f517d3c21 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 20 Jan 2023 12:59:10 +0100 Subject: [PATCH 16/34] feat: Validate workspace build parameters --- coderd/templateversions.go | 35 ++++++++++++-------- coderd/workspacebuilds.go | 19 ++++++++++- coderd/workspaces.go | 28 ++++++++++++++++ codersdk/richparameters.go | 67 ++++++++++++++++++++++++++++++++++++++ 4 files changed, 135 insertions(+), 14 deletions(-) create mode 100644 codersdk/richparameters.go diff --git a/coderd/templateversions.go b/coderd/templateversions.go index b4fcddaf6ac54..8ec633d32fde3 100644 --- a/coderd/templateversions.go +++ b/coderd/templateversions.go @@ -223,7 +223,7 @@ func (api *API) templateVersionRichParameters(rw http.ResponseWriter, r *http.Re }) return } - dbParameters, err := api.Database.GetTemplateVersionParameters(ctx, templateVersion.ID) + dbTemplateVersionParameters, err := api.Database.GetTemplateVersionParameters(ctx, templateVersion.ID) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ Message: "Internal error fetching template version parameters.", @@ -231,19 +231,16 @@ func (api *API) templateVersionRichParameters(rw http.ResponseWriter, r *http.Re }) return } - params := make([]codersdk.TemplateVersionParameter, 0) - for _, dbParameter := range dbParameters { - param, err := convertTemplateVersionParameter(dbParameter) - if err != nil { - httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ - Message: "Internal error converting template version parameter.", - Detail: err.Error(), - }) - return - } - params = append(params, param) + + templateVersionParameters, err := convertTemplateVersionParameters(dbTemplateVersionParameters) + if err != nil { + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Internal error converting template version parameter.", + Detail: err.Error(), + }) + return } - httpapi.Write(ctx, rw, http.StatusOK, params) + httpapi.Write(ctx, rw, http.StatusOK, templateVersionParameters) } // @Summary Get parameters by template version @@ -1379,6 +1376,18 @@ func convertTemplateVersion(version database.TemplateVersion, job codersdk.Provi } } +func convertTemplateVersionParameters(dbParams []database.TemplateVersionParameter) ([]codersdk.TemplateVersionParameter, error) { + params := make([]codersdk.TemplateVersionParameter, 0) + for _, dbParameter := range dbParams { + param, err := convertTemplateVersionParameter(dbParameter) + if err != nil { + return nil, err + } + params = append(params, param) + } + return params, nil +} + func convertTemplateVersionParameter(param database.TemplateVersionParameter) (codersdk.TemplateVersionParameter, error) { var protoOptions []*sdkproto.RichParameterOption err := json.Unmarshal(param.Options, &protoOptions) diff --git a/coderd/workspacebuilds.go b/coderd/workspacebuilds.go index b663ec729042f..da5e91e1c6c14 100644 --- a/coderd/workspacebuilds.go +++ b/coderd/workspacebuilds.go @@ -449,7 +449,7 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { state = priorHistory.ProvisionerState } - templateVersionParameters, err := api.Database.GetTemplateVersionParameters(ctx, createBuild.TemplateVersionID) + dbTemplateVersionParameters, 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.", @@ -457,6 +457,23 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) { }) return } + templateVersionParameters, err := convertTemplateVersionParameters(dbTemplateVersionParameters) + if err != nil { + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Internal error converting template version parameters.", + Detail: err.Error(), + }) + return + } + + err = codersdk.ValidateWorkspaceBuildParameters(templateVersionParameters, createBuild.RichParameterValues) + if err != nil { + httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ + Message: "Error validating workspace build parameters.", + Detail: err.Error(), + }) + return + } lastBuildParameters, err := api.Database.GetWorkspaceBuildParameters(ctx, priorHistory.ID) if err != nil { diff --git a/coderd/workspaces.go b/coderd/workspaces.go index 75ccfd2cba60e..019e36b3c7b01 100644 --- a/coderd/workspaces.go +++ b/coderd/workspaces.go @@ -390,6 +390,34 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req }) return } + + dbTemplateVersionParameters, err := api.Database.GetTemplateVersionParameters(ctx, templateVersion.ID) + if err != nil { + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Internal error fetching template version parameters.", + Detail: err.Error(), + }) + return + } + + templateVersionParameters, err := convertTemplateVersionParameters(dbTemplateVersionParameters) + if err != nil { + httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ + Message: "Internal error converting template version parameters.", + Detail: err.Error(), + }) + return + } + + err = codersdk.ValidateWorkspaceBuildParameters(templateVersionParameters, createWorkspace.RichParameterValues) + if err != nil { + httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{ + Message: "Error validating workspace build parameters.", + Detail: err.Error(), + }) + return + } + templateVersionJob, err := api.Database.GetProvisionerJobByID(ctx, templateVersion.JobID) if err != nil { httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{ diff --git a/codersdk/richparameters.go b/codersdk/richparameters.go new file mode 100644 index 0000000000000..14cfd9619136d --- /dev/null +++ b/codersdk/richparameters.go @@ -0,0 +1,67 @@ +package codersdk + +import ( + "golang.org/x/xerrors" + + "github.com/coder/terraform-provider-coder/provider" +) + +func ValidateWorkspaceBuildParameters(richParameters []TemplateVersionParameter, buildParameters []WorkspaceBuildParameter) error { + for _, buildParameter := range buildParameters { + richParameter, found := findTemplateVersionParameter(richParameters, buildParameter.Name) + if !found { + return xerrors.Errorf(`workspace build parameter is not defined in the template ("coder_parameter")`) + } + + err := ValidateWorkspaceBuildParameter(*richParameter, buildParameter) + if err != nil { + return xerrors.Errorf("can't validate build parameter %q: %w", buildParameter.Name, err) + } + } + return nil +} + +func ValidateWorkspaceBuildParameter(richParameter TemplateVersionParameter, buildParameter WorkspaceBuildParameter) error { + if buildParameter.Value == "" { + return xerrors.Errorf("parameter value can't be empty") + } + + if len(richParameter.Options) > 0 { + var matched bool + for _, opt := range richParameter.Options { + if opt.Value == buildParameter.Value { + matched = true + break + } + } + + if !matched { + return xerrors.Errorf("parameter value must match one of options: %s", parameterValuesAsArray(richParameter.Options)) + } + return nil + } + + validation := &provider.Validation{ + Min: int(richParameter.ValidationMin), + Max: int(richParameter.ValidationMax), + Regex: richParameter.ValidationRegex, + } + return validation.Valid(richParameter.Type, buildParameter.Value) +} + +func findTemplateVersionParameter(params []TemplateVersionParameter, parameterName string) (*TemplateVersionParameter, bool) { + for _, p := range params { + if p.Name == parameterName { + return &p, true + } + } + return nil, false +} + +func parameterValuesAsArray(options []TemplateVersionParameterOption) []string { + var arr []string + for _, opt := range options { + arr = append(arr, opt.Value) + } + return arr +} From e278cc03debd62e5317edc688b4ee7fa6a39f0d2 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 20 Jan 2023 15:27:33 +0100 Subject: [PATCH 17/34] Validator tests --- coderd/workspacebuilds_test.go | 159 +++++++++++++++++++++++++++++++++ codersdk/richparameters.go | 9 ++ 2 files changed, 168 insertions(+) diff --git a/coderd/workspacebuilds_test.go b/coderd/workspacebuilds_test.go index bbdec82b4a30d..47f8df9527261 100644 --- a/coderd/workspacebuilds_test.go +++ b/coderd/workspacebuilds_test.go @@ -780,3 +780,162 @@ func TestWorkspaceBuildWithRichParameters(t *testing.T) { require.Error(t, err) }) } + +func TestWorkspaceBuildValidateRichParameters(t *testing.T) { + t.Parallel() + + const ( + stringParameterName = "string_parameter" + stringParameterValue = "abc" + + numberParameterName = "number_parameter" + numberParameterValue = "7" + + boolParameterName = "bool_parameter" + boolParameterValue = "true" + ) + + initialBuildParameters := []codersdk.WorkspaceBuildParameter{ + {Name: stringParameterName, Value: stringParameterValue}, + {Name: numberParameterName, Value: numberParameterValue}, + {Name: boolParameterName, Value: boolParameterValue}, + } + + 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("NoValidation", func(t *testing.T) { + t.Parallel() + + richParameters := []*proto.RichParameter{ + {Name: stringParameterName, Type: "string", Mutable: true}, + {Name: numberParameterName, Type: "number", Mutable: true}, + {Name: boolParameterName, Type: "bool", Mutable: true}, + } + + client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + user := coderdtest.CreateFirstUser(t, client) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, prepareEchoResponses(richParameters)) + 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: numberParameterName, Value: "42"}, + } + nextWorkspaceBuild, err := client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ + Transition: codersdk.WorkspaceTransitionStart, + RichParameterValues: nextBuildParameters, + }) + require.NoError(t, err) + coderdtest.AwaitWorkspaceBuildJob(t, client, nextWorkspaceBuild.ID) + + _, err = client.WorkspaceBuildParameters(ctx, nextWorkspaceBuild.ID) + require.NoError(t, err) + }) + + t.Run("Validation", func(t *testing.T) { + t.Parallel() + + numberRichParameters := []*proto.RichParameter{ + {Name: stringParameterName, Type: "string", Mutable: true}, + {Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: 3, ValidationMax: 10}, + {Name: boolParameterName, Type: "bool", Mutable: true}, + } + + stringRichParameters := []*proto.RichParameter{ + {Name: stringParameterName, Type: "string", Mutable: true}, + {Name: numberParameterName, Type: "number", Mutable: true}, + {Name: boolParameterName, Type: "bool", Mutable: true}, + } + + /* FIXME + regexRichParameters := []*proto.RichParameter{ + {Name: stringParameterName, Type: "string", Mutable: true, ValidationRegex: "[a-z]+"}, + {Name: numberParameterName, Type: "number", Mutable: true}, + {Name: boolParameterName, Type: "bool", Mutable: true}, + }*/ + + tests := []struct { + value string + valid bool + richParameters []*proto.RichParameter + }{ + {"2", false, numberRichParameters}, + {"3", true, numberRichParameters}, + {"10", true, numberRichParameters}, + {"11", false, numberRichParameters}, + + {"", false, stringRichParameters}, + {"foobar", true, stringRichParameters}, + + /* FIXME can't validate build parameter "string_parameter": an error must be specified with a regex validation + {"abcd", true, regexRichParameters}, + {"abcd1", false, regexRichParameters},*/ + } + + for _, tc := range tests { + t.Run("Value-"+tc.value, func(t *testing.T) { + client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + user := coderdtest.CreateFirstUser(t, client) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, prepareEchoResponses(tc.richParameters)) + 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: numberParameterName, Value: tc.value}, + } + nextWorkspaceBuild, err := client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ + Transition: codersdk.WorkspaceTransitionStart, + RichParameterValues: nextBuildParameters, + }) + + if tc.valid { + require.NoError(t, err) + coderdtest.AwaitWorkspaceBuildJob(t, client, nextWorkspaceBuild.ID) + } else { + require.Error(t, err) + } + }) + } + }) +} diff --git a/codersdk/richparameters.go b/codersdk/richparameters.go index 14cfd9619136d..4ba0fe9beb3ad 100644 --- a/codersdk/richparameters.go +++ b/codersdk/richparameters.go @@ -41,10 +41,15 @@ func ValidateWorkspaceBuildParameter(richParameter TemplateVersionParameter, bui return nil } + if !validationEnabled(richParameter) { + return nil + } + validation := &provider.Validation{ Min: int(richParameter.ValidationMin), Max: int(richParameter.ValidationMax), Regex: richParameter.ValidationRegex, + // TODO Error: ?, } return validation.Valid(richParameter.Type, buildParameter.Value) } @@ -65,3 +70,7 @@ func parameterValuesAsArray(options []TemplateVersionParameterOption) []string { } return arr } + +func validationEnabled(param TemplateVersionParameter) bool { + return len(param.ValidationRegex) > 0 || (param.ValidationMin != 0 && param.ValidationMax != 0) +} From b6c3cde6dd6b623cf59c4109651883e6fbc5103c Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Fri, 20 Jan 2023 15:38:16 +0100 Subject: [PATCH 18/34] WIP validation --- coderd/workspacebuilds_test.go | 31 +++++++++++++++++++++---------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/coderd/workspacebuilds_test.go b/coderd/workspacebuilds_test.go index 47f8df9527261..76e2718030eb0 100644 --- a/coderd/workspacebuilds_test.go +++ b/coderd/workspacebuilds_test.go @@ -877,6 +877,12 @@ func TestWorkspaceBuildValidateRichParameters(t *testing.T) { {Name: boolParameterName, Type: "bool", Mutable: true}, } + boolRichParameters := []*proto.RichParameter{ + {Name: stringParameterName, Type: "string", Mutable: true}, + {Name: numberParameterName, Type: "number", Mutable: true}, + {Name: boolParameterName, Type: "bool", Mutable: true}, + } + /* FIXME regexRichParameters := []*proto.RichParameter{ {Name: stringParameterName, Type: "string", Mutable: true, ValidationRegex: "[a-z]+"}, @@ -885,25 +891,30 @@ func TestWorkspaceBuildValidateRichParameters(t *testing.T) { }*/ tests := []struct { + parameterName string value string valid bool richParameters []*proto.RichParameter }{ - {"2", false, numberRichParameters}, - {"3", true, numberRichParameters}, - {"10", true, numberRichParameters}, - {"11", false, numberRichParameters}, + {numberParameterName, "2", false, numberRichParameters}, + {numberParameterName, "3", true, numberRichParameters}, + {numberParameterName, "10", true, numberRichParameters}, + {numberParameterName, "11", false, numberRichParameters}, - {"", false, stringRichParameters}, - {"foobar", true, stringRichParameters}, + {stringParameterName, "", false, stringRichParameters}, + {stringParameterName, "foobar", true, stringRichParameters}, /* FIXME can't validate build parameter "string_parameter": an error must be specified with a regex validation - {"abcd", true, regexRichParameters}, - {"abcd1", false, regexRichParameters},*/ + {stringParameterName, "abcd", true, regexRichParameters}, + {stringParameterName, "abcd1", false, regexRichParameters},*/ + + {boolParameterName, "true", true, boolRichParameters}, + {boolParameterName, "false", true, boolRichParameters}, + // FIXME {boolParameterName, "cat", false, boolRichParameters}, } for _, tc := range tests { - t.Run("Value-"+tc.value, func(t *testing.T) { + t.Run(tc.parameterName+"-"+tc.value, func(t *testing.T) { client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) user := coderdtest.CreateFirstUser(t, client) version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, prepareEchoResponses(tc.richParameters)) @@ -922,7 +933,7 @@ func TestWorkspaceBuildValidateRichParameters(t *testing.T) { defer cancel() nextBuildParameters := []codersdk.WorkspaceBuildParameter{ - {Name: numberParameterName, Value: tc.value}, + {Name: tc.parameterName, Value: tc.value}, } nextWorkspaceBuild, err := client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{ Transition: codersdk.WorkspaceTransitionStart, From 5d6c54704be0e8823c5651bcca9830f51a1308cf Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 23 Jan 2023 12:46:03 +0100 Subject: [PATCH 19/34] Column: validation error --- coderd/database/databasefake/databasefake.go | 1 + coderd/database/dump.sql | 5 +- ..._rich_parameters_validation_error.down.sql | 1 + ...90_rich_parameters_validation_error.up.sql | 4 + coderd/database/models.go | 2 + coderd/database/queries.sql.go | 14 +- .../queries/templateversionparameters.sql | 6 +- .../provisionerdserver/provisionerdserver.go | 1 + coderd/templateversions.go | 1 + coderd/workspacebuilds_test.go | 13 +- codersdk/richparameters.go | 9 +- provisioner/terraform/resources.go | 1 + provisionersdk/proto/provisioner.pb.go | 458 +++++++++--------- provisionersdk/proto/provisioner.proto | 5 +- provisionersdk/proto/provisioner_drpc.pb.go | 2 +- 15 files changed, 278 insertions(+), 245 deletions(-) create mode 100644 coderd/database/migrations/000090_rich_parameters_validation_error.down.sql create mode 100644 coderd/database/migrations/000090_rich_parameters_validation_error.up.sql diff --git a/coderd/database/databasefake/databasefake.go b/coderd/database/databasefake/databasefake.go index c2db0b9998f84..850acfa35d01b 100644 --- a/coderd/database/databasefake/databasefake.go +++ b/coderd/database/databasefake/databasefake.go @@ -2442,6 +2442,7 @@ func (q *fakeQuerier) InsertTemplateVersionParameter(_ context.Context, arg data DefaultValue: arg.DefaultValue, Icon: arg.Icon, Options: arg.Options, + ValidationError: arg.ValidationError, ValidationRegex: arg.ValidationRegex, ValidationMin: arg.ValidationMin, ValidationMax: arg.ValidationMax, diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index 6ed5a26954b92..839666163c7aa 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -342,7 +342,8 @@ CREATE TABLE template_version_parameters ( options jsonb DEFAULT '[]'::jsonb NOT NULL, validation_regex text NOT NULL, validation_min integer NOT NULL, - validation_max integer NOT NULL + validation_max integer NOT NULL, + validation_error text NOT NULL ); COMMENT ON COLUMN template_version_parameters.name IS 'Parameter name'; @@ -365,6 +366,8 @@ COMMENT ON COLUMN template_version_parameters.validation_min IS 'Validation: min COMMENT ON COLUMN template_version_parameters.validation_max IS 'Validation: maximum length of value'; +COMMENT ON COLUMN template_version_parameters.validation_error IS 'Validation: error displayed when the regex does not match.'; + CREATE TABLE template_versions ( id uuid NOT NULL, template_id uuid, diff --git a/coderd/database/migrations/000090_rich_parameters_validation_error.down.sql b/coderd/database/migrations/000090_rich_parameters_validation_error.down.sql new file mode 100644 index 0000000000000..155dce526ed2e --- /dev/null +++ b/coderd/database/migrations/000090_rich_parameters_validation_error.down.sql @@ -0,0 +1 @@ +ALTER TABLE template_version_parameters DROP COLUMN validation_error; diff --git a/coderd/database/migrations/000090_rich_parameters_validation_error.up.sql b/coderd/database/migrations/000090_rich_parameters_validation_error.up.sql new file mode 100644 index 0000000000000..d1c21deb4330c --- /dev/null +++ b/coderd/database/migrations/000090_rich_parameters_validation_error.up.sql @@ -0,0 +1,4 @@ +ALTER TABLE template_version_parameters ADD COLUMN validation_error text NOT NULL; + +COMMENT ON COLUMN template_version_parameters.validation_error +IS 'Validation: error displayed when the regex does not match.'; diff --git a/coderd/database/models.go b/coderd/database/models.go index 909ca433f66e8..7d7741a533480 100644 --- a/coderd/database/models.go +++ b/coderd/database/models.go @@ -634,6 +634,8 @@ type TemplateVersionParameter struct { ValidationMin int32 `db:"validation_min" json:"validation_min"` // Validation: maximum length of value ValidationMax int32 `db:"validation_max" json:"validation_max"` + // Validation: error displayed when the regex does not match. + ValidationError string `db:"validation_error" json:"validation_error"` } type User struct { diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 0ba92dd09326b..8a20cc7180125 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -3543,7 +3543,7 @@ func (q *sqlQuerier) UpdateTemplateMetaByID(ctx context.Context, arg UpdateTempl } const getTemplateVersionParameters = `-- name: GetTemplateVersionParameters :many -SELECT template_version_id, name, description, type, mutable, default_value, icon, options, validation_regex, validation_min, validation_max FROM template_version_parameters WHERE template_version_id = $1 +SELECT template_version_id, name, description, type, mutable, default_value, icon, options, validation_regex, validation_min, validation_max, validation_error FROM template_version_parameters WHERE template_version_id = $1 ` func (q *sqlQuerier) GetTemplateVersionParameters(ctx context.Context, templateVersionID uuid.UUID) ([]TemplateVersionParameter, error) { @@ -3567,6 +3567,7 @@ func (q *sqlQuerier) GetTemplateVersionParameters(ctx context.Context, templateV &i.ValidationRegex, &i.ValidationMin, &i.ValidationMax, + &i.ValidationError, ); err != nil { return nil, err } @@ -3594,7 +3595,8 @@ INSERT INTO options, validation_regex, validation_min, - validation_max + validation_max, + validation_error ) VALUES ( @@ -3608,8 +3610,9 @@ VALUES $8, $9, $10, - $11 - ) RETURNING template_version_id, name, description, type, mutable, default_value, icon, options, validation_regex, validation_min, validation_max + $11, + $12 + ) RETURNING template_version_id, name, description, type, mutable, default_value, icon, options, validation_regex, validation_min, validation_max, validation_error ` type InsertTemplateVersionParameterParams struct { @@ -3624,6 +3627,7 @@ type InsertTemplateVersionParameterParams struct { ValidationRegex string `db:"validation_regex" json:"validation_regex"` ValidationMin int32 `db:"validation_min" json:"validation_min"` ValidationMax int32 `db:"validation_max" json:"validation_max"` + ValidationError string `db:"validation_error" json:"validation_error"` } func (q *sqlQuerier) InsertTemplateVersionParameter(ctx context.Context, arg InsertTemplateVersionParameterParams) (TemplateVersionParameter, error) { @@ -3639,6 +3643,7 @@ func (q *sqlQuerier) InsertTemplateVersionParameter(ctx context.Context, arg Ins arg.ValidationRegex, arg.ValidationMin, arg.ValidationMax, + arg.ValidationError, ) var i TemplateVersionParameter err := row.Scan( @@ -3653,6 +3658,7 @@ func (q *sqlQuerier) InsertTemplateVersionParameter(ctx context.Context, arg Ins &i.ValidationRegex, &i.ValidationMin, &i.ValidationMax, + &i.ValidationError, ) return i, err } diff --git a/coderd/database/queries/templateversionparameters.sql b/coderd/database/queries/templateversionparameters.sql index 7fa247f279392..6fa2119f9b968 100644 --- a/coderd/database/queries/templateversionparameters.sql +++ b/coderd/database/queries/templateversionparameters.sql @@ -11,7 +11,8 @@ INSERT INTO options, validation_regex, validation_min, - validation_max + validation_max, + validation_error ) VALUES ( @@ -25,7 +26,8 @@ VALUES $8, $9, $10, - $11 + $11, + $12 ) RETURNING *; -- name: GetTemplateVersionParameters :many diff --git a/coderd/provisionerdserver/provisionerdserver.go b/coderd/provisionerdserver/provisionerdserver.go index 9f5ffa68f0e0a..1c2191d92f377 100644 --- a/coderd/provisionerdserver/provisionerdserver.go +++ b/coderd/provisionerdserver/provisionerdserver.go @@ -647,6 +647,7 @@ func (server *Server) CompleteJob(ctx context.Context, completed *proto.Complete Icon: richParameter.Icon, Options: options, ValidationRegex: richParameter.ValidationRegex, + ValidationError: richParameter.ValidationError, ValidationMin: richParameter.ValidationMin, ValidationMax: richParameter.ValidationMax, }) diff --git a/coderd/templateversions.go b/coderd/templateversions.go index 8ec633d32fde3..abcf87ce1ee3c 100644 --- a/coderd/templateversions.go +++ b/coderd/templateversions.go @@ -1414,6 +1414,7 @@ func convertTemplateVersionParameter(param database.TemplateVersionParameter) (c ValidationRegex: param.ValidationRegex, ValidationMin: param.ValidationMin, ValidationMax: param.ValidationMax, + ValidationError: param.ValidationError, }, nil } diff --git a/coderd/workspacebuilds_test.go b/coderd/workspacebuilds_test.go index 76e2718030eb0..5caef361d52b7 100644 --- a/coderd/workspacebuilds_test.go +++ b/coderd/workspacebuilds_test.go @@ -883,12 +883,11 @@ func TestWorkspaceBuildValidateRichParameters(t *testing.T) { {Name: boolParameterName, Type: "bool", Mutable: true}, } - /* FIXME regexRichParameters := []*proto.RichParameter{ - {Name: stringParameterName, Type: "string", Mutable: true, ValidationRegex: "[a-z]+"}, + {Name: stringParameterName, Type: "string", Mutable: true, ValidationRegex: "^[a-z]+$", ValidationError: "this is error"}, {Name: numberParameterName, Type: "number", Mutable: true}, {Name: boolParameterName, Type: "bool", Mutable: true}, - }*/ + } tests := []struct { parameterName string @@ -904,17 +903,18 @@ func TestWorkspaceBuildValidateRichParameters(t *testing.T) { {stringParameterName, "", false, stringRichParameters}, {stringParameterName, "foobar", true, stringRichParameters}, - /* FIXME can't validate build parameter "string_parameter": an error must be specified with a regex validation {stringParameterName, "abcd", true, regexRichParameters}, - {stringParameterName, "abcd1", false, regexRichParameters},*/ + {stringParameterName, "abcd1", false, regexRichParameters}, {boolParameterName, "true", true, boolRichParameters}, {boolParameterName, "false", true, boolRichParameters}, - // FIXME {boolParameterName, "cat", false, boolRichParameters}, + {boolParameterName, "cat", false, boolRichParameters}, } for _, tc := range tests { t.Run(tc.parameterName+"-"+tc.value, 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, prepareEchoResponses(tc.richParameters)) @@ -928,7 +928,6 @@ func TestWorkspaceBuildValidateRichParameters(t *testing.T) { 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() diff --git a/codersdk/richparameters.go b/codersdk/richparameters.go index 4ba0fe9beb3ad..29351884a1511 100644 --- a/codersdk/richparameters.go +++ b/codersdk/richparameters.go @@ -10,7 +10,7 @@ func ValidateWorkspaceBuildParameters(richParameters []TemplateVersionParameter, for _, buildParameter := range buildParameters { richParameter, found := findTemplateVersionParameter(richParameters, buildParameter.Name) if !found { - return xerrors.Errorf(`workspace build parameter is not defined in the template ("coder_parameter")`) + return xerrors.Errorf(`workspace build parameter is not defined in the template ("coder_parameter"): %s`, buildParameter.Name) } err := ValidateWorkspaceBuildParameter(*richParameter, buildParameter) @@ -41,6 +41,11 @@ func ValidateWorkspaceBuildParameter(richParameter TemplateVersionParameter, bui return nil } + // Method provider.Validation.Valid() does not check the boolean type correctness, so it has to be checked here. + if richParameter.Type == "bool" && (buildParameter.Value != "true" && buildParameter.Value != "false") { + return xerrors.Errorf("%q is not a bool", richParameter.Type) + } + if !validationEnabled(richParameter) { return nil } @@ -49,7 +54,7 @@ func ValidateWorkspaceBuildParameter(richParameter TemplateVersionParameter, bui Min: int(richParameter.ValidationMin), Max: int(richParameter.ValidationMax), Regex: richParameter.ValidationRegex, - // TODO Error: ?, + Error: richParameter.ValidationError, } return validation.Valid(richParameter.Type, buildParameter.Value) } diff --git a/provisioner/terraform/resources.go b/provisioner/terraform/resources.go index 7e701cc82749e..cda20a127fa17 100644 --- a/provisioner/terraform/resources.go +++ b/provisioner/terraform/resources.go @@ -421,6 +421,7 @@ func ConvertResourcesAndParameters(modules []*tfjson.StateModule, rawGraph strin } if len(param.Validation) == 1 { protoParam.ValidationRegex = param.Validation[0].Regex + protoParam.ValidationError = param.Validation[0].Error protoParam.ValidationMax = int32(param.Validation[0].Max) protoParam.ValidationMin = int32(param.Validation[0].Min) } diff --git a/provisionersdk/proto/provisioner.pb.go b/provisionersdk/proto/provisioner.pb.go index 1355451e5c57e..fa12eae587763 100644 --- a/provisionersdk/proto/provisioner.pb.go +++ b/provisionersdk/proto/provisioner.pb.go @@ -730,8 +730,9 @@ type RichParameter struct { Icon string `protobuf:"bytes,6,opt,name=icon,proto3" json:"icon,omitempty"` Options []*RichParameterOption `protobuf:"bytes,7,rep,name=options,proto3" json:"options,omitempty"` ValidationRegex string `protobuf:"bytes,8,opt,name=validation_regex,json=validationRegex,proto3" json:"validation_regex,omitempty"` - ValidationMin int32 `protobuf:"varint,9,opt,name=validation_min,json=validationMin,proto3" json:"validation_min,omitempty"` - ValidationMax int32 `protobuf:"varint,10,opt,name=validation_max,json=validationMax,proto3" json:"validation_max,omitempty"` + ValidationError string `protobuf:"bytes,9,opt,name=validation_error,json=validationError,proto3" json:"validation_error,omitempty"` + ValidationMin int32 `protobuf:"varint,10,opt,name=validation_min,json=validationMin,proto3" json:"validation_min,omitempty"` + ValidationMax int32 `protobuf:"varint,11,opt,name=validation_max,json=validationMax,proto3" json:"validation_max,omitempty"` } func (x *RichParameter) Reset() { @@ -822,6 +823,13 @@ func (x *RichParameter) GetValidationRegex() string { return "" } +func (x *RichParameter) GetValidationError() string { + if x != nil { + return x.ValidationError + } + return "" +} + func (x *RichParameter) GetValidationMin() int32 { if x != nil { return x.ValidationMin @@ -1010,7 +1018,6 @@ type Agent struct { Directory string `protobuf:"bytes,7,opt,name=directory,proto3" json:"directory,omitempty"` Apps []*App `protobuf:"bytes,8,rep,name=apps,proto3" json:"apps,omitempty"` // Types that are assignable to Auth: - // // *Agent_Token // *Agent_InstanceId Auth isAgent_Auth `protobuf_oneof:"auth"` @@ -1697,7 +1704,6 @@ type Parse_Response struct { unknownFields protoimpl.UnknownFields // Types that are assignable to Type: - // // *Parse_Response_Log // *Parse_Response_Complete Type isParse_Response_Type `protobuf_oneof:"type"` @@ -2094,7 +2100,6 @@ type Provision_Request struct { unknownFields protoimpl.UnknownFields // Types that are assignable to Type: - // // *Provision_Request_Plan // *Provision_Request_Apply // *Provision_Request_Cancel @@ -2268,7 +2273,6 @@ type Provision_Response struct { unknownFields protoimpl.UnknownFields // Types that are assignable to Type: - // // *Provision_Response_Log // *Provision_Response_Complete Type isProvision_Response_Type `protobuf_oneof:"type"` @@ -2424,8 +2428,8 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x63, - 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x22, 0xe1, - 0x02, 0x0a, 0x0d, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, + 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x22, 0x8c, + 0x03, 0x0a, 0x0d, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, @@ -2442,228 +2446,230 @@ var file_provisionersdk_proto_provisioner_proto_rawDesc = []byte{ 0x52, 0x07, 0x6f, 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x12, 0x29, 0x0a, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x72, 0x65, 0x67, 0x65, 0x78, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, - 0x65, 0x67, 0x65, 0x78, 0x12, 0x25, 0x0a, 0x0e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, - 0x6f, 0x6e, 0x5f, 0x6d, 0x69, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x76, 0x61, - 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x69, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x76, - 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x0a, 0x20, - 0x01, 0x28, 0x05, 0x52, 0x0d, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, - 0x61, 0x78, 0x22, 0x3e, 0x0a, 0x12, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, - 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, - 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, - 0x75, 0x65, 0x22, 0x4a, 0x0a, 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x2b, 0x0a, 0x05, 0x6c, 0x65, 0x76, - 0x65, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, - 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, - 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, - 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x37, - 0x0a, 0x14, 0x49, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, - 0x74, 0x79, 0x41, 0x75, 0x74, 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, - 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x22, 0x9b, 0x04, 0x0a, 0x05, 0x41, 0x67, 0x65, 0x6e, - 0x74, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, - 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x2d, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x03, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, - 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x2e, 0x45, 0x6e, 0x76, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, - 0x03, 0x65, 0x6e, 0x76, 0x12, 0x25, 0x0a, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x5f, - 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x74, - 0x61, 0x72, 0x74, 0x75, 0x70, 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x6f, - 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, - 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, - 0x53, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, - 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x72, - 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x69, - 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, - 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x12, 0x24, 0x0a, 0x04, 0x61, 0x70, 0x70, 0x73, - 0x18, 0x08, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x70, 0x70, 0x52, 0x04, 0x61, 0x70, 0x70, 0x73, 0x12, 0x16, - 0x0a, 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, - 0x05, 0x74, 0x6f, 0x6b, 0x65, 0x6e, 0x12, 0x21, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, - 0x63, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, 0x69, - 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x12, 0x3c, 0x0a, 0x1a, 0x63, 0x6f, 0x6e, - 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, - 0x73, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x18, 0x63, - 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, - 0x53, 0x65, 0x63, 0x6f, 0x6e, 0x64, 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x74, 0x72, 0x6f, 0x75, 0x62, - 0x6c, 0x65, 0x73, 0x68, 0x6f, 0x6f, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x0c, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x12, 0x74, 0x72, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x73, 0x68, 0x6f, - 0x6f, 0x74, 0x69, 0x6e, 0x67, 0x55, 0x72, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x6f, 0x74, 0x64, - 0x5f, 0x66, 0x69, 0x6c, 0x65, 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x6f, 0x74, - 0x64, 0x46, 0x69, 0x6c, 0x65, 0x1a, 0x36, 0x0a, 0x08, 0x45, 0x6e, 0x76, 0x45, 0x6e, 0x74, 0x72, - 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, - 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x06, 0x0a, - 0x04, 0x61, 0x75, 0x74, 0x68, 0x22, 0xb5, 0x02, 0x0a, 0x03, 0x41, 0x70, 0x70, 0x12, 0x12, 0x0a, - 0x04, 0x73, 0x6c, 0x75, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x6c, 0x75, - 0x67, 0x12, 0x21, 0x0a, 0x0c, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, - 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, - 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x10, - 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, - 0x12, 0x12, 0x0a, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, - 0x69, 0x63, 0x6f, 0x6e, 0x12, 0x1c, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, - 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x09, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, - 0x69, 0x6e, 0x12, 0x3a, 0x0a, 0x0b, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, - 0x6b, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, - 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, - 0x6b, 0x52, 0x0b, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x41, - 0x0a, 0x0d, 0x73, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, - 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, - 0x76, 0x65, 0x6c, 0x52, 0x0c, 0x73, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, - 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x09, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x08, 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x22, 0x59, 0x0a, - 0x0b, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x10, 0x0a, 0x03, - 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1a, - 0x0a, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, - 0x52, 0x08, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, - 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, - 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, 0x6c, 0x64, 0x22, 0xf1, 0x02, 0x0a, 0x08, 0x52, 0x65, 0x73, - 0x6f, 0x75, 0x72, 0x63, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, - 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, + 0x65, 0x67, 0x65, 0x78, 0x12, 0x29, 0x0a, 0x10, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0f, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x45, 0x72, 0x72, 0x6f, 0x72, 0x12, + 0x25, 0x0a, 0x0e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x69, + 0x6e, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, + 0x69, 0x6f, 0x6e, 0x4d, 0x69, 0x6e, 0x12, 0x25, 0x0a, 0x0e, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, + 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x6d, 0x61, 0x78, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, + 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x4d, 0x61, 0x78, 0x22, 0x3e, 0x0a, + 0x12, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, + 0x6c, 0x75, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x22, 0x4a, 0x0a, + 0x03, 0x4c, 0x6f, 0x67, 0x12, 0x2b, 0x0a, 0x05, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x01, 0x20, + 0x01, 0x28, 0x0e, 0x32, 0x15, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, + 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x05, 0x6c, 0x65, 0x76, 0x65, + 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x06, 0x6f, 0x75, 0x74, 0x70, 0x75, 0x74, 0x22, 0x37, 0x0a, 0x14, 0x49, 0x6e, 0x73, + 0x74, 0x61, 0x6e, 0x63, 0x65, 0x49, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x41, 0x75, 0x74, + 0x68, 0x12, 0x1f, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, + 0x49, 0x64, 0x22, 0x9b, 0x04, 0x0a, 0x05, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x12, 0x0e, 0x0a, 0x02, + 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, + 0x12, 0x2d, 0x0a, 0x03, 0x65, 0x6e, 0x76, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, - 0x74, 0x52, 0x06, 0x61, 0x67, 0x65, 0x6e, 0x74, 0x73, 0x12, 0x3a, 0x0a, 0x08, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, - 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, - 0x63, 0x65, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, - 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x12, 0x0a, 0x04, 0x68, 0x69, 0x64, 0x65, 0x18, 0x05, 0x20, - 0x01, 0x28, 0x08, 0x52, 0x04, 0x68, 0x69, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x63, 0x6f, - 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x12, 0x23, 0x0a, - 0x0d, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x07, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x79, - 0x70, 0x65, 0x12, 0x1d, 0x0a, 0x0a, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x5f, 0x63, 0x6f, 0x73, 0x74, - 0x18, 0x08, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x43, 0x6f, 0x73, - 0x74, 0x1a, 0x69, 0x0a, 0x08, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 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, 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, 0xfc, 0x01, 0x0a, - 0x05, 0x50, 0x61, 0x72, 0x73, 0x65, 0x1a, 0x27, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, - 0x74, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x1a, - 0x55, 0x0a, 0x08, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x49, 0x0a, 0x11, 0x70, - 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, - 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, - 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x63, - 0x68, 0x65, 0x6d, 0x61, 0x52, 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, - 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x1a, 0x73, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, - 0x73, 0x65, 0x12, 0x24, 0x0a, 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, - 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, - 0x67, 0x48, 0x00, 0x52, 0x03, 0x6c, 0x6f, 0x67, 0x12, 0x39, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, - 0x6c, 0x65, 0x74, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, - 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x2e, 0x43, - 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x48, 0x00, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, - 0x65, 0x74, 0x65, 0x42, 0x06, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x82, 0x0a, 0x0a, 0x09, - 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0xd1, 0x02, 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, 0x1a, 0x79, 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, 0x1a, 0xda, 0x01, 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, 0x46, 0x0a, 0x10, 0x70, 0x61, 0x72, 0x61, - 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, - 0x2e, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, - 0x0f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, - 0x12, 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, 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, + 0x74, 0x2e, 0x45, 0x6e, 0x76, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x03, 0x65, 0x6e, 0x76, 0x12, + 0x25, 0x0a, 0x0e, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, 0x5f, 0x73, 0x63, 0x72, 0x69, 0x70, + 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0d, 0x73, 0x74, 0x61, 0x72, 0x74, 0x75, 0x70, + 0x53, 0x63, 0x72, 0x69, 0x70, 0x74, 0x12, 0x29, 0x0a, 0x10, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, + 0x69, 0x6e, 0x67, 0x5f, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x0f, 0x6f, 0x70, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x53, 0x79, 0x73, 0x74, 0x65, + 0x6d, 0x12, 0x22, 0x0a, 0x0c, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, 0x63, 0x74, 0x75, 0x72, + 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0c, 0x61, 0x72, 0x63, 0x68, 0x69, 0x74, 0x65, + 0x63, 0x74, 0x75, 0x72, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, + 0x72, 0x79, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, + 0x6f, 0x72, 0x79, 0x12, 0x24, 0x0a, 0x04, 0x61, 0x70, 0x70, 0x73, 0x18, 0x08, 0x20, 0x03, 0x28, + 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, + 0x41, 0x70, 0x70, 0x52, 0x04, 0x61, 0x70, 0x70, 0x73, 0x12, 0x16, 0x0a, 0x05, 0x74, 0x6f, 0x6b, + 0x65, 0x6e, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x05, 0x74, 0x6f, 0x6b, 0x65, + 0x6e, 0x12, 0x21, 0x0a, 0x0b, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x69, 0x64, + 0x18, 0x0a, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x0a, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, + 0x63, 0x65, 0x49, 0x64, 0x12, 0x3c, 0x0a, 0x1a, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, 0x74, 0x69, + 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x5f, 0x73, 0x65, 0x63, 0x6f, 0x6e, + 0x64, 0x73, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x05, 0x52, 0x18, 0x63, 0x6f, 0x6e, 0x6e, 0x65, 0x63, + 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x6f, 0x75, 0x74, 0x53, 0x65, 0x63, 0x6f, 0x6e, + 0x64, 0x73, 0x12, 0x2f, 0x0a, 0x13, 0x74, 0x72, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x73, 0x68, 0x6f, + 0x6f, 0x74, 0x69, 0x6e, 0x67, 0x5f, 0x75, 0x72, 0x6c, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x12, 0x74, 0x72, 0x6f, 0x75, 0x62, 0x6c, 0x65, 0x73, 0x68, 0x6f, 0x6f, 0x74, 0x69, 0x6e, 0x67, + 0x55, 0x72, 0x6c, 0x12, 0x1b, 0x0a, 0x09, 0x6d, 0x6f, 0x74, 0x64, 0x5f, 0x66, 0x69, 0x6c, 0x65, + 0x18, 0x0d, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x6f, 0x74, 0x64, 0x46, 0x69, 0x6c, 0x65, + 0x1a, 0x36, 0x0a, 0x08, 0x45, 0x6e, 0x76, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, + 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, + 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, + 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x42, 0x06, 0x0a, 0x04, 0x61, 0x75, 0x74, 0x68, + 0x22, 0xb5, 0x02, 0x0a, 0x03, 0x41, 0x70, 0x70, 0x12, 0x12, 0x0a, 0x04, 0x73, 0x6c, 0x75, 0x67, + 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x73, 0x6c, 0x75, 0x67, 0x12, 0x21, 0x0a, 0x0c, + 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x0b, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x4e, 0x61, 0x6d, 0x65, 0x12, + 0x18, 0x0a, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x07, 0x63, 0x6f, 0x6d, 0x6d, 0x61, 0x6e, 0x64, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x12, 0x0a, 0x04, 0x69, + 0x63, 0x6f, 0x6e, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x12, + 0x1c, 0x0a, 0x09, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x08, 0x52, 0x09, 0x73, 0x75, 0x62, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x3a, 0x0a, + 0x0b, 0x68, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x18, 0x07, 0x20, 0x01, + 0x28, 0x0b, 0x32, 0x18, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, + 0x2e, 0x48, 0x65, 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x52, 0x0b, 0x68, 0x65, + 0x61, 0x6c, 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x41, 0x0a, 0x0d, 0x73, 0x68, 0x61, + 0x72, 0x69, 0x6e, 0x67, 0x5f, 0x6c, 0x65, 0x76, 0x65, 0x6c, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, + 0x70, 0x70, 0x53, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x52, 0x0c, + 0x73, 0x68, 0x61, 0x72, 0x69, 0x6e, 0x67, 0x4c, 0x65, 0x76, 0x65, 0x6c, 0x12, 0x1a, 0x0a, 0x08, + 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x18, 0x09, 0x20, 0x01, 0x28, 0x08, 0x52, 0x08, + 0x65, 0x78, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x22, 0x59, 0x0a, 0x0b, 0x48, 0x65, 0x61, 0x6c, + 0x74, 0x68, 0x63, 0x68, 0x65, 0x63, 0x6b, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x76, 0x61, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x08, 0x69, 0x6e, 0x74, + 0x65, 0x72, 0x76, 0x61, 0x6c, 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, 0x6f, + 0x6c, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x09, 0x74, 0x68, 0x72, 0x65, 0x73, 0x68, + 0x6f, 0x6c, 0x64, 0x22, 0xf1, 0x02, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, + 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, + 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x61, 0x67, 0x65, 0x6e, + 0x74, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x41, 0x67, 0x65, 0x6e, 0x74, 0x52, 0x06, 0x61, 0x67, + 0x65, 0x6e, 0x74, 0x73, 0x12, 0x3a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, + 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x2e, 0x4d, 0x65, + 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x12, 0x12, 0x0a, 0x04, 0x68, 0x69, 0x64, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, + 0x68, 0x69, 0x64, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x18, 0x06, 0x20, 0x01, + 0x28, 0x09, 0x52, 0x04, 0x69, 0x63, 0x6f, 0x6e, 0x12, 0x23, 0x0a, 0x0d, 0x69, 0x6e, 0x73, 0x74, + 0x61, 0x6e, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x0c, 0x69, 0x6e, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x1d, 0x0a, + 0x0a, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x5f, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x08, 0x20, 0x01, 0x28, + 0x05, 0x52, 0x09, 0x64, 0x61, 0x69, 0x6c, 0x79, 0x43, 0x6f, 0x73, 0x74, 0x1a, 0x69, 0x0a, 0x08, + 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 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, + 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, 0xfc, 0x01, 0x0a, 0x05, 0x50, 0x61, 0x72, 0x73, + 0x65, 0x1a, 0x27, 0x0a, 0x07, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x09, + 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, + 0x09, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x79, 0x1a, 0x55, 0x0a, 0x08, 0x43, 0x6f, + 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x12, 0x49, 0x0a, 0x11, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, + 0x74, 0x65, 0x72, 0x5f, 0x73, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1c, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, - 0x50, 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, + 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, 0x52, + 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x53, 0x63, 0x68, 0x65, 0x6d, 0x61, + 0x73, 0x1a, 0x73, 0x0a, 0x08, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x24, 0x0a, + 0x03, 0x6c, 0x6f, 0x67, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x10, 0x2e, 0x70, 0x72, 0x6f, + 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x4c, 0x6f, 0x67, 0x48, 0x00, 0x52, 0x03, + 0x6c, 0x6f, 0x67, 0x12, 0x39, 0x0a, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1b, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, + 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x73, 0x65, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, + 0x74, 0x65, 0x48, 0x00, 0x52, 0x08, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x42, 0x06, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x22, 0x82, 0x0a, 0x0a, 0x09, 0x50, 0x72, 0x6f, 0x76, 0x69, + 0x73, 0x69, 0x6f, 0x6e, 0x1a, 0xd1, 0x02, 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, 0x1a, 0x79, 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, 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, 0xbb, 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, 0x12, 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x05, 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, + 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, + 0x61, 0x74, 0x61, 0x1a, 0xda, 0x01, 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, 0x46, 0x0a, 0x10, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, + 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1b, 0x2e, + 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x61, 0x72, 0x61, + 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0f, 0x70, 0x61, 0x72, 0x61, + 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 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, + 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, 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, 0x2d, 0x5a, - 0x2b, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, - 0x72, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, - 0x6e, 0x65, 0x72, 0x73, 0x64, 0x6b, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, - 0x6f, 0x74, 0x6f, 0x33, + 0x2e, 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, 0xbb, 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, 0x12, + 0x0a, 0x04, 0x70, 0x6c, 0x61, 0x6e, 0x18, 0x05, 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, 0x2d, 0x5a, 0x2b, 0x67, 0x69, 0x74, 0x68, + 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x63, 0x6f, 0x64, 0x65, 0x72, 0x2f, 0x63, 0x6f, 0x64, + 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x73, 0x64, + 0x6b, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/provisionersdk/proto/provisioner.proto b/provisionersdk/proto/provisioner.proto index c1dcb09fcee8e..223675d9f79ed 100644 --- a/provisionersdk/proto/provisioner.proto +++ b/provisionersdk/proto/provisioner.proto @@ -70,8 +70,9 @@ message RichParameter { string icon = 6; repeated RichParameterOption options = 7; string validation_regex = 8; - int32 validation_min = 9; - int32 validation_max = 10; + string validation_error = 9; + int32 validation_min = 10; + int32 validation_max = 11; } // RichParameterValue holds the key/value mapping of a parameter. diff --git a/provisionersdk/proto/provisioner_drpc.pb.go b/provisionersdk/proto/provisioner_drpc.pb.go index c990f6f645b7f..d307402447c78 100644 --- a/provisionersdk/proto/provisioner_drpc.pb.go +++ b/provisionersdk/proto/provisioner_drpc.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-go-drpc. DO NOT EDIT. -// protoc-gen-go-drpc version: v0.0.26 +// protoc-gen-go-drpc version: (devel) // source: provisionersdk/proto/provisioner.proto package proto From f655603d5ea2b9a07bde0b5644a72476c3b2e13c Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 23 Jan 2023 12:46:38 +0100 Subject: [PATCH 20/34] fix --- provisionersdk/proto/provisioner.pb.go | 4 ++++ provisionersdk/proto/provisioner_drpc.pb.go | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/provisionersdk/proto/provisioner.pb.go b/provisionersdk/proto/provisioner.pb.go index fa12eae587763..e3e7953785e90 100644 --- a/provisionersdk/proto/provisioner.pb.go +++ b/provisionersdk/proto/provisioner.pb.go @@ -1018,6 +1018,7 @@ type Agent struct { Directory string `protobuf:"bytes,7,opt,name=directory,proto3" json:"directory,omitempty"` Apps []*App `protobuf:"bytes,8,rep,name=apps,proto3" json:"apps,omitempty"` // Types that are assignable to Auth: + // // *Agent_Token // *Agent_InstanceId Auth isAgent_Auth `protobuf_oneof:"auth"` @@ -1704,6 +1705,7 @@ type Parse_Response struct { unknownFields protoimpl.UnknownFields // Types that are assignable to Type: + // // *Parse_Response_Log // *Parse_Response_Complete Type isParse_Response_Type `protobuf_oneof:"type"` @@ -2100,6 +2102,7 @@ type Provision_Request struct { unknownFields protoimpl.UnknownFields // Types that are assignable to Type: + // // *Provision_Request_Plan // *Provision_Request_Apply // *Provision_Request_Cancel @@ -2273,6 +2276,7 @@ type Provision_Response struct { unknownFields protoimpl.UnknownFields // Types that are assignable to Type: + // // *Provision_Response_Log // *Provision_Response_Complete Type isProvision_Response_Type `protobuf_oneof:"type"` diff --git a/provisionersdk/proto/provisioner_drpc.pb.go b/provisionersdk/proto/provisioner_drpc.pb.go index d307402447c78..c990f6f645b7f 100644 --- a/provisionersdk/proto/provisioner_drpc.pb.go +++ b/provisionersdk/proto/provisioner_drpc.pb.go @@ -1,5 +1,5 @@ // Code generated by protoc-gen-go-drpc. DO NOT EDIT. -// protoc-gen-go-drpc version: (devel) +// protoc-gen-go-drpc version: v0.0.26 // source: provisionersdk/proto/provisioner.proto package proto From f35ec025f317a79e27b72181fe651eab77c8bc36 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 23 Jan 2023 12:55:12 +0100 Subject: [PATCH 21/34] merge --- ....down.sql => 000091_rich_parameters_validation_error.down.sql} | 0 ...rror.up.sql => 000091_rich_parameters_validation_error.up.sql} | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename coderd/database/migrations/{000090_rich_parameters_validation_error.down.sql => 000091_rich_parameters_validation_error.down.sql} (100%) rename coderd/database/migrations/{000090_rich_parameters_validation_error.up.sql => 000091_rich_parameters_validation_error.up.sql} (100%) diff --git a/coderd/database/migrations/000090_rich_parameters_validation_error.down.sql b/coderd/database/migrations/000091_rich_parameters_validation_error.down.sql similarity index 100% rename from coderd/database/migrations/000090_rich_parameters_validation_error.down.sql rename to coderd/database/migrations/000091_rich_parameters_validation_error.down.sql diff --git a/coderd/database/migrations/000090_rich_parameters_validation_error.up.sql b/coderd/database/migrations/000091_rich_parameters_validation_error.up.sql similarity index 100% rename from coderd/database/migrations/000090_rich_parameters_validation_error.up.sql rename to coderd/database/migrations/000091_rich_parameters_validation_error.up.sql From cfb1d4b10bba9945b579647f6c0cb827bb5fd94a Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 23 Jan 2023 13:04:07 +0100 Subject: [PATCH 22/34] Fix --- coderd/database/queries.sql.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index 67227ee5a85bf..c6f79bed7c2e8 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -45,7 +45,7 @@ func (q *sqlQuerier) GetLatestAgentStat(ctx context.Context, agentID uuid.UUID) } const getTemplateDAUs = `-- name: GetTemplateDAUs :many -SELECT +SELECT (created_at at TIME ZONE 'UTC')::date as date, user_id FROM @@ -2425,7 +2425,7 @@ WHERE -- Ensure the caller has the correct provisioner. AND nested.provisioner = ANY($3 :: provisioner_type [ ]) -- Ensure the caller satisfies all job tags. - AND nested.tags <@ $4 :: jsonb + AND nested.tags <@ $4 :: jsonb ORDER BY nested.created_at FOR UPDATE @@ -3611,7 +3611,7 @@ VALUES $9, $10, $11, - $12 + $12 ) RETURNING template_version_id, name, description, type, mutable, default_value, icon, options, validation_regex, validation_min, validation_max, validation_error ` From fc3e03942dbf07e1ccead2ff61b5be5a1fc97c78 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 23 Jan 2023 14:25:49 +0100 Subject: [PATCH 23/34] fix --- coderd/database/queries.sql.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/coderd/database/queries.sql.go b/coderd/database/queries.sql.go index c6f79bed7c2e8..838a1c513e538 100644 --- a/coderd/database/queries.sql.go +++ b/coderd/database/queries.sql.go @@ -45,7 +45,7 @@ func (q *sqlQuerier) GetLatestAgentStat(ctx context.Context, agentID uuid.UUID) } const getTemplateDAUs = `-- name: GetTemplateDAUs :many -SELECT +SELECT (created_at at TIME ZONE 'UTC')::date as date, user_id FROM @@ -2425,7 +2425,7 @@ WHERE -- Ensure the caller has the correct provisioner. AND nested.provisioner = ANY($3 :: provisioner_type [ ]) -- Ensure the caller satisfies all job tags. - AND nested.tags <@ $4 :: jsonb + AND nested.tags <@ $4 :: jsonb ORDER BY nested.created_at FOR UPDATE From ebddd3cab86bed246d63719e41162f891323b063 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 23 Jan 2023 15:00:52 +0100 Subject: [PATCH 24/34] fix: default null --- coderd/database/dump.sql | 2 +- .../migrations/000091_rich_parameters_validation_error.up.sql | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/coderd/database/dump.sql b/coderd/database/dump.sql index c1a4881218bf4..5f1fee8b36a7a 100644 --- a/coderd/database/dump.sql +++ b/coderd/database/dump.sql @@ -343,7 +343,7 @@ CREATE TABLE template_version_parameters ( validation_regex text NOT NULL, validation_min integer NOT NULL, validation_max integer NOT NULL, - validation_error text NOT NULL + validation_error text DEFAULT ''::text NOT NULL ); COMMENT ON COLUMN template_version_parameters.name IS 'Parameter name'; diff --git a/coderd/database/migrations/000091_rich_parameters_validation_error.up.sql b/coderd/database/migrations/000091_rich_parameters_validation_error.up.sql index d1c21deb4330c..d8b59dddd82be 100644 --- a/coderd/database/migrations/000091_rich_parameters_validation_error.up.sql +++ b/coderd/database/migrations/000091_rich_parameters_validation_error.up.sql @@ -1,4 +1,4 @@ -ALTER TABLE template_version_parameters ADD COLUMN validation_error text NOT NULL; +ALTER TABLE template_version_parameters ADD COLUMN validation_error text NOT NULL DEFAULT ''; COMMENT ON COLUMN template_version_parameters.validation_error IS 'Validation: error displayed when the regex does not match.'; From cfd033037b820da039dcef993552d4ae3a2f5811 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 23 Jan 2023 16:33:12 +0100 Subject: [PATCH 25/34] CLI validation --- cli/cliui/parameter.go | 11 ++++++++++- codersdk/richparameters.go | 2 +- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/cli/cliui/parameter.go b/cli/cliui/parameter.go index e19e09671dada..2377b775d6173 100644 --- a/cli/cliui/parameter.go +++ b/cli/cliui/parameter.go @@ -67,7 +67,6 @@ func RichParameter(cmd *cobra.Command, templateVersionParameter codersdk.Templat _, _ = 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 { @@ -91,6 +90,9 @@ func RichParameter(cmd *cobra.Command, templateVersionParameter codersdk.Templat value, err = Prompt(cmd, PromptOptions{ Text: Styles.Bold.Render(text), + Validate: func(value string) error { + return validateRichPrompt(value, templateVersionParameter) + }, }) value = strings.TrimSpace(value) } @@ -113,3 +115,10 @@ func templateVersionParameterOptionValues(param codersdk.TemplateVersionParamete } return options } + +func validateRichPrompt(value string, p codersdk.TemplateVersionParameter) error { + return codersdk.ValidateWorkspaceBuildParameter(p, codersdk.WorkspaceBuildParameter{ + Name: p.Name, + Value: value, + }) +} diff --git a/codersdk/richparameters.go b/codersdk/richparameters.go index 29351884a1511..ff784c33e81e3 100644 --- a/codersdk/richparameters.go +++ b/codersdk/richparameters.go @@ -43,7 +43,7 @@ func ValidateWorkspaceBuildParameter(richParameter TemplateVersionParameter, bui // Method provider.Validation.Valid() does not check the boolean type correctness, so it has to be checked here. if richParameter.Type == "bool" && (buildParameter.Value != "true" && buildParameter.Value != "false") { - return xerrors.Errorf("%q is not a bool", richParameter.Type) + return xerrors.Errorf(`boolean value can be either "true" or "false"`) } if !validationEnabled(richParameter) { From 83ddace3ea579e628ac4563b62b9b576a8cf0dc5 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 23 Jan 2023 16:34:36 +0100 Subject: [PATCH 26/34] fmt --- provisionersdk/proto/provisioner.proto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/provisionersdk/proto/provisioner.proto b/provisionersdk/proto/provisioner.proto index 223675d9f79ed..22f840a3ed410 100644 --- a/provisionersdk/proto/provisioner.proto +++ b/provisionersdk/proto/provisioner.proto @@ -70,7 +70,7 @@ message RichParameter { string icon = 6; repeated RichParameterOption options = 7; string validation_regex = 8; - string validation_error = 9; + string validation_error = 9; int32 validation_min = 10; int32 validation_max = 11; } From 2e7c5f496d968a425f2068fa1b1846d488bd32f3 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 23 Jan 2023 16:59:36 +0100 Subject: [PATCH 27/34] fix: default --- codersdk/richparameters.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/codersdk/richparameters.go b/codersdk/richparameters.go index ff784c33e81e3..bdf7f54f95f0c 100644 --- a/codersdk/richparameters.go +++ b/codersdk/richparameters.go @@ -22,10 +22,14 @@ func ValidateWorkspaceBuildParameters(richParameters []TemplateVersionParameter, } func ValidateWorkspaceBuildParameter(richParameter TemplateVersionParameter, buildParameter WorkspaceBuildParameter) error { - if buildParameter.Value == "" { + if buildParameter.Value == "" && richParameter.DefaultValue == "" { return xerrors.Errorf("parameter value can't be empty") } + if buildParameter.Value == "" { + return nil // Default value wins + } + if len(richParameter.Options) > 0 { var matched bool for _, opt := range richParameter.Options { From f317891462a153c9abdcbc133a00b165bdde44c1 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 23 Jan 2023 17:05:05 +0100 Subject: [PATCH 28/34] Fix --- codersdk/richparameters.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/codersdk/richparameters.go b/codersdk/richparameters.go index bdf7f54f95f0c..5171e332bce14 100644 --- a/codersdk/richparameters.go +++ b/codersdk/richparameters.go @@ -22,18 +22,19 @@ func ValidateWorkspaceBuildParameters(richParameters []TemplateVersionParameter, } func ValidateWorkspaceBuildParameter(richParameter TemplateVersionParameter, buildParameter WorkspaceBuildParameter) error { - if buildParameter.Value == "" && richParameter.DefaultValue == "" { - return xerrors.Errorf("parameter value can't be empty") + value := buildParameter.Value + if value == "" { + value = richParameter.DefaultValue } - if buildParameter.Value == "" { - return nil // Default value wins + if value == "" { + return xerrors.Errorf("parameter value can't be empty") } if len(richParameter.Options) > 0 { var matched bool for _, opt := range richParameter.Options { - if opt.Value == buildParameter.Value { + if opt.Value == value { matched = true break } @@ -46,7 +47,7 @@ func ValidateWorkspaceBuildParameter(richParameter TemplateVersionParameter, bui } // Method provider.Validation.Valid() does not check the boolean type correctness, so it has to be checked here. - if richParameter.Type == "bool" && (buildParameter.Value != "true" && buildParameter.Value != "false") { + if richParameter.Type == "bool" && (value != "true" && value != "false") { return xerrors.Errorf(`boolean value can be either "true" or "false"`) } @@ -60,7 +61,7 @@ func ValidateWorkspaceBuildParameter(richParameter TemplateVersionParameter, bui Regex: richParameter.ValidationRegex, Error: richParameter.ValidationError, } - return validation.Valid(richParameter.Type, buildParameter.Value) + return validation.Valid(richParameter.Type, value) } func findTemplateVersionParameter(params []TemplateVersionParameter, parameterName string) (*TemplateVersionParameter, bool) { From 695680e29d2c59365a88353dbe3eb2ad38dabd9a Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 23 Jan 2023 18:30:40 +0100 Subject: [PATCH 29/34] Pull new version of terraform-provider-coder --- codersdk/richparameters.go | 13 +++---------- go.mod | 2 +- go.sum | 12 ++++++++++-- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/codersdk/richparameters.go b/codersdk/richparameters.go index 5171e332bce14..ec3263706d499 100644 --- a/codersdk/richparameters.go +++ b/codersdk/richparameters.go @@ -27,10 +27,6 @@ func ValidateWorkspaceBuildParameter(richParameter TemplateVersionParameter, bui value = richParameter.DefaultValue } - if value == "" { - return xerrors.Errorf("parameter value can't be empty") - } - if len(richParameter.Options) > 0 { var matched bool for _, opt := range richParameter.Options { @@ -46,11 +42,6 @@ func ValidateWorkspaceBuildParameter(richParameter TemplateVersionParameter, bui return nil } - // Method provider.Validation.Valid() does not check the boolean type correctness, so it has to be checked here. - if richParameter.Type == "bool" && (value != "true" && value != "false") { - return xerrors.Errorf(`boolean value can be either "true" or "false"`) - } - if !validationEnabled(richParameter) { return nil } @@ -82,5 +73,7 @@ func parameterValuesAsArray(options []TemplateVersionParameterOption) []string { } func validationEnabled(param TemplateVersionParameter) bool { - return len(param.ValidationRegex) > 0 || (param.ValidationMin != 0 && param.ValidationMax != 0) + return len(param.ValidationRegex) > 0 || + (param.ValidationMin != 0 && param.ValidationMax != 0) || + param.Type == "bool" // boolean type doesn't have any custom validation rules, but the value must be checked (true/false). } diff --git a/go.mod b/go.mod index 4a0a0e1244523..41388c09aa777 100644 --- a/go.mod +++ b/go.mod @@ -67,6 +67,7 @@ require ( github.com/charmbracelet/lipgloss v0.6.0 github.com/cli/safeexec v1.0.0 github.com/coder/retry v1.3.0 + github.com/coder/terraform-provider-coder v0.6.8 github.com/coreos/go-oidc/v3 v3.4.0 github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf github.com/creack/pty v1.1.18 @@ -169,7 +170,6 @@ require ( require ( cloud.google.com/go/longrunning v0.1.1 // indirect - github.com/coder/terraform-provider-coder v0.6.6 // indirect github.com/hashicorp/go-cty v1.4.1-0.20200414143053-d3edf31b6320 // indirect github.com/hashicorp/go-hclog v1.2.1 // indirect github.com/hashicorp/go-uuid v1.0.3 // indirect diff --git a/go.sum b/go.sum index e094033970b02..5b85be824e5ec 100644 --- a/go.sum +++ b/go.sum @@ -203,6 +203,7 @@ github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g github.com/apache/arrow/go/arrow v0.0.0-20210818145353-234c94e4ce64/go.mod h1:2qMFB56yOP3KzkB3PbYZ4AlUFg3a88F67TIx5lB/WwY= github.com/apache/arrow/go/arrow v0.0.0-20211013220434-5962184e7a30/go.mod h1:Q7yQnSMnLvcXlZ8RV+jwz/6y1rQTqbX6C82SndT52Zs= github.com/apparentlymart/go-dump v0.0.0-20180507223929-23540a00eaa3/go.mod h1:oL81AME2rN47vu18xqj1S1jPIPuN7afo62yKTNn3XMM= +github.com/apparentlymart/go-dump v0.0.0-20190214190832-042adf3cf4a0 h1:MzVXffFUye+ZcSR6opIgz9Co7WcDx6ZcY+RjfFHoA0I= github.com/apparentlymart/go-textseg v1.0.0/go.mod h1:z96Txxhf3xSFMPmb5X/1W05FF/Nj9VFpLOpjS5yuumk= github.com/apparentlymart/go-textseg/v12 v12.0.0/go.mod h1:S/4uRK2UtaQttw1GenVJEynmyUenKwP++x/+DdGV/Ec= github.com/apparentlymart/go-textseg/v13 v13.0.0 h1:Y+KvPE1NYz0xl601PVImeQfFyEy6iT90AvPUL1NNfNw= @@ -362,8 +363,8 @@ github.com/coder/ssh v0.0.0-20220811105153-fcea99919338 h1:tN5GKFT68YLVzJoA8AHui github.com/coder/ssh v0.0.0-20220811105153-fcea99919338/go.mod h1:ZSS+CUoKHDrqVakTfTWUlKSr9MtMFkC4UvtQKD7O914= github.com/coder/tailscale v1.1.1-0.20221117204504-2d6503f027c3 h1:lq8GmpE5bn8A36uxq1h+TWnaQKPugtRkxKrYZA78O9c= github.com/coder/tailscale v1.1.1-0.20221117204504-2d6503f027c3/go.mod h1:lkCb74eSJwxeNq8YwyILoHD5vtHktiZnTOxBxo3tbNc= -github.com/coder/terraform-provider-coder v0.6.6 h1:ZAYvERlgjQPHyDdemXEuVcwdCFGfk9v5zQARegWL6nQ= -github.com/coder/terraform-provider-coder v0.6.6/go.mod h1:UIfU3bYNeSzJJvHyJ30tEKjD6Z9utloI+HUM/7n94CY= +github.com/coder/terraform-provider-coder v0.6.8 h1:j1M3IjzI/OUQBfmKtVxPIj37lzjHtxqjduGB3JrlO7Q= +github.com/coder/terraform-provider-coder v0.6.8/go.mod h1:UIfU3bYNeSzJJvHyJ30tEKjD6Z9utloI+HUM/7n94CY= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= @@ -982,6 +983,7 @@ github.com/hashicorp/errwrap v0.0.0-20141028054710-7554cd9344ce/go.mod h1:YH+1FK github.com/hashicorp/errwrap v1.0.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= github.com/hashicorp/errwrap v1.1.0 h1:OxrOeh75EUXMY8TBjag2fzXGZ40LB6IKw45YeGUDY2I= github.com/hashicorp/errwrap v1.1.0/go.mod h1:YH+1FKiLXxHSkmPseP+kNlulaMuP3n2brvKWEqk/Jc4= +github.com/hashicorp/go-checkpoint v0.5.0 h1:MFYpPZCnQqQTE18jFwSII6eUQrD/oxMFp3mlgcqk5mU= github.com/hashicorp/go-checkpoint v0.5.0/go.mod h1:7nfLNL10NsxqO4iWuW6tWW0HjZuDrwkBuEQsVcpCOgg= github.com/hashicorp/go-cleanhttp v0.5.0/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= github.com/hashicorp/go-cleanhttp v0.5.1/go.mod h1:JpRdi6/HCYpAwUzNwuwqhbovhLtngrth3wmdIIUrZ80= @@ -999,6 +1001,7 @@ github.com/hashicorp/go-multierror v1.0.0/go.mod h1:dHtQlpGsu+cZNNAkkCN/P3hoUDHh github.com/hashicorp/go-multierror v1.1.0/go.mod h1:spPvp8C1qA32ftKqdAHm4hHTbPw+vmowP0z+KUhOZdA= github.com/hashicorp/go-multierror v1.1.1 h1:H5DkEtf6CXdFp0N0Em5UCwQpXMWke8IA0+lD48awMYo= github.com/hashicorp/go-multierror v1.1.1/go.mod h1:iw975J/qwKPdAO1clOe2L8331t/9/fmwbPZ6JB6eMoM= +github.com/hashicorp/go-plugin v1.4.4 h1:NVdrSdFRt3SkZtNckJ6tog7gbpRrcbOjQi/rgF7JYWQ= github.com/hashicorp/go-reap v0.0.0-20170704170343-bf58d8a43e7b h1:3GrpnZQBxcMj1gCXQLelfjCT1D5MPGTuGMKHVzSIH6A= github.com/hashicorp/go-reap v0.0.0-20170704170343-bf58d8a43e7b/go.mod h1:qIFzeFcJU3OIFk/7JreWXcUjFmcCaeHTH9KoNyHYVCs= github.com/hashicorp/go-rootcerts v1.0.0/go.mod h1:K6zTfqpRlCUIjkwsN4Z+hiSfzSTQa6eBIzfwKfwNnHU= @@ -1033,6 +1036,7 @@ github.com/hashicorp/memberlist v0.1.3/go.mod h1:ajVTdAv/9Im8oMAAj5G31PhhMCZJV2p github.com/hashicorp/memberlist v0.2.2/go.mod h1:MS2lj3INKhZjWNqd3N0m3J+Jxf3DAOnAH9VT3Sh9MUE= github.com/hashicorp/serf v0.8.2/go.mod h1:6hOLApaqBFA1NXqRQAsxw9QxuDEvNxSQRwA/JwenrHc= github.com/hashicorp/serf v0.9.5/go.mod h1:UWDWwZeL5cuWDJdl0C6wrvrUwEqtQ4ZKBKKENpqIUyk= +github.com/hashicorp/terraform-exec v0.17.2 h1:EU7i3Fh7vDUI9nNRdMATCEfnm9axzTnad8zszYZ73Go= github.com/hashicorp/terraform-json v0.14.0 h1:sh9iZ1Y8IFJLx+xQiKHGud6/TSUCM0N8e17dKDpqV7s= github.com/hashicorp/terraform-json v0.14.0/go.mod h1:5A9HIWPkk4e5aeeXIBbkcOvaZbIYnAIkEyqP2pNSckM= github.com/hashicorp/terraform-plugin-go v0.12.0 h1:6wW9mT1dSs0Xq4LR6HXj1heQ5ovr5GxXNJwkErZzpJw= @@ -1041,6 +1045,8 @@ github.com/hashicorp/terraform-plugin-log v0.7.0 h1:SDxJUyT8TwN4l5b5/VkiTIaQgY6R github.com/hashicorp/terraform-plugin-log v0.7.0/go.mod h1:p4R1jWBXRTvL4odmEkFfDdhUjHf9zcs/BCoNHAc7IK4= github.com/hashicorp/terraform-plugin-sdk/v2 v2.20.0 h1:+KxZULPsbjpAVoP0WNj/8aVW6EqpcX5JcUcQ5wl7Da4= github.com/hashicorp/terraform-plugin-sdk/v2 v2.20.0/go.mod h1:DwGJG3KNxIPluVk6hexvDfYR/MS/eKGpiztJoT3Bbbw= +github.com/hashicorp/terraform-registry-address v0.0.0-20220623143253-7d51757b572c h1:D8aRO6+mTqHfLsK/BC3j5OAoogv1WLRWzY1AaTo3rBg= +github.com/hashicorp/terraform-svchost v0.0.0-20200729002733-f050f53b9734 h1:HKLsbzeOsfXmKNpr3GiT18XAblV0BjCbzL8KQAMZGa0= github.com/hashicorp/yamux v0.0.0-20220718163420-dd80a7ee44ce h1:7FO+LmZwiG/eDsBWo50ZeqV5PoH0gwiM1mxFajXAkas= github.com/hashicorp/yamux v0.0.0-20220718163420-dd80a7ee44ce/go.mod h1:CtWFDAQgb7dxtzFs4tWbplKIe2jSi3+5vKbgIO0SLnQ= github.com/hdevalence/ed25519consensus v0.0.0-20220222234857-c00d1f31bab3 h1:aSVUgRRRtOrZOC1fYmY9gV0e9z/Iu+xNVSASWjsuyGU= @@ -1443,10 +1449,12 @@ github.com/niklasfasching/go-org v1.6.5/go.mod h1:ybv0eGDnxylFUfFE+ySaQc734j/L3+ github.com/nishanths/exhaustive v0.2.3/go.mod h1:bhIX678Nx8inLM9PbpvK1yv6oGtoP8BfaIeMzgBNKvc= github.com/nishanths/predeclared v0.0.0-20190419143655-18a43bb90ffc/go.mod h1:62PewwiQTlm/7Rj+cxVYqZvDIUc+JjZq6GHAC1fsObQ= github.com/nishanths/predeclared v0.2.1/go.mod h1:HvkGJcA3naj4lOwnFXFDkFxVtSqQMB9sbB1usJ+xjQE= +github.com/nsf/jsondiff v0.0.0-20200515183724-f29ed568f4ce h1:RPclfga2SEJmgMmz2k+Mg7cowZ8yv4Trqw9UsJby758= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d h1:VhgPp6v9qf9Agr/56bj7Y/xa04UccTW04VP0Qed4vnQ= github.com/nu7hatch/gouuid v0.0.0-20131221200532-179d4d0c4d8d/go.mod h1:YUTz3bUH2ZwIWBy3CJBeOBEugqcmXREj14T+iG/4k4U= github.com/nxadm/tail v1.4.4/go.mod h1:kenIhsEOeOJmVchQTgglprH7qJGnHDVpk1VPCcaMI8A= github.com/nxadm/tail v1.4.8/go.mod h1:+ncqLTQzXmGhMZNUePPaPqPvBxHAIsmXswZKocGu+AU= +github.com/oklog/run v1.0.0 h1:Ru7dDtJNOyC66gQ5dQmaCa0qIsAUFY3sFpK1Xk8igrw= github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U= github.com/olekukonko/tablewriter v0.0.0-20170122224234-a0225b3f23b5/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo= From 1e5b776c058120c9660b38dd74ca3c1647ee04fe Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Mon, 23 Jan 2023 20:02:23 +0100 Subject: [PATCH 30/34] go mod --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 41388c09aa777..48a2c7bcfd568 100644 --- a/go.mod +++ b/go.mod @@ -67,7 +67,7 @@ require ( github.com/charmbracelet/lipgloss v0.6.0 github.com/cli/safeexec v1.0.0 github.com/coder/retry v1.3.0 - github.com/coder/terraform-provider-coder v0.6.8 + github.com/coder/terraform-provider-coder v0.6.9 github.com/coreos/go-oidc/v3 v3.4.0 github.com/coreos/go-systemd v0.0.0-20191104093116-d3cd4ed1dbcf github.com/creack/pty v1.1.18 diff --git a/go.sum b/go.sum index 5b85be824e5ec..6bd56622579a8 100644 --- a/go.sum +++ b/go.sum @@ -363,8 +363,8 @@ github.com/coder/ssh v0.0.0-20220811105153-fcea99919338 h1:tN5GKFT68YLVzJoA8AHui github.com/coder/ssh v0.0.0-20220811105153-fcea99919338/go.mod h1:ZSS+CUoKHDrqVakTfTWUlKSr9MtMFkC4UvtQKD7O914= github.com/coder/tailscale v1.1.1-0.20221117204504-2d6503f027c3 h1:lq8GmpE5bn8A36uxq1h+TWnaQKPugtRkxKrYZA78O9c= github.com/coder/tailscale v1.1.1-0.20221117204504-2d6503f027c3/go.mod h1:lkCb74eSJwxeNq8YwyILoHD5vtHktiZnTOxBxo3tbNc= -github.com/coder/terraform-provider-coder v0.6.8 h1:j1M3IjzI/OUQBfmKtVxPIj37lzjHtxqjduGB3JrlO7Q= -github.com/coder/terraform-provider-coder v0.6.8/go.mod h1:UIfU3bYNeSzJJvHyJ30tEKjD6Z9utloI+HUM/7n94CY= +github.com/coder/terraform-provider-coder v0.6.9 h1:8WKYCwc3kq6Be/cjzrCKydbGB464xfGpnHHCzJULVA0= +github.com/coder/terraform-provider-coder v0.6.9/go.mod h1:UIfU3bYNeSzJJvHyJ30tEKjD6Z9utloI+HUM/7n94CY= github.com/containerd/aufs v0.0.0-20200908144142-dab0cbea06f4/go.mod h1:nukgQABAEopAHvB6j7cnP5zJ+/3aVcE7hCYqvIwAHyE= github.com/containerd/aufs v0.0.0-20201003224125-76a6863f2989/go.mod h1:AkGGQs9NM2vtYHaUen+NljV0/baGCAPELGm2q9ZXpWU= github.com/containerd/aufs v0.0.0-20210316121734-20793ff83c97/go.mod h1:kL5kd6KM5TzQjR79jljyi4olc1Vrx6XBlcyj3gNv2PU= From fb0ee7396796a9b7504fe626683e8624875a05f3 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Tue, 24 Jan 2023 11:57:23 +0100 Subject: [PATCH 31/34] CLI --- cli/cliui/parameter.go | 8 +++++--- cli/cliui/select.go | 39 +++++++++++++++++++++++++++++++++++ cli/cliui/select_test.go | 44 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 3 deletions(-) diff --git a/cli/cliui/parameter.go b/cli/cliui/parameter.go index 2377b775d6173..4c8de8fd87a0b 100644 --- a/cli/cliui/parameter.go +++ b/cli/cliui/parameter.go @@ -72,14 +72,16 @@ func RichParameter(cmd *cobra.Command, templateVersionParameter codersdk.Templat 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), + var richParameterOption *codersdk.TemplateVersionParameterOption + richParameterOption, err = RichSelect(cmd, RichSelectOptions{ + Options: templateVersionParameter.Options, Default: templateVersionParameter.DefaultValue, HideSearch: true, }) if err == nil { _, _ = fmt.Fprintln(cmd.OutOrStdout()) - _, _ = fmt.Fprintln(cmd.OutOrStdout(), " "+Styles.Prompt.String()+Styles.Field.Render(value)) + _, _ = fmt.Fprintln(cmd.OutOrStdout(), " "+Styles.Prompt.String()+Styles.Field.Render(richParameterOption.Name)) + value = richParameterOption.Value } } else { text := "Enter a value" diff --git a/cli/cliui/select.go b/cli/cliui/select.go index 63fda4f87720d..17c056ae4ac8a 100644 --- a/cli/cliui/select.go +++ b/cli/cliui/select.go @@ -9,6 +9,9 @@ import ( "github.com/AlecAivazis/survey/v2" "github.com/AlecAivazis/survey/v2/terminal" "github.com/spf13/cobra" + "golang.org/x/xerrors" + + "github.com/coder/coder/codersdk" ) func init() { @@ -42,6 +45,42 @@ type SelectOptions struct { HideSearch bool } +type RichSelectOptions struct { + Options []codersdk.TemplateVersionParameterOption + Default string + Size int + HideSearch bool +} + +// RichSelect displays a list of user options including name and description. +func RichSelect(cmd *cobra.Command, richOptions RichSelectOptions) (*codersdk.TemplateVersionParameterOption, error) { + opts := make([]string, len(richOptions.Options)) + for i, option := range richOptions.Options { + line := option.Name + if len(option.Description) > 0 { + line += ": " + option.Description + } + opts[i] = line + } + + selected, err := Select(cmd, SelectOptions{ + Options: opts, + Default: richOptions.Default, + Size: richOptions.Size, + HideSearch: richOptions.HideSearch, + }) + if err != nil { + return nil, err + } + + for i, option := range opts { + if option == selected { + return &richOptions.Options[i], nil + } + } + return nil, xerrors.Errorf("unknown option selected: %s", selected) +} + // Select displays a list of user options. func Select(cmd *cobra.Command, opts SelectOptions) (string, error) { // The survey library used *always* fails when testing on Windows, diff --git a/cli/cliui/select_test.go b/cli/cliui/select_test.go index 7696f4a7080a9..4a7cede5cf92a 100644 --- a/cli/cliui/select_test.go +++ b/cli/cliui/select_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/cli/cliui" + "github.com/coder/coder/codersdk" "github.com/coder/coder/pty/ptytest" ) @@ -42,3 +43,46 @@ func newSelect(ptty *ptytest.PTY, opts cliui.SelectOptions) (string, error) { cmd.SetIn(ptty.Input()) return value, cmd.ExecuteContext(context.Background()) } + +func TestRichSelect(t *testing.T) { + t.Parallel() + t.Run("RichSelect", func(t *testing.T) { + t.Parallel() + ptty := ptytest.New(t) + msgChan := make(chan string) + go func() { + resp, err := newRichSelect(ptty, cliui.RichSelectOptions{ + Options: []codersdk.TemplateVersionParameterOption{ + { + Name: "A-Name", + Value: "A-Value", + Description: "A-Description", + }, { + Name: "B-Name", + Value: "B-Value", + Description: "B-Description", + }, + }, + }) + assert.NoError(t, err) + msgChan <- resp + }() + require.Equal(t, "A-Value", <-msgChan) + }) +} + +func newRichSelect(ptty *ptytest.PTY, opts cliui.RichSelectOptions) (string, error) { + value := "" + cmd := &cobra.Command{ + RunE: func(cmd *cobra.Command, args []string) error { + richOption, err := cliui.RichSelect(cmd, opts) + if err == nil { + value = richOption.Value + } + return err + }, + } + cmd.SetOutput(ptty.Output()) + cmd.SetIn(ptty.Input()) + return value, cmd.ExecuteContext(context.Background()) +} From 0b426b86a6d3fa30f0123c2782b51a55d402ed1d Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Tue, 24 Jan 2023 12:08:52 +0100 Subject: [PATCH 32/34] Fix --- cli/cliui/parameter.go | 8 -------- 1 file changed, 8 deletions(-) diff --git a/cli/cliui/parameter.go b/cli/cliui/parameter.go index 4c8de8fd87a0b..1469fbe0642d8 100644 --- a/cli/cliui/parameter.go +++ b/cli/cliui/parameter.go @@ -110,14 +110,6 @@ func RichParameter(cmd *cobra.Command, templateVersionParameter codersdk.Templat return value, nil } -func templateVersionParameterOptionValues(param codersdk.TemplateVersionParameter) []string { - var options []string - for _, opt := range param.Options { - options = append(options, opt.Value) - } - return options -} - func validateRichPrompt(value string, p codersdk.TemplateVersionParameter) error { return codersdk.ValidateWorkspaceBuildParameter(p, codersdk.WorkspaceBuildParameter{ Name: p.Name, From d347b6889c9dadf91a686e22bd783d81002acf29 Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Tue, 24 Jan 2023 12:42:23 +0100 Subject: [PATCH 33/34] TestCreateValidateRichParameters --- cli/create_test.go | 162 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 162 insertions(+) diff --git a/cli/create_test.go b/cli/create_test.go index 03552dbd9bd43..ac607617f1bf1 100644 --- a/cli/create_test.go +++ b/cli/create_test.go @@ -439,6 +439,168 @@ func TestCreateWithRichParameters(t *testing.T) { }) } +func TestCreateValidateRichParameters(t *testing.T) { + t.Parallel() + + const ( + stringParameterName = "string_parameter" + stringParameterValue = "abc" + + numberParameterName = "number_parameter" + numberParameterValue = "7" + + boolParameterName = "bool_parameter" + boolParameterValue = "true" + ) + + numberRichParameters := []*proto.RichParameter{ + {Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: 3, ValidationMax: 10}, + } + + stringRichParameters := []*proto.RichParameter{ + {Name: stringParameterName, Type: "string", Mutable: true, ValidationRegex: "^[a-z]+$", ValidationError: "this is error"}, + } + + boolRichParameters := []*proto.RichParameter{ + {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() + + client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + user := coderdtest.CreateFirstUser(t, client) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, prepareEchoResponses(stringRichParameters)) + 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{ + stringParameterName, "$$", + "does not match", "", + "Enter a value", "abc", + "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("ValidateNumber", 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, prepareEchoResponses(numberRichParameters)) + 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{ + numberParameterName, "12", + "is more than the maximum", "", + "Enter a value", "8", + "Confirm create?", "yes", + } + for i := 0; i < len(matches); i += 2 { + match := matches[i] + value := matches[i+1] + pty.ExpectMatch(match) + + if value != "" { + pty.WriteLine(value) + } + } + <-doneChan + }) + + t.Run("ValidateBool", 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, prepareEchoResponses(boolRichParameters)) + 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{ + boolParameterName, "cat", + "boolean value can be either", "", + "Enter a value", "true", + "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{ From 228d80665d395e67847f0c165942cd3784ac243e Mon Sep 17 00:00:00 2001 From: Marcin Tojek Date: Tue, 24 Jan 2023 13:06:20 +0100 Subject: [PATCH 34/34] CLI tests --- cli/update_test.go | 191 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) diff --git a/cli/update_test.go b/cli/update_test.go index 250e768d48580..60f644744eeac 100644 --- a/cli/update_test.go +++ b/cli/update_test.go @@ -232,3 +232,194 @@ func TestUpdateWithRichParameters(t *testing.T) { <-doneChan }) } + +func TestUpdateValidateRichParameters(t *testing.T) { + t.Parallel() + + const ( + stringParameterName = "string_parameter" + stringParameterValue = "abc" + + numberParameterName = "number_parameter" + numberParameterValue = "7" + + boolParameterName = "bool_parameter" + boolParameterValue = "true" + ) + + numberRichParameters := []*proto.RichParameter{ + {Name: numberParameterName, Type: "number", Mutable: true, ValidationMin: 3, ValidationMax: 10}, + } + + stringRichParameters := []*proto.RichParameter{ + {Name: stringParameterName, Type: "string", Mutable: true, ValidationRegex: "^[a-z]+$", ValidationError: "this is error"}, + } + + boolRichParameters := []*proto.RichParameter{ + {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() + + client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true}) + user := coderdtest.CreateFirstUser(t, client) + version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, prepareEchoResponses(stringRichParameters)) + 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( + stringParameterName + ": " + stringParameterValue) + + 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() + require.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{ + stringParameterName, "$$", + "does not match", "", + "Enter a value", "abc", + } + for i := 0; i < len(matches); i += 2 { + match := matches[i] + value := matches[i+1] + pty.ExpectMatch(match) + pty.WriteLine(value) + } + <-doneChan + }) + + t.Run("ValidateNumber", 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, prepareEchoResponses(numberRichParameters)) + 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( + numberParameterName + ": " + numberParameterValue) + + 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() + require.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{ + numberParameterName, "12", + "is more than the maximum", "", + "Enter a value", "8", + } + for i := 0; i < len(matches); i += 2 { + match := matches[i] + value := matches[i+1] + pty.ExpectMatch(match) + + if value != "" { + pty.WriteLine(value) + } + } + <-doneChan + }) + + t.Run("ValidateBool", 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, prepareEchoResponses(boolRichParameters)) + 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( + boolParameterName + ": " + boolParameterValue) + + 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() + require.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{ + boolParameterName, "cat", + "boolean value can be either", "", + "Enter a value", "false", + } + for i := 0; i < len(matches); i += 2 { + match := matches[i] + value := matches[i+1] + pty.ExpectMatch(match) + pty.WriteLine(value) + } + <-doneChan + }) +}