feat: Expose managed variables via API (#6134)

* WIP

* hcl

* useManagedVariables

* fix

* Fix

* Fix

* fix

* go:build

* Fix

* fix: bool flag

* Insert template variables

* API

* fix

* Expose via API

* More wiring

* CLI for testing purposes

* WIP

* Delete FIXME

* planVars

* WIP

* WIP

* UserVariableValues

* no dry run

* Dry run

* Done FIXME

* Fix

* Fix: CLI

* Fix: migration

* API tests

* Test info

* Tests

* More tests

* fix: lint

* Fix: authz

* Address PR comments

* Fix

* fix

* fix
This commit is contained in:
Marcin Tojek
2023-02-15 18:24:15 +01:00
committed by GitHub
parent f0f39b4892
commit 3b7b96ac28
41 changed files with 2423 additions and 667 deletions
+15 -6
View File
@@ -133,6 +133,7 @@ type createValidTemplateVersionArgs struct {
Provisioner database.ProvisionerType
FileID uuid.UUID
ParameterFile string
ValuesFile string
// Template is only required if updating a template's active version.
Template *codersdk.Template
// ReuseParameters will attempt to reuse params from the Template field
@@ -145,13 +146,21 @@ type createValidTemplateVersionArgs struct {
func createValidTemplateVersion(cmd *cobra.Command, args createValidTemplateVersionArgs, parameters ...codersdk.CreateParameterRequest) (*codersdk.TemplateVersion, []codersdk.CreateParameterRequest, error) {
client := args.Client
// FIXME(mtojek): I will iterate on CLI experience in the follow-up.
// see: https://github.com/coder/coder/issues/5980
variableValues, err := loadVariableValues(args.ValuesFile)
if err != nil {
return nil, nil, err
}
req := codersdk.CreateTemplateVersionRequest{
Name: args.Name,
StorageMethod: codersdk.ProvisionerStorageMethodFile,
FileID: args.FileID,
Provisioner: codersdk.ProvisionerType(args.Provisioner),
ParameterValues: parameters,
ProvisionerTags: args.ProvisionerTags,
Name: args.Name,
StorageMethod: codersdk.ProvisionerStorageMethodFile,
FileID: args.FileID,
Provisioner: codersdk.ProvisionerType(args.Provisioner),
ParameterValues: parameters,
ProvisionerTags: args.ProvisionerTags,
UserVariableValues: variableValues,
}
if args.Template != nil {
req.TemplateID = args.Template.ID
+3
View File
@@ -93,6 +93,7 @@ func templatePush() *cobra.Command {
versionName string
provisioner string
parameterFile string
valuesFile string
alwaysPrompt bool
provisionerTags []string
uploadFlags templateUploadFlags
@@ -139,6 +140,7 @@ func templatePush() *cobra.Command {
Provisioner: database.ProvisionerType(provisioner),
FileID: resp.ID,
ParameterFile: parameterFile,
ValuesFile: valuesFile,
Template: &template,
ReuseParameters: !alwaysPrompt,
ProvisionerTags: tags,
@@ -165,6 +167,7 @@ func templatePush() *cobra.Command {
cmd.Flags().StringVarP(&provisioner, "test.provisioner", "", "terraform", "Customize the provisioner backend")
cmd.Flags().StringVarP(&parameterFile, "parameter-file", "", "", "Specify a file path with parameter values.")
cmd.Flags().StringVarP(&valuesFile, "values-file", "", "", "Specify a file path with values for managed variables.")
cmd.Flags().StringVarP(&versionName, "name", "", "", "Specify a name for the new template version. It will be automatically generated if not provided.")
cmd.Flags().StringArrayVarP(&provisionerTags, "provisioner-tag", "", []string{}, "Specify a set of tags to target provisioner daemons.")
cmd.Flags().BoolVar(&alwaysPrompt, "always-prompt", false, "Always prompt all parameters. Does not pull parameter values from active template version")
+50
View File
@@ -0,0 +1,50 @@
package cli
import (
"os"
"golang.org/x/xerrors"
"gopkg.in/yaml.v3"
"github.com/coder/coder/codersdk"
)
func loadVariableValues(variablesFile string) ([]codersdk.VariableValue, error) {
var values []codersdk.VariableValue
if variablesFile == "" {
return values, nil
}
variablesMap, err := createVariablesMapFromFile(variablesFile)
if err != nil {
return nil, err
}
for name, value := range variablesMap {
values = append(values, codersdk.VariableValue{
Name: name,
Value: value,
})
}
return values, nil
}
// Reads a YAML file and populates a string -> string map.
// Throws an error if the file name is empty.
func createVariablesMapFromFile(variablesFile string) (map[string]string, error) {
if variablesFile == "" {
return nil, xerrors.Errorf("variable file name is not specified")
}
variablesMap := make(map[string]string)
variablesFileContents, err := os.ReadFile(variablesFile)
if err != nil {
return nil, err
}
err = yaml.Unmarshal(variablesFileContents, &variablesMap)
if err != nil {
return nil, err
}
return variablesMap, nil
}
+1
View File
@@ -13,6 +13,7 @@ Flags:
automatically generated if not provided.
--parameter-file string Specify a file path with parameter values.
--provisioner-tag stringArray Specify a set of tags to target provisioner daemons.
--values-file string Specify a file path with values for managed variables.
-y, --yes Bypass prompts
Global Flags:
+86
View File
@@ -2693,6 +2693,44 @@ const docTemplate = `{
}
}
},
"/templateversions/{templateversion}/variables": {
"get": {
"security": [
{
"CoderSessionToken": []
}
],
"produces": [
"application/json"
],
"tags": [
"Templates"
],
"summary": "Get template variables by template version",
"operationId": "get-template-variables-by-template-version",
"parameters": [
{
"type": "string",
"format": "uuid",
"description": "Template version ID",
"name": "templateversion",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/codersdk.TemplateVersionVariable"
}
}
}
}
}
},
"/updatecheck": {
"get": {
"produces": [
@@ -5753,6 +5791,12 @@ const docTemplate = `{
"$ref": "#/definitions/codersdk.WorkspaceBuildParameter"
}
},
"user_variable_values": {
"type": "array",
"items": {
"$ref": "#/definitions/codersdk.VariableValue"
}
},
"workspace_name": {
"type": "string"
}
@@ -7681,6 +7725,37 @@ const docTemplate = `{
}
}
},
"codersdk.TemplateVersionVariable": {
"type": "object",
"properties": {
"default_value": {
"type": "string"
},
"description": {
"type": "string"
},
"name": {
"type": "string"
},
"required": {
"type": "boolean"
},
"sensitive": {
"type": "boolean"
},
"type": {
"type": "string",
"enum": [
"string",
"number",
"bool"
]
},
"value": {
"type": "string"
}
}
},
"codersdk.TraceConfig": {
"type": "object",
"properties": {
@@ -7918,6 +7993,17 @@ const docTemplate = `{
"MonotonicOrderDecreasing"
]
},
"codersdk.VariableValue": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"value": {
"type": "string"
}
}
},
"codersdk.Workspace": {
"type": "object",
"properties": {
+78
View File
@@ -2371,6 +2371,40 @@
}
}
},
"/templateversions/{templateversion}/variables": {
"get": {
"security": [
{
"CoderSessionToken": []
}
],
"produces": ["application/json"],
"tags": ["Templates"],
"summary": "Get template variables by template version",
"operationId": "get-template-variables-by-template-version",
"parameters": [
{
"type": "string",
"format": "uuid",
"description": "Template version ID",
"name": "templateversion",
"in": "path",
"required": true
}
],
"responses": {
"200": {
"description": "OK",
"schema": {
"type": "array",
"items": {
"$ref": "#/definitions/codersdk.TemplateVersionVariable"
}
}
}
}
}
},
"/updatecheck": {
"get": {
"produces": ["application/json"],
@@ -5105,6 +5139,12 @@
"$ref": "#/definitions/codersdk.WorkspaceBuildParameter"
}
},
"user_variable_values": {
"type": "array",
"items": {
"$ref": "#/definitions/codersdk.VariableValue"
}
},
"workspace_name": {
"type": "string"
}
@@ -6907,6 +6947,33 @@
}
}
},
"codersdk.TemplateVersionVariable": {
"type": "object",
"properties": {
"default_value": {
"type": "string"
},
"description": {
"type": "string"
},
"name": {
"type": "string"
},
"required": {
"type": "boolean"
},
"sensitive": {
"type": "boolean"
},
"type": {
"type": "string",
"enum": ["string", "number", "bool"]
},
"value": {
"type": "string"
}
}
},
"codersdk.TraceConfig": {
"type": "object",
"properties": {
@@ -7118,6 +7185,17 @@
"MonotonicOrderDecreasing"
]
},
"codersdk.VariableValue": {
"type": "object",
"properties": {
"name": {
"type": "string"
},
"value": {
"type": "string"
}
}
},
"codersdk.Workspace": {
"type": "object",
"properties": {
@@ -13,6 +13,7 @@ import (
"github.com/coder/coder/coderd/autobuild/schedule"
"github.com/coder/coder/coderd/database"
"github.com/coder/coder/coderd/database/dbauthz"
"github.com/coder/coder/coderd/provisionerdserver"
)
// Executor automatically starts or stops workspaces.
@@ -249,10 +250,8 @@ func build(ctx context.Context, store database.Store, workspace database.Workspa
// This must happen in a transaction to ensure history can be inserted, and
// the prior history can update it's "after" column to point at the new.
workspaceBuildID := uuid.New()
input, err := json.Marshal(struct {
WorkspaceBuildID string `json:"workspace_build_id"`
}{
WorkspaceBuildID: workspaceBuildID.String(),
input, err := json.Marshal(provisionerdserver.WorkspaceProvisionJob{
WorkspaceBuildID: workspaceBuildID,
})
if err != nil {
return xerrors.Errorf("marshal provision job: %w", err)
+1
View File
@@ -479,6 +479,7 @@ func New(options *Options) *API {
r.Get("/schema", api.templateVersionSchema)
r.Get("/parameters", api.templateVersionParameters)
r.Get("/rich-parameters", api.templateVersionRichParameters)
r.Get("/variables", api.templateVersionVariables)
r.Get("/resources", api.templateVersionResources)
r.Get("/logs", api.templateVersionLogs)
r.Route("/dry-run", func(r chi.Router) {
+9 -3
View File
@@ -522,17 +522,23 @@ func createAnotherUserRetry(t *testing.T, client *codersdk.Client, organizationI
// CreateTemplateVersion creates a template import provisioner job
// with the responses provided. It uses the "echo" provisioner for compatibility
// with testing.
func CreateTemplateVersion(t *testing.T, client *codersdk.Client, organizationID uuid.UUID, res *echo.Responses) codersdk.TemplateVersion {
func CreateTemplateVersion(t *testing.T, client *codersdk.Client, organizationID uuid.UUID, res *echo.Responses, mutators ...func(*codersdk.CreateTemplateVersionRequest)) codersdk.TemplateVersion {
t.Helper()
data, err := echo.Tar(res)
require.NoError(t, err)
file, err := client.Upload(context.Background(), codersdk.ContentTypeTar, bytes.NewReader(data))
require.NoError(t, err)
templateVersion, err := client.CreateTemplateVersion(context.Background(), organizationID, codersdk.CreateTemplateVersionRequest{
req := codersdk.CreateTemplateVersionRequest{
FileID: file.ID,
StorageMethod: codersdk.ProvisionerStorageMethodFile,
Provisioner: codersdk.ProvisionerTypeEcho,
})
}
for _, mut := range mutators {
mut(&req)
}
templateVersion, err := client.CreateTemplateVersion(context.Background(), organizationID, req)
require.NoError(t, err)
return templateVersion
}
+23
View File
@@ -698,6 +698,29 @@ func (q *querier) GetTemplateVersionParameters(ctx context.Context, templateVers
return q.db.GetTemplateVersionParameters(ctx, templateVersionID)
}
func (q *querier) GetTemplateVersionVariables(ctx context.Context, templateVersionID uuid.UUID) ([]database.TemplateVersionVariable, error) {
tv, err := q.db.GetTemplateVersionByID(ctx, templateVersionID)
if err != nil {
return nil, err
}
var object rbac.Objecter
template, err := q.db.GetTemplateByID(ctx, tv.TemplateID.UUID)
if err != nil {
if !errors.Is(err, sql.ErrNoRows) {
return nil, err
}
object = rbac.ResourceTemplate.InOrg(tv.OrganizationID)
} else {
object = tv.RBACObject(template)
}
if err := q.authorizeContext(ctx, rbac.ActionCreate, object); err != nil {
return nil, err
}
return q.db.GetTemplateVersionVariables(ctx, templateVersionID)
}
func (q *querier) GetTemplateVersionsByIDs(ctx context.Context, ids []uuid.UUID) ([]database.TemplateVersion, error) {
// TODO: This is so inefficient
versions, err := q.db.GetTemplateVersionsByIDs(ctx, ids)
+4
View File
@@ -200,6 +200,10 @@ func (q *querier) InsertTemplateVersionParameter(ctx context.Context, arg databa
return q.db.InsertTemplateVersionParameter(ctx, arg)
}
func (q *querier) InsertTemplateVersionVariable(ctx context.Context, arg database.InsertTemplateVersionVariableParams) (database.TemplateVersionVariable, error) {
return q.db.InsertTemplateVersionVariable(ctx, arg)
}
func (q *querier) InsertWorkspaceResource(ctx context.Context, arg database.InsertWorkspaceResourceParams) (database.WorkspaceResource, error) {
return q.db.InsertWorkspaceResource(ctx, arg)
}
+38
View File
@@ -114,6 +114,7 @@ type data struct {
replicas []database.Replica
templateVersions []database.TemplateVersion
templateVersionParameters []database.TemplateVersionParameter
templateVersionVariables []database.TemplateVersionVariable
templates []database.Template
workspaceAgents []database.WorkspaceAgent
workspaceApps []database.WorkspaceApp
@@ -1841,6 +1842,20 @@ func (q *fakeQuerier) GetTemplateVersionParameters(_ context.Context, templateVe
return parameters, nil
}
func (q *fakeQuerier) GetTemplateVersionVariables(_ context.Context, templateVersionID uuid.UUID) ([]database.TemplateVersionVariable, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()
variables := make([]database.TemplateVersionVariable, 0)
for _, variable := range q.templateVersionVariables {
if variable.TemplateVersionID != templateVersionID {
continue
}
variables = append(variables, variable)
}
return variables, nil
}
func (q *fakeQuerier) GetTemplateVersionByID(ctx context.Context, templateVersionID uuid.UUID) (database.TemplateVersion, error) {
q.mutex.RLock()
defer q.mutex.RUnlock()
@@ -2643,6 +2658,29 @@ func (q *fakeQuerier) InsertTemplateVersionParameter(_ context.Context, arg data
return param, nil
}
func (q *fakeQuerier) InsertTemplateVersionVariable(_ context.Context, arg database.InsertTemplateVersionVariableParams) (database.TemplateVersionVariable, error) {
if err := validateDatabaseType(arg); err != nil {
return database.TemplateVersionVariable{}, err
}
q.mutex.Lock()
defer q.mutex.Unlock()
//nolint:gosimple
variable := database.TemplateVersionVariable{
TemplateVersionID: arg.TemplateVersionID,
Name: arg.Name,
Description: arg.Description,
Type: arg.Type,
Value: arg.Value,
DefaultValue: arg.DefaultValue,
Required: arg.Required,
Sensitive: arg.Sensitive,
}
q.templateVersionVariables = append(q.templateVersionVariables, variable)
return variable, nil
}
func (q *fakeQuerier) InsertProvisionerJobLogs(_ context.Context, arg database.InsertProvisionerJobLogsParams) ([]database.ProvisionerJobLog, error) {
if err := validateDatabaseType(arg); err != nil {
return nil, err
+15
View File
@@ -383,6 +383,21 @@ func TemplateVersion(t testing.TB, db database.Store, orig database.TemplateVers
return version
}
func TemplateVersionVariable(t testing.TB, db database.Store, orig database.TemplateVersionVariable) database.TemplateVersionVariable {
version, err := db.InsertTemplateVersionVariable(context.Background(), database.InsertTemplateVersionVariableParams{
TemplateVersionID: takeFirst(orig.TemplateVersionID, uuid.New()),
Name: takeFirst(orig.Name, namesgenerator.GetRandomName(1)),
Description: takeFirst(orig.Description, namesgenerator.GetRandomName(1)),
Type: takeFirst(orig.Type, "string"),
Value: takeFirst(orig.Value, ""),
DefaultValue: takeFirst(orig.DefaultValue, namesgenerator.GetRandomName(1)),
Required: takeFirst(orig.Required, false),
Sensitive: takeFirst(orig.Sensitive, false),
})
require.NoError(t, err, "insert template version variable")
return version
}
func ParameterSchema(t testing.TB, db database.Store, seed database.ParameterSchema) database.ParameterSchema {
scheme, err := db.InsertParameterSchema(context.Background(), database.InsertParameterSchemaParams{
ID: takeFirst(seed.ID, uuid.New()),
+31
View File
@@ -383,6 +383,31 @@ COMMENT ON COLUMN template_version_parameters.validation_error IS 'Validation: e
COMMENT ON COLUMN template_version_parameters.validation_monotonic IS 'Validation: consecutive values preserve the monotonic order';
CREATE TABLE template_version_variables (
template_version_id uuid NOT NULL,
name text NOT NULL,
description text NOT NULL,
type text NOT NULL,
value text NOT NULL,
default_value text NOT NULL,
required boolean NOT NULL,
sensitive boolean NOT NULL
);
COMMENT ON COLUMN template_version_variables.name IS 'Variable name';
COMMENT ON COLUMN template_version_variables.description IS 'Variable description';
COMMENT ON COLUMN template_version_variables.type IS 'Variable type';
COMMENT ON COLUMN template_version_variables.value IS 'Variable value';
COMMENT ON COLUMN template_version_variables.default_value IS 'Variable default value';
COMMENT ON COLUMN template_version_variables.required IS 'Required variables needs a default value or a value provided by template admin';
COMMENT ON COLUMN template_version_variables.sensitive IS 'Sensitive variables have their values redacted in logs or site UI';
CREATE TABLE template_versions (
id uuid NOT NULL,
template_id uuid,
@@ -655,6 +680,9 @@ ALTER TABLE ONLY site_configs
ALTER TABLE ONLY template_version_parameters
ADD CONSTRAINT template_version_parameters_template_version_id_name_key UNIQUE (template_version_id, name);
ALTER TABLE ONLY template_version_variables
ADD CONSTRAINT template_version_variables_template_version_id_name_key UNIQUE (template_version_id, name);
ALTER TABLE ONLY template_versions
ADD CONSTRAINT template_versions_pkey PRIMARY KEY (id);
@@ -780,6 +808,9 @@ ALTER TABLE ONLY provisioner_jobs
ALTER TABLE ONLY template_version_parameters
ADD CONSTRAINT template_version_parameters_template_version_id_fkey FOREIGN KEY (template_version_id) REFERENCES template_versions(id) ON DELETE CASCADE;
ALTER TABLE ONLY template_version_variables
ADD CONSTRAINT template_version_variables_template_version_id_fkey FOREIGN KEY (template_version_id) REFERENCES template_versions(id) ON DELETE CASCADE;
ALTER TABLE ONLY template_versions
ADD CONSTRAINT template_versions_created_by_fkey FOREIGN KEY (created_by) REFERENCES users(id) ON DELETE RESTRICT;
@@ -0,0 +1 @@
DROP TABLE template_version_variables;
@@ -0,0 +1,19 @@
CREATE TABLE IF NOT EXISTS template_version_variables (
template_version_id uuid not null references template_versions (id) on delete cascade,
name text not null,
description text not null,
type text not null,
value text not null,
default_value text not null,
required boolean not null,
sensitive boolean not null,
unique (template_version_id, name)
);
COMMENT ON COLUMN template_version_variables.name IS 'Variable name';
COMMENT ON COLUMN template_version_variables.description IS 'Variable description';
COMMENT ON COLUMN template_version_variables.type IS 'Variable type';
COMMENT ON COLUMN template_version_variables.value IS 'Variable value';
COMMENT ON COLUMN template_version_variables.default_value IS 'Variable default value';
COMMENT ON COLUMN template_version_variables.required IS 'Required variables needs a default value or a value provided by template admin';
COMMENT ON COLUMN template_version_variables.sensitive IS 'Sensitive variables have their values redacted in logs or site UI';
@@ -241,6 +241,7 @@ func TestMigrateUpWithFixtures(t *testing.T) {
"replicas",
"template_version_parameters",
"workspace_build_parameters",
"template_version_variables",
}
s := &tableStats{s: make(map[string]int)}
+18
View File
@@ -1463,6 +1463,24 @@ type TemplateVersionParameter struct {
ValidationMonotonic string `db:"validation_monotonic" json:"validation_monotonic"`
}
type TemplateVersionVariable struct {
TemplateVersionID uuid.UUID `db:"template_version_id" json:"template_version_id"`
// Variable name
Name string `db:"name" json:"name"`
// Variable description
Description string `db:"description" json:"description"`
// Variable type
Type string `db:"type" json:"type"`
// Variable value
Value string `db:"value" json:"value"`
// Variable default value
DefaultValue string `db:"default_value" json:"default_value"`
// Required variables needs a default value or a value provided by template admin
Required bool `db:"required" json:"required"`
// Sensitive variables have their values redacted in logs or site UI
Sensitive bool `db:"sensitive" json:"sensitive"`
}
type User struct {
ID uuid.UUID `db:"id" json:"id"`
Email string `db:"email" json:"email"`
+2
View File
@@ -87,6 +87,7 @@ type sqlcQuerier interface {
GetTemplateVersionByJobID(ctx context.Context, jobID uuid.UUID) (TemplateVersion, error)
GetTemplateVersionByTemplateIDAndName(ctx context.Context, arg GetTemplateVersionByTemplateIDAndNameParams) (TemplateVersion, error)
GetTemplateVersionParameters(ctx context.Context, templateVersionID uuid.UUID) ([]TemplateVersionParameter, error)
GetTemplateVersionVariables(ctx context.Context, templateVersionID uuid.UUID) ([]TemplateVersionVariable, error)
GetTemplateVersionsByIDs(ctx context.Context, ids []uuid.UUID) ([]TemplateVersion, error)
GetTemplateVersionsByTemplateID(ctx context.Context, arg GetTemplateVersionsByTemplateIDParams) ([]TemplateVersion, error)
GetTemplateVersionsCreatedAfter(ctx context.Context, createdAt time.Time) ([]TemplateVersion, error)
@@ -159,6 +160,7 @@ type sqlcQuerier interface {
InsertTemplate(ctx context.Context, arg InsertTemplateParams) (Template, error)
InsertTemplateVersion(ctx context.Context, arg InsertTemplateVersionParams) (TemplateVersion, error)
InsertTemplateVersionParameter(ctx context.Context, arg InsertTemplateVersionParameterParams) (TemplateVersionParameter, error)
InsertTemplateVersionVariable(ctx context.Context, arg InsertTemplateVersionVariableParams) (TemplateVersionVariable, error)
InsertUser(ctx context.Context, arg InsertUserParams) (User, error)
// InsertUserGroupsByName adds a user to all provided groups, if they exist.
InsertUserGroupsByName(ctx context.Context, arg InsertUserGroupsByNameParams) error
+97
View File
@@ -4050,6 +4050,103 @@ func (q *sqlQuerier) UpdateTemplateVersionDescriptionByJobID(ctx context.Context
return err
}
const getTemplateVersionVariables = `-- name: GetTemplateVersionVariables :many
SELECT template_version_id, name, description, type, value, default_value, required, sensitive FROM template_version_variables WHERE template_version_id = $1
`
func (q *sqlQuerier) GetTemplateVersionVariables(ctx context.Context, templateVersionID uuid.UUID) ([]TemplateVersionVariable, error) {
rows, err := q.db.QueryContext(ctx, getTemplateVersionVariables, templateVersionID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []TemplateVersionVariable
for rows.Next() {
var i TemplateVersionVariable
if err := rows.Scan(
&i.TemplateVersionID,
&i.Name,
&i.Description,
&i.Type,
&i.Value,
&i.DefaultValue,
&i.Required,
&i.Sensitive,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Close(); err != nil {
return nil, err
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const insertTemplateVersionVariable = `-- name: InsertTemplateVersionVariable :one
INSERT INTO
template_version_variables (
template_version_id,
name,
description,
type,
value,
default_value,
required,
sensitive
)
VALUES
(
$1,
$2,
$3,
$4,
$5,
$6,
$7,
$8
) RETURNING template_version_id, name, description, type, value, default_value, required, sensitive
`
type InsertTemplateVersionVariableParams struct {
TemplateVersionID uuid.UUID `db:"template_version_id" json:"template_version_id"`
Name string `db:"name" json:"name"`
Description string `db:"description" json:"description"`
Type string `db:"type" json:"type"`
Value string `db:"value" json:"value"`
DefaultValue string `db:"default_value" json:"default_value"`
Required bool `db:"required" json:"required"`
Sensitive bool `db:"sensitive" json:"sensitive"`
}
func (q *sqlQuerier) InsertTemplateVersionVariable(ctx context.Context, arg InsertTemplateVersionVariableParams) (TemplateVersionVariable, error) {
row := q.db.QueryRowContext(ctx, insertTemplateVersionVariable,
arg.TemplateVersionID,
arg.Name,
arg.Description,
arg.Type,
arg.Value,
arg.DefaultValue,
arg.Required,
arg.Sensitive,
)
var i TemplateVersionVariable
err := row.Scan(
&i.TemplateVersionID,
&i.Name,
&i.Description,
&i.Type,
&i.Value,
&i.DefaultValue,
&i.Required,
&i.Sensitive,
)
return i, err
}
const getUserLinkByLinkedID = `-- name: GetUserLinkByLinkedID :one
SELECT
user_id, login_type, linked_id, oauth_access_token, oauth_refresh_token, oauth_expiry
@@ -0,0 +1,26 @@
-- name: InsertTemplateVersionVariable :one
INSERT INTO
template_version_variables (
template_version_id,
name,
description,
type,
value,
default_value,
required,
sensitive
)
VALUES
(
$1,
$2,
$3,
$4,
$5,
$6,
$7,
$8
) RETURNING *;
-- name: GetTemplateVersionVariables :many
SELECT * FROM template_version_variables WHERE template_version_id = $1;
+1
View File
@@ -16,6 +16,7 @@ const (
UniqueProvisionerDaemonsNameKey UniqueConstraint = "provisioner_daemons_name_key" // ALTER TABLE ONLY provisioner_daemons ADD CONSTRAINT provisioner_daemons_name_key UNIQUE (name);
UniqueSiteConfigsKeyKey UniqueConstraint = "site_configs_key_key" // ALTER TABLE ONLY site_configs ADD CONSTRAINT site_configs_key_key UNIQUE (key);
UniqueTemplateVersionParametersTemplateVersionIDNameKey UniqueConstraint = "template_version_parameters_template_version_id_name_key" // ALTER TABLE ONLY template_version_parameters ADD CONSTRAINT template_version_parameters_template_version_id_name_key UNIQUE (template_version_id, name);
UniqueTemplateVersionVariablesTemplateVersionIDNameKey UniqueConstraint = "template_version_variables_template_version_id_name_key" // ALTER TABLE ONLY template_version_variables ADD CONSTRAINT template_version_variables_template_version_id_name_key UNIQUE (template_version_id, name);
UniqueTemplateVersionsTemplateIDNameKey UniqueConstraint = "template_versions_template_id_name_key" // ALTER TABLE ONLY template_versions ADD CONSTRAINT template_versions_template_id_name_key UNIQUE (template_id, name);
UniqueWorkspaceAppsAgentIDSlugIndex UniqueConstraint = "workspace_apps_agent_id_slug_idx" // ALTER TABLE ONLY workspace_apps ADD CONSTRAINT workspace_apps_agent_id_slug_idx UNIQUE (agent_id, slug);
UniqueWorkspaceBuildParametersWorkspaceBuildIDNameKey UniqueConstraint = "workspace_build_parameters_workspace_build_id_name_key" // ALTER TABLE ONLY workspace_build_parameters ADD CONSTRAINT workspace_build_parameters_workspace_build_id_name_key UNIQUE (workspace_build_id, name);
+123 -1
View File
@@ -10,6 +10,7 @@ import (
"net/url"
"reflect"
"strconv"
"strings"
"sync"
"sync/atomic"
"time"
@@ -145,6 +146,10 @@ func (server *Server) AcquireJob(ctx context.Context, _ *proto.Empty) (*proto.Ac
if err != nil {
return nil, failJob(fmt.Sprintf("get template version: %s", err))
}
templateVariables, err := server.Database.GetTemplateVersionVariables(ctx, templateVersion.ID)
if err != nil && !xerrors.Is(err, sql.ErrNoRows) {
return nil, failJob(fmt.Sprintf("get template version variables: %s", err))
}
template, err := server.Database.GetTemplateByID(ctx, templateVersion.TemplateID.UUID)
if err != nil {
return nil, failJob(fmt.Sprintf("get template: %s", err))
@@ -196,6 +201,7 @@ func (server *Server) AcquireJob(ctx context.Context, _ *proto.Empty) (*proto.Ac
State: workspaceBuild.ProvisionerState,
ParameterValues: protoParameters,
RichParameterValues: convertRichParameterValues(workspaceBuildParameters),
VariableValues: asVariableValues(templateVariables),
Metadata: &sdkproto.Provision_Metadata{
CoderUrl: server.AccessURL.String(),
WorkspaceTransition: transition,
@@ -218,6 +224,10 @@ func (server *Server) AcquireJob(ctx context.Context, _ *proto.Empty) (*proto.Ac
if err != nil {
return nil, failJob(fmt.Sprintf("get template version: %s", err))
}
templateVariables, err := server.Database.GetTemplateVersionVariables(ctx, templateVersion.ID)
if err != nil && !xerrors.Is(err, sql.ErrNoRows) {
return nil, failJob(fmt.Sprintf("get template version variables: %s", err))
}
// Compute parameters for the dry-run to consume.
parameters, err := parameter.Compute(ctx, server.Database, parameter.ComputeScope{
@@ -240,6 +250,7 @@ func (server *Server) AcquireJob(ctx context.Context, _ *proto.Empty) (*proto.Ac
TemplateDryRun: &proto.AcquiredJob_TemplateDryRun{
ParameterValues: protoParameters,
RichParameterValues: convertRichParameterValues(input.RichParameterValues),
VariableValues: asVariableValues(templateVariables),
Metadata: &sdkproto.Provision_Metadata{
CoderUrl: server.AccessURL.String(),
WorkspaceName: input.WorkspaceName,
@@ -247,8 +258,15 @@ func (server *Server) AcquireJob(ctx context.Context, _ *proto.Empty) (*proto.Ac
},
}
case database.ProvisionerJobTypeTemplateVersionImport:
var input TemplateVersionImportJob
err = json.Unmarshal(job.Input, &input)
if err != nil {
return nil, failJob(fmt.Sprintf("unmarshal job input %q: %s", job.Input, err))
}
protoJob.Type = &proto.AcquiredJob_TemplateImport_{
TemplateImport: &proto.AcquiredJob_TemplateImport{
UserVariableValues: convertVariableValues(input.UserVariableValues),
Metadata: &sdkproto.Provision_Metadata{
CoderUrl: server.AccessURL.String(),
},
@@ -387,6 +405,61 @@ func (server *Server) UpdateJob(ctx context.Context, request *proto.UpdateJobReq
}
}
if len(request.TemplateVariables) > 0 {
templateVersion, err := server.Database.GetTemplateVersionByJobID(ctx, job.ID)
if err != nil {
server.Logger.Error(ctx, "failed to get the template version", slog.F("job_id", parsedID), slog.Error(err))
return nil, xerrors.Errorf("get template version by job id: %w", err)
}
var variableValues []*sdkproto.VariableValue
var variablesWithMissingValues []string
for _, templateVariable := range request.TemplateVariables {
server.Logger.Debug(ctx, "insert template variable", slog.F("template_version_id", templateVersion.ID), slog.F("template_variable", redactTemplateVariable(templateVariable)))
var value = templateVariable.DefaultValue
for _, v := range request.UserVariableValues {
if v.Name == templateVariable.Name {
value = v.Value
break
}
}
if templateVariable.Required && value == "" {
variablesWithMissingValues = append(variablesWithMissingValues, templateVariable.Name)
}
variableValues = append(variableValues, &sdkproto.VariableValue{
Name: templateVariable.Name,
Value: value,
Sensitive: templateVariable.Sensitive,
})
_, err = server.Database.InsertTemplateVersionVariable(ctx, database.InsertTemplateVersionVariableParams{
TemplateVersionID: templateVersion.ID,
Name: templateVariable.Name,
Description: templateVariable.Description,
Type: templateVariable.Type,
DefaultValue: templateVariable.DefaultValue,
Required: templateVariable.Required,
Sensitive: templateVariable.Sensitive,
Value: value,
})
if err != nil {
return nil, xerrors.Errorf("insert parameter schema: %w", err)
}
}
if len(variablesWithMissingValues) > 0 {
return nil, xerrors.Errorf("required template variables need values: %s", strings.Join(variablesWithMissingValues, ", "))
}
return &proto.UpdateJobResponse{
Canceled: job.CanceledAt.Valid,
VariableValues: variableValues,
}, nil
}
if len(request.ParameterSchemas) > 0 {
for index, protoParameter := range request.ParameterSchemas {
validationTypeSystem, err := convertValidationTypeSystem(protoParameter.ValidationTypeSystem)
@@ -1145,6 +1218,17 @@ func convertRichParameterValues(workspaceBuildParameters []database.WorkspaceBui
return protoParameters
}
func convertVariableValues(variableValues []codersdk.VariableValue) []*sdkproto.VariableValue {
protoVariableValues := make([]*sdkproto.VariableValue, len(variableValues))
for i, variableValue := range variableValues {
protoVariableValues[i] = &sdkproto.VariableValue{
Name: variableValue.Name,
Value: variableValue.Value,
}
}
return protoVariableValues
}
func convertComputedParameterValues(parameters []parameter.ComputedValue) ([]*sdkproto.ParameterValue, error) {
protoParameters := make([]*sdkproto.ParameterValue, len(parameters))
for i, computedParameter := range parameters {
@@ -1203,7 +1287,8 @@ func auditActionFromTransition(transition database.WorkspaceTransition) database
}
type TemplateVersionImportJob struct {
TemplateVersionID uuid.UUID `json:"template_version_id"`
TemplateVersionID uuid.UUID `json:"template_version_id"`
UserVariableValues []codersdk.VariableValue `json:"user_variable_values"`
}
// WorkspaceProvisionJob is the payload for the "workspace_provision" job type.
@@ -1232,3 +1317,40 @@ type ProvisionerJobLogsNotifyMessage struct {
func ProvisionerJobLogsNotifyChannel(jobID uuid.UUID) string {
return fmt.Sprintf("provisioner-log-logs:%s", jobID)
}
func asVariableValues(templateVariables []database.TemplateVersionVariable) []*sdkproto.VariableValue {
var apiVariableValues []*sdkproto.VariableValue
for _, v := range templateVariables {
var value = v.Value
if value == "" && v.DefaultValue != "" {
value = v.DefaultValue
}
if value != "" || v.Required {
apiVariableValues = append(apiVariableValues, &sdkproto.VariableValue{
Name: v.Name,
Value: v.Value,
Sensitive: v.Sensitive,
})
}
}
return apiVariableValues
}
func redactTemplateVariable(templateVariable *sdkproto.TemplateVariable) *sdkproto.TemplateVariable {
if templateVariable == nil {
return nil
}
maybeRedacted := &sdkproto.TemplateVariable{
Name: templateVariable.Name,
Description: templateVariable.Description,
Type: templateVariable.Type,
DefaultValue: templateVariable.DefaultValue,
Required: templateVariable.Required,
Sensitive: templateVariable.Sensitive,
}
if maybeRedacted.Sensitive {
maybeRedacted.DefaultValue = "*redacted*"
}
return maybeRedacted
}
@@ -22,6 +22,7 @@ import (
"github.com/coder/coder/codersdk"
"github.com/coder/coder/provisionerd/proto"
sdkproto "github.com/coder/coder/provisionersdk/proto"
"github.com/coder/coder/testutil"
)
func mockAuditor() *atomic.Pointer[audit.Auditor] {
@@ -113,8 +114,26 @@ func TestAcquireJob(t *testing.T) {
Type: database.ProvisionerJobTypeTemplateVersionImport,
Input: must(json.Marshal(provisionerdserver.TemplateVersionImportJob{
TemplateVersionID: version.ID,
UserVariableValues: []codersdk.VariableValue{
{Name: "second", Value: "bah"},
},
})),
})
_ = dbgen.TemplateVersionVariable(t, srv.Database, database.TemplateVersionVariable{
TemplateVersionID: version.ID,
Name: "first",
Value: "first_value",
DefaultValue: "default_value",
Sensitive: true,
})
_ = dbgen.TemplateVersionVariable(t, srv.Database, database.TemplateVersionVariable{
TemplateVersionID: version.ID,
Name: "second",
Value: "second_value",
DefaultValue: "default_value",
Required: true,
Sensitive: false,
})
workspace := dbgen.Workspace(t, srv.Database, database.Workspace{
TemplateID: template.ID,
OwnerID: user.ID,
@@ -168,6 +187,17 @@ func TestAcquireJob(t *testing.T) {
WorkspaceBuildId: build.ID.String(),
WorkspaceName: workspace.Name,
ParameterValues: []*sdkproto.ParameterValue{},
VariableValues: []*sdkproto.VariableValue{
{
Name: "first",
Value: "first_value",
Sensitive: true,
},
{
Name: "second",
Value: "second_value",
},
},
Metadata: &sdkproto.Provision_Metadata{
CoderUrl: srv.AccessURL.String(),
WorkspaceTransition: sdkproto.WorkspaceTransition_START,
@@ -253,6 +283,49 @@ func TestAcquireJob(t *testing.T) {
require.NoError(t, err)
require.JSONEq(t, string(want), string(got))
})
t.Run("TemplateVersionImportWithUserVariable", func(t *testing.T) {
t.Parallel()
srv := setup(t, false)
user := dbgen.User(t, srv.Database, database.User{})
version := dbgen.TemplateVersion(t, srv.Database, database.TemplateVersion{})
file := dbgen.File(t, srv.Database, database.File{CreatedBy: user.ID})
_ = dbgen.ProvisionerJob(t, srv.Database, database.ProvisionerJob{
FileID: file.ID,
InitiatorID: user.ID,
Provisioner: database.ProvisionerTypeEcho,
StorageMethod: database.ProvisionerStorageMethodFile,
Type: database.ProvisionerJobTypeTemplateVersionImport,
Input: must(json.Marshal(provisionerdserver.TemplateVersionImportJob{
TemplateVersionID: version.ID,
UserVariableValues: []codersdk.VariableValue{
{Name: "first", Value: "first_value"},
},
})),
})
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
defer cancel()
job, err := srv.AcquireJob(ctx, nil)
require.NoError(t, err)
got, err := json.Marshal(job.Type)
require.NoError(t, err)
want, err := json.Marshal(&proto.AcquiredJob_TemplateImport_{
TemplateImport: &proto.AcquiredJob_TemplateImport{
UserVariableValues: []*sdkproto.VariableValue{
{Name: "first", Value: "first_value"},
},
Metadata: &sdkproto.Provision_Metadata{
CoderUrl: srv.AccessURL.String(),
},
},
})
require.NoError(t, err)
require.JSONEq(t, string(want), string(got))
})
}
func TestUpdateJob(t *testing.T) {
@@ -384,6 +457,98 @@ func TestUpdateJob(t *testing.T) {
require.NoError(t, err)
require.Equal(t, "# hello world", version.Readme)
})
t.Run("TemplateVariables", func(t *testing.T) {
t.Parallel()
t.Run("Valid", func(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
srv := setup(t, false)
job := setupJob(t, srv)
version, err := srv.Database.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{
ID: uuid.New(),
JobID: job,
})
require.NoError(t, err)
firstTemplateVariable := &sdkproto.TemplateVariable{
Name: "first",
Type: "string",
DefaultValue: "default_value",
Sensitive: true,
}
secondTemplateVariable := &sdkproto.TemplateVariable{
Name: "second",
Type: "string",
Required: true,
Sensitive: true,
}
response, err := srv.UpdateJob(ctx, &proto.UpdateJobRequest{
JobId: job.String(),
TemplateVariables: []*sdkproto.TemplateVariable{
firstTemplateVariable,
secondTemplateVariable,
},
UserVariableValues: []*sdkproto.VariableValue{
{
Name: "second",
Value: "foobar",
},
},
})
require.NoError(t, err)
require.Len(t, response.VariableValues, 2)
templateVariables, err := srv.Database.GetTemplateVersionVariables(ctx, version.ID)
require.NoError(t, err)
require.Len(t, templateVariables, 2)
require.Equal(t, templateVariables[0].Value, firstTemplateVariable.DefaultValue)
require.Equal(t, templateVariables[1].Value, "foobar")
})
t.Run("Missing required value", func(t *testing.T) {
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
defer cancel()
srv := setup(t, false)
job := setupJob(t, srv)
version, err := srv.Database.InsertTemplateVersion(ctx, database.InsertTemplateVersionParams{
ID: uuid.New(),
JobID: job,
})
require.NoError(t, err)
firstTemplateVariable := &sdkproto.TemplateVariable{
Name: "first",
Type: "string",
DefaultValue: "default_value",
Sensitive: true,
}
secondTemplateVariable := &sdkproto.TemplateVariable{
Name: "second",
Type: "string",
Required: true,
Sensitive: true,
}
response, err := srv.UpdateJob(ctx, &proto.UpdateJobRequest{
JobId: job.String(),
TemplateVariables: []*sdkproto.TemplateVariable{
firstTemplateVariable,
secondTemplateVariable,
},
})
require.Error(t, err) // required template variables need values
require.Nil(t, response)
// Even though there is an error returned, variables are stored in the database
// to show the schema in the site UI.
templateVariables, err := srv.Database.GetTemplateVersionVariables(ctx, version.ID)
require.NoError(t, err)
require.Len(t, templateVariables, 2)
require.Equal(t, templateVariables[0].Value, firstTemplateVariable.DefaultValue)
require.Equal(t, templateVariables[1].Value, "")
})
})
}
func TestFailJob(t *testing.T) {
+64 -1
View File
@@ -243,6 +243,48 @@ func (api *API) templateVersionRichParameters(rw http.ResponseWriter, r *http.Re
httpapi.Write(ctx, rw, http.StatusOK, templateVersionParameters)
}
// @Summary Get template variables by template version
// @ID get-template-variables-by-template-version
// @Security CoderSessionToken
// @Produce json
// @Tags Templates
// @Param templateversion path string true "Template version ID" format(uuid)
// @Success 200 {array} codersdk.TemplateVersionVariable
// @Router /templateversions/{templateversion}/variables [get]
func (api *API) templateVersionVariables(rw http.ResponseWriter, r *http.Request) {
ctx := r.Context()
templateVersion := httpmw.TemplateVersionParam(r)
template := httpmw.TemplateParam(r)
if !api.Authorize(r, rbac.ActionRead, templateVersion.RBACObject(template)) {
httpapi.ResourceNotFound(rw)
return
}
job, err := api.Database.GetProvisionerJobByID(ctx, templateVersion.JobID)
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching provisioner job.",
Detail: err.Error(),
})
return
}
if !job.CompletedAt.Valid {
httpapi.Write(ctx, rw, http.StatusPreconditionFailed, codersdk.Response{
Message: "Job hasn't completed!",
})
return
}
dbTemplateVersionVariables, err := api.Database.GetTemplateVersionVariables(ctx, templateVersion.ID)
if err != nil {
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
Message: "Internal error fetching template version variables.",
Detail: err.Error(),
})
return
}
httpapi.Write(ctx, rw, http.StatusOK, convertTemplateVersionVariables(dbTemplateVersionVariables))
}
// @Summary Get parameters by template version
// @ID get-parameters-by-template-version
// @Security CoderSessionToken
@@ -1260,7 +1302,8 @@ func (api *API) postTemplateVersionsByOrganization(rw http.ResponseWriter, r *ht
templateVersionID := uuid.New()
jobInput, err := json.Marshal(provisionerdserver.TemplateVersionImportJob{
TemplateVersionID: templateVersionID,
TemplateVersionID: templateVersionID,
UserVariableValues: req.UserVariableValues,
})
if err != nil {
return xerrors.Errorf("marshal job input: %w", err)
@@ -1480,6 +1523,26 @@ func convertTemplateVersionParameter(param database.TemplateVersionParameter) (c
}, nil
}
func convertTemplateVersionVariables(dbVariables []database.TemplateVersionVariable) []codersdk.TemplateVersionVariable {
variables := make([]codersdk.TemplateVersionVariable, 0)
for _, dbVariable := range dbVariables {
variables = append(variables, convertTemplateVersionVariable(dbVariable))
}
return variables
}
func convertTemplateVersionVariable(variable database.TemplateVersionVariable) codersdk.TemplateVersionVariable {
return codersdk.TemplateVersionVariable{
Name: variable.Name,
Description: variable.Description,
Type: variable.Type,
Value: variable.Value,
DefaultValue: variable.DefaultValue,
Required: variable.Required,
Sensitive: variable.Sensitive,
}
}
func watchTemplateChannel(id uuid.UUID) string {
return fmt.Sprintf("template:%s", id)
}
+120
View File
@@ -1099,3 +1099,123 @@ func TestTemplateExamples(t *testing.T) {
require.EqualValues(t, ls, ex)
})
}
func TestTemplateVersionVariables(t *testing.T) {
t.Parallel()
createEchoResponses := func(templateVariables []*proto.TemplateVariable) *echo.Responses {
return &echo.Responses{
Parse: []*proto.Parse_Response{
{
Type: &proto.Parse_Response_Complete{
Complete: &proto.Parse_Complete{
TemplateVariables: templateVariables,
},
},
},
},
ProvisionPlan: echo.ProvisionComplete,
ProvisionApply: []*proto.Provision_Response{{
Type: &proto.Provision_Response_Complete{
Complete: &proto.Provision_Complete{},
},
}},
}
}
t.Run("Pass value for required variable", func(t *testing.T) {
t.Parallel()
templateVariables := []*proto.TemplateVariable{
{
Name: "first_variable",
Description: "This is the first variable",
Type: "string",
Required: true,
Sensitive: true,
},
}
const firstVariableValue = "foobar"
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID,
createEchoResponses(templateVariables),
func(ctvr *codersdk.CreateTemplateVersionRequest) {
ctvr.UserVariableValues = []codersdk.VariableValue{
{
Name: templateVariables[0].Name,
Value: firstVariableValue,
},
}
},
)
templateVersion := coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
// As user passed the value for the first parameter, the job will succeed.
require.Empty(t, templateVersion.Job.Error)
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
defer cancel()
actualVariables, err := client.TemplateVersionVariables(ctx, templateVersion.ID)
require.NoError(t, err)
require.Len(t, actualVariables, 1)
require.Equal(t, templateVariables[0].Name, actualVariables[0].Name)
require.Equal(t, templateVariables[0].Description, actualVariables[0].Description)
require.Equal(t, templateVariables[0].Type, actualVariables[0].Type)
require.Equal(t, templateVariables[0].DefaultValue, actualVariables[0].DefaultValue)
require.Equal(t, templateVariables[0].Required, actualVariables[0].Required)
require.Equal(t, templateVariables[0].Sensitive, actualVariables[0].Sensitive)
require.Equal(t, firstVariableValue, actualVariables[0].Value)
})
t.Run("Missing value for required variable", func(t *testing.T) {
t.Parallel()
templateVariables := []*proto.TemplateVariable{
{
Name: "first_variable",
Description: "This is the first variable",
Type: "string",
Required: true,
Sensitive: true,
},
{
Name: "second_variable",
Description: "This is the second variable",
DefaultValue: "123",
Type: "number",
},
}
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
user := coderdtest.CreateFirstUser(t, client)
version := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, createEchoResponses(templateVariables))
templateVersion := coderdtest.AwaitTemplateVersionJob(t, client, version.ID)
// As the first variable is marked as required and misses the default value,
// the job will fail, but will populate the template_version_variables table with existing variables.
require.Contains(t, templateVersion.Job.Error, "required template variables need values")
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitShort)
defer cancel()
actualVariables, err := client.TemplateVersionVariables(ctx, templateVersion.ID)
require.NoError(t, err)
require.Len(t, actualVariables, 2)
for i := range templateVariables {
require.Equal(t, templateVariables[i].Name, actualVariables[i].Name)
require.Equal(t, templateVariables[i].Description, actualVariables[i].Description)
require.Equal(t, templateVariables[i].Type, actualVariables[i].Type)
require.Equal(t, templateVariables[i].DefaultValue, actualVariables[i].DefaultValue)
require.Equal(t, templateVariables[i].Required, actualVariables[i].Required)
require.Equal(t, templateVariables[i].Sensitive, actualVariables[i].Sensitive)
}
require.Equal(t, "", actualVariables[0].Value)
require.Equal(t, templateVariables[1].DefaultValue, actualVariables[1].Value)
})
}
-1
View File
@@ -461,7 +461,6 @@ func (api *API) postWorkspacesByOrganization(rw http.ResponseWriter, r *http.Req
}
tags := provisionerdserver.MutateTags(user.ID, templateVersionJob.Tags)
var (
provisionerJob database.ProvisionerJob
workspaceBuild database.WorkspaceBuild
+7
View File
@@ -54,6 +54,13 @@ type CreateTemplateVersionRequest struct {
// ParameterValues allows for additional parameters to be provided
// during the dry-run provision stage.
ParameterValues []CreateParameterRequest `json:"parameter_values,omitempty"`
UserVariableValues []VariableValue `json:"user_variable_values,omitempty"`
}
type VariableValue struct {
Name string `json:"name"`
Value string `json:"value"`
}
// CreateTemplateRequest provides options when creating a template.
+26
View File
@@ -56,6 +56,17 @@ type TemplateVersionParameterOption struct {
Icon string `json:"icon"`
}
// TemplateVersionVariable represents a managed template variable.
type TemplateVersionVariable struct {
Name string `json:"name"`
Description string `json:"description"`
Type string `json:"type" enums:"string,number,bool"`
Value string `json:"value"`
DefaultValue string `json:"default_value"`
Required bool `json:"required"`
Sensitive bool `json:"sensitive"`
}
// TemplateVersion returns a template version by ID.
func (c *Client) TemplateVersion(ctx context.Context, id uuid.UUID) (TemplateVersion, error) {
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/templateversions/%s", id), nil)
@@ -139,6 +150,20 @@ func (c *Client) TemplateVersionResources(ctx context.Context, version uuid.UUID
return resources, json.NewDecoder(res.Body).Decode(&resources)
}
// TemplateVersionVariables returns resources a template version variables.
func (c *Client) TemplateVersionVariables(ctx context.Context, version uuid.UUID) ([]TemplateVersionVariable, error) {
res, err := c.Request(ctx, http.MethodGet, fmt.Sprintf("/api/v2/templateversions/%s/variables", version), nil)
if err != nil {
return nil, err
}
defer res.Body.Close()
if res.StatusCode != http.StatusOK {
return nil, ReadBodyAsError(res)
}
var variables []TemplateVersionVariable
return variables, json.NewDecoder(res.Body).Decode(&variables)
}
// TemplateVersionLogsBefore returns logs that occurred before a specific log ID.
func (c *Client) TemplateVersionLogsBefore(ctx context.Context, version uuid.UUID, before int64) ([]ProvisionerJobLog, error) {
return c.provisionerJobLogsBefore(ctx, fmt.Sprintf("/api/v2/templateversions/%s/logs", version), before)
@@ -155,6 +180,7 @@ type CreateTemplateVersionDryRunRequest struct {
WorkspaceName string `json:"workspace_name"`
ParameterValues []CreateParameterRequest `json:"parameter_values"`
RichParameterValues []WorkspaceBuildParameter `json:"rich_parameter_values"`
UserVariableValues []VariableValue `json:"user_variable_values,omitempty"`
}
// CreateTemplateVersionDryRun begins a dry-run provisioner job against the
+57
View File
@@ -1000,6 +1000,12 @@ CreateParameterRequest is a structure used to create a new parameter value for a
"value": "string"
}
],
"user_variable_values": [
{
"name": "string",
"value": "string"
}
],
"workspace_name": "string"
}
```
@@ -1010,6 +1016,7 @@ CreateParameterRequest is a structure used to create a new parameter value for a
| ----------------------- | ----------------------------------------------------------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------- |
| `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 | | |
| `user_variable_values` | array of [codersdk.VariableValue](#codersdkvariablevalue) | false | | |
| `workspace_name` | string | false | | |
## codersdk.CreateTestAuditLogRequest
@@ -4638,6 +4645,40 @@ Parameter represents a set value for the scope.
| `name` | string | false | | |
| `value` | string | false | | |
## codersdk.TemplateVersionVariable
```json
{
"default_value": "string",
"description": "string",
"name": "string",
"required": true,
"sensitive": true,
"type": "string",
"value": "string"
}
```
### Properties
| Name | Type | Required | Restrictions | Description |
| --------------- | ------- | -------- | ------------ | ----------- |
| `default_value` | string | false | | |
| `description` | string | false | | |
| `name` | string | false | | |
| `required` | boolean | false | | |
| `sensitive` | boolean | false | | |
| `type` | string | false | | |
| `value` | string | false | | |
#### Enumerated Values
| Property | Value |
| -------- | -------- |
| `type` | `string` |
| `type` | `number` |
| `type` | `bool` |
## codersdk.TraceConfig
```json
@@ -4946,6 +4987,22 @@ Parameter represents a set value for the scope.
| `increasing` |
| `decreasing` |
## codersdk.VariableValue
```json
{
"name": "string",
"value": "string"
}
```
### Properties
| Name | Type | Required | Restrictions | Description |
| ------- | ------ | -------- | ------------ | ----------- |
| `name` | string | false | | |
| `value` | string | false | | |
## codersdk.Workspace
```json
+80
View File
@@ -560,6 +560,12 @@ curl -X POST http://coder-server:8080/api/v2/organizations/{organization}/templa
"value": "string"
}
],
"user_variable_values": [
{
"name": "string",
"value": "string"
}
],
"workspace_name": "string"
}
```
@@ -1299,6 +1305,12 @@ curl -X POST http://coder-server:8080/api/v2/templateversions/{templateversion}/
"value": "string"
}
],
"user_variable_values": [
{
"name": "string",
"value": "string"
}
],
"workspace_name": "string"
}
```
@@ -2246,3 +2258,71 @@ Status Code **200**
| `default_source_scheme` | `data` |
To perform this operation, you must be authenticated. [Learn more](authentication.md).
## Get template variables by template version
### Code samples
```shell
# Example request using curl
curl -X GET http://coder-server:8080/api/v2/templateversions/{templateversion}/variables \
-H 'Accept: application/json' \
-H 'Coder-Session-Token: API_KEY'
```
`GET /templateversions/{templateversion}/variables`
### Parameters
| Name | In | Type | Required | Description |
| ----------------- | ---- | ------------ | -------- | ------------------- |
| `templateversion` | path | string(uuid) | true | Template version ID |
### Example responses
> 200 Response
```json
[
{
"default_value": "string",
"description": "string",
"name": "string",
"required": true,
"sensitive": true,
"type": "string",
"value": "string"
}
]
```
### Responses
| Status | Meaning | Description | Schema |
| ------ | ------------------------------------------------------- | ----------- | --------------------------------------------------------------------------------------- |
| 200 | [OK](https://tools.ietf.org/html/rfc7231#section-6.3.1) | OK | array of [codersdk.TemplateVersionVariable](schemas.md#codersdktemplateversionvariable) |
<h3 id="get-template-variables-by-template-version-responseschema">Response Schema</h3>
Status Code **200**
| Name | Type | Required | Restrictions | Description |
| ----------------- | ------- | -------- | ------------ | ----------- |
| `[array item]` | array | false | | |
| `» default_value` | string | false | | |
| `» description` | string | false | | |
| `» name` | string | false | | |
| `» required` | boolean | false | | |
| `» sensitive` | boolean | false | | |
| `» type` | string | false | | |
| `» value` | string | false | | |
#### Enumerated Values
| Property | Value |
| -------- | -------- |
| `type` | `string` |
| `type` | `number` |
| `type` | `bool` |
To perform this operation, you must be authenticated. [Learn more](authentication.md).
+1
View File
@@ -15,6 +15,7 @@ coder templates push [template] [flags]
--name string Specify a name for the new template version. It will be automatically generated if not provided.
--parameter-file string Specify a file path with parameter values.
--provisioner-tag stringArray Specify a set of tags to target provisioner daemons.
--values-file string Specify a file path with values for managed variables.
-y, --yes Bypass prompts
```
+142 -8
View File
@@ -4,10 +4,14 @@ import (
"encoding/json"
"fmt"
"os"
"path"
"path/filepath"
"sort"
"strings"
"github.com/hashicorp/hcl/v2"
"github.com/hashicorp/hcl/v2/gohcl"
"github.com/hashicorp/hcl/v2/hclparse"
"github.com/hashicorp/terraform-config-inspect/tfconfig"
"github.com/mitchellh/go-wordwrap"
"golang.org/x/xerrors"
@@ -15,6 +19,25 @@ import (
"github.com/coder/coder/provisionersdk/proto"
)
const featureUseManagedVariables = "feature_use_managed_variables"
var terraformWithFeaturesSchema = &hcl.BodySchema{
Blocks: []hcl.BlockHeaderSchema{
{
Type: "provider",
LabelNames: []string{"type"},
},
},
}
var providerFeaturesConfigSchema = &hcl.BodySchema{
Attributes: []hcl.AttributeSchema{
{
Name: featureUseManagedVariables,
},
},
}
// Parse extracts Terraform variables from source-code.
func (*server) Parse(request *proto.Parse_Request, stream proto.DRPCProvisioner_ParseStream) error {
// Load the module and print any parse errors.
@@ -23,6 +46,11 @@ func (*server) Parse(request *proto.Parse_Request, stream proto.DRPCProvisioner_
return xerrors.Errorf("load module: %s", formatDiagnostics(request.Directory, diags))
}
flags, flagsDiags := loadEnabledFeatures(request.Directory)
if flagsDiags.HasErrors() {
return xerrors.Errorf("load coder provider features: %s", formatDiagnostics(request.Directory, diags))
}
// Sort variables by (filename, line) to make the ordering consistent
variables := make([]*tfconfig.Variable, 0, len(module.Variables))
for _, v := range module.Variables {
@@ -32,25 +60,106 @@ func (*server) Parse(request *proto.Parse_Request, stream proto.DRPCProvisioner_
return compareSourcePos(variables[i].Pos, variables[j].Pos)
})
parameters := make([]*proto.ParameterSchema, 0, len(variables))
for _, v := range variables {
schema, err := convertVariableToParameter(v)
if err != nil {
return xerrors.Errorf("convert variable %q: %w", v.Name, err)
var parameters []*proto.ParameterSchema
var templateVariables []*proto.TemplateVariable
useManagedVariables := flags != nil && flags[featureUseManagedVariables]
if useManagedVariables {
for _, v := range variables {
mv, err := convertTerraformVariableToManagedVariable(v)
if err != nil {
return xerrors.Errorf("can't convert the Terraform variable to a managed one: %w", err)
}
templateVariables = append(templateVariables, mv)
}
} else {
for _, v := range variables {
schema, err := convertVariableToParameter(v)
if err != nil {
return xerrors.Errorf("convert variable %q: %w", v.Name, err)
}
parameters = append(parameters, schema)
parameters = append(parameters, schema)
}
}
return stream.Send(&proto.Parse_Response{
Type: &proto.Parse_Response_Complete{
Complete: &proto.Parse_Complete{
ParameterSchemas: parameters,
ParameterSchemas: parameters,
TemplateVariables: templateVariables,
},
},
})
}
func loadEnabledFeatures(moduleDir string) (map[string]bool, hcl.Diagnostics) {
flags := map[string]bool{}
var diags hcl.Diagnostics
entries, err := os.ReadDir(moduleDir)
if err != nil {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: "Failed to read module directory",
Detail: fmt.Sprintf("Module directory %s does not exist or cannot be read.", moduleDir),
})
return flags, diags
}
var found bool
for _, entry := range entries {
if !strings.HasSuffix(entry.Name(), ".tf") {
continue
}
flags, found, diags = parseFeatures(path.Join(moduleDir, entry.Name()))
if found {
break
}
}
return flags, diags
}
func parseFeatures(hclFilepath string) (map[string]bool, bool, hcl.Diagnostics) {
flags := map[string]bool{}
var diags hcl.Diagnostics
_, err := os.Stat(hclFilepath)
if os.IsNotExist(err) {
return flags, false, diags
} else if err != nil {
diags = append(diags, &hcl.Diagnostic{
Severity: hcl.DiagError,
Summary: fmt.Sprintf("Failed to open %q file", hclFilepath),
})
return flags, false, diags
}
parser := hclparse.NewParser()
parsedHCL, diags := parser.ParseHCLFile(hclFilepath)
if diags.HasErrors() {
return flags, false, diags
}
var found bool
content, _ := parsedHCL.Body.Content(terraformWithFeaturesSchema)
for _, block := range content.Blocks {
if block.Type == "provider" && block.Labels[0] == "coder" {
content, _, partialDiags := block.Body.PartialContent(providerFeaturesConfigSchema)
diags = append(diags, partialDiags...)
if attr, defined := content.Attributes[featureUseManagedVariables]; defined {
found = true
var useManagedVariables bool
partialDiags := gohcl.DecodeExpression(attr.Expr, nil, &useManagedVariables)
diags = append(diags, partialDiags...)
flags[featureUseManagedVariables] = useManagedVariables
}
}
}
return flags, found, diags
}
// Converts a Terraform variable to a provisioner parameter.
func convertVariableToParameter(variable *tfconfig.Variable) (*proto.ParameterSchema, error) {
schema := &proto.ParameterSchema{
@@ -96,6 +205,31 @@ func convertVariableToParameter(variable *tfconfig.Variable) (*proto.ParameterSc
return schema, nil
}
// Converts a Terraform variable to a managed variable.
func convertTerraformVariableToManagedVariable(variable *tfconfig.Variable) (*proto.TemplateVariable, error) {
var defaultData string
if variable.Default != nil {
var valid bool
defaultData, valid = variable.Default.(string)
if !valid {
defaultDataRaw, err := json.Marshal(variable.Default)
if err != nil {
return nil, xerrors.Errorf("parse variable %q default: %w", variable.Name, err)
}
defaultData = string(defaultDataRaw)
}
}
return &proto.TemplateVariable{
Name: variable.Name,
Description: variable.Description,
Type: variable.Type,
DefaultValue: defaultData,
Required: defaultData == "", // variable.Required is always false?
Sensitive: variable.Sensitive,
}, nil
}
// formatDiagnostics returns a nicely formatted string containing all of the
// error details within the tfconfig.Diagnostics. We need to use this because
// the default format doesn't provide much useful information.
+92 -1
View File
@@ -1,4 +1,4 @@
//go:build linux
//go:build linux || darwin
package terraform_test
@@ -161,6 +161,97 @@ func TestParse(t *testing.T) {
},
},
},
{
Name: "enable-managed-variables-with-default-bool",
Files: map[string]string{
"main.tf": `variable "A" {
description = "Testing!"
type = bool
default = true
sensitive = true
}
provider "coder" {
feature_use_managed_variables = true
}`,
},
Response: &proto.Parse_Response{
Type: &proto.Parse_Response_Complete{
Complete: &proto.Parse_Complete{
TemplateVariables: []*proto.TemplateVariable{
{
Name: "A",
Description: "Testing!",
Type: "bool",
DefaultValue: "true",
Required: false,
Sensitive: true,
},
},
},
},
},
},
{
Name: "enable-managed-variables-with-default-string",
Files: map[string]string{
"main.tf": `variable "A" {
description = "Testing!"
type = string
default = "abc"
sensitive = true
}
provider "coder" {
feature_use_managed_variables = true
}`,
},
Response: &proto.Parse_Response{
Type: &proto.Parse_Response_Complete{
Complete: &proto.Parse_Complete{
TemplateVariables: []*proto.TemplateVariable{
{
Name: "A",
Description: "Testing!",
Type: "string",
DefaultValue: "abc",
Required: false,
Sensitive: true,
},
},
},
},
},
},
{
Name: "enable-managed-variables-without-default",
Files: map[string]string{
"main2.tf": `variable "A" {
description = "Testing!"
type = string
sensitive = true
}
provider "coder" {
feature_use_managed_variables = true
}`,
},
Response: &proto.Parse_Response{
Type: &proto.Parse_Response_Complete{
Complete: &proto.Parse_Complete{
TemplateVariables: []*proto.TemplateVariable{
{
Name: "A",
Description: "Testing!",
Type: "string",
Required: true,
Sensitive: true,
},
},
},
},
},
},
}
for _, testCase := range testCases {
+3 -1
View File
@@ -138,7 +138,6 @@ func (s *server) Provision(stream proto.DRPCProvisioner_ProvisionStream) error {
return xerrors.Errorf("initialize terraform: %w", err)
}
s.logger.Debug(ctx, "ran initialization")
env, err := provisionEnv(config, request.GetPlan().GetParameterValues(), request.GetPlan().GetRichParameterValues())
if err != nil {
return err
@@ -202,6 +201,9 @@ func planVars(plan *proto.Provision_Plan) ([]string, error) {
return nil, xerrors.Errorf("unsupported parameter type %q for %q", param.DestinationScheme, param.Name)
}
}
for _, variable := range plan.VariableValues {
vars = append(vars, fmt.Sprintf("%s=%s", variable.Name, variable.Value))
}
return vars, nil
}
+286 -202
View File
@@ -544,10 +544,12 @@ type UpdateJobRequest struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
Logs []*Log `protobuf:"bytes,2,rep,name=logs,proto3" json:"logs,omitempty"`
ParameterSchemas []*proto.ParameterSchema `protobuf:"bytes,3,rep,name=parameter_schemas,json=parameterSchemas,proto3" json:"parameter_schemas,omitempty"`
Readme []byte `protobuf:"bytes,4,opt,name=readme,proto3" json:"readme,omitempty"`
JobId string `protobuf:"bytes,1,opt,name=job_id,json=jobId,proto3" json:"job_id,omitempty"`
Logs []*Log `protobuf:"bytes,2,rep,name=logs,proto3" json:"logs,omitempty"`
ParameterSchemas []*proto.ParameterSchema `protobuf:"bytes,3,rep,name=parameter_schemas,json=parameterSchemas,proto3" json:"parameter_schemas,omitempty"`
TemplateVariables []*proto.TemplateVariable `protobuf:"bytes,4,rep,name=template_variables,json=templateVariables,proto3" json:"template_variables,omitempty"`
UserVariableValues []*proto.VariableValue `protobuf:"bytes,5,rep,name=user_variable_values,json=userVariableValues,proto3" json:"user_variable_values,omitempty"`
Readme []byte `protobuf:"bytes,6,opt,name=readme,proto3" json:"readme,omitempty"`
}
func (x *UpdateJobRequest) Reset() {
@@ -603,6 +605,20 @@ func (x *UpdateJobRequest) GetParameterSchemas() []*proto.ParameterSchema {
return nil
}
func (x *UpdateJobRequest) GetTemplateVariables() []*proto.TemplateVariable {
if x != nil {
return x.TemplateVariables
}
return nil
}
func (x *UpdateJobRequest) GetUserVariableValues() []*proto.VariableValue {
if x != nil {
return x.UserVariableValues
}
return nil
}
func (x *UpdateJobRequest) GetReadme() []byte {
if x != nil {
return x.Readme
@@ -619,6 +635,7 @@ type UpdateJobResponse struct {
// If parameter schemas are sent, the job will respond
// with resolved parameter values.
ParameterValues []*proto.ParameterValue `protobuf:"bytes,2,rep,name=parameter_values,json=parameterValues,proto3" json:"parameter_values,omitempty"`
VariableValues []*proto.VariableValue `protobuf:"bytes,3,rep,name=variable_values,json=variableValues,proto3" json:"variable_values,omitempty"`
}
func (x *UpdateJobResponse) Reset() {
@@ -667,6 +684,13 @@ func (x *UpdateJobResponse) GetParameterValues() []*proto.ParameterValue {
return nil
}
func (x *UpdateJobResponse) GetVariableValues() []*proto.VariableValue {
if x != nil {
return x.VariableValues
}
return nil
}
type CommitQuotaRequest struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -794,8 +818,9 @@ type AcquiredJob_WorkspaceBuild struct {
WorkspaceName string `protobuf:"bytes,2,opt,name=workspace_name,json=workspaceName,proto3" json:"workspace_name,omitempty"`
ParameterValues []*proto.ParameterValue `protobuf:"bytes,3,rep,name=parameter_values,json=parameterValues,proto3" json:"parameter_values,omitempty"`
RichParameterValues []*proto.RichParameterValue `protobuf:"bytes,4,rep,name=rich_parameter_values,json=richParameterValues,proto3" json:"rich_parameter_values,omitempty"`
Metadata *proto.Provision_Metadata `protobuf:"bytes,5,opt,name=metadata,proto3" json:"metadata,omitempty"`
State []byte `protobuf:"bytes,6,opt,name=state,proto3" json:"state,omitempty"`
VariableValues []*proto.VariableValue `protobuf:"bytes,5,rep,name=variable_values,json=variableValues,proto3" json:"variable_values,omitempty"`
Metadata *proto.Provision_Metadata `protobuf:"bytes,6,opt,name=metadata,proto3" json:"metadata,omitempty"`
State []byte `protobuf:"bytes,7,opt,name=state,proto3" json:"state,omitempty"`
}
func (x *AcquiredJob_WorkspaceBuild) Reset() {
@@ -858,6 +883,13 @@ func (x *AcquiredJob_WorkspaceBuild) GetRichParameterValues() []*proto.RichParam
return nil
}
func (x *AcquiredJob_WorkspaceBuild) GetVariableValues() []*proto.VariableValue {
if x != nil {
return x.VariableValues
}
return nil
}
func (x *AcquiredJob_WorkspaceBuild) GetMetadata() *proto.Provision_Metadata {
if x != nil {
return x.Metadata
@@ -877,7 +909,8 @@ type AcquiredJob_TemplateImport struct {
sizeCache protoimpl.SizeCache
unknownFields protoimpl.UnknownFields
Metadata *proto.Provision_Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"`
Metadata *proto.Provision_Metadata `protobuf:"bytes,1,opt,name=metadata,proto3" json:"metadata,omitempty"`
UserVariableValues []*proto.VariableValue `protobuf:"bytes,2,rep,name=user_variable_values,json=userVariableValues,proto3" json:"user_variable_values,omitempty"`
}
func (x *AcquiredJob_TemplateImport) Reset() {
@@ -919,6 +952,13 @@ func (x *AcquiredJob_TemplateImport) GetMetadata() *proto.Provision_Metadata {
return nil
}
func (x *AcquiredJob_TemplateImport) GetUserVariableValues() []*proto.VariableValue {
if x != nil {
return x.UserVariableValues
}
return nil
}
type AcquiredJob_TemplateDryRun struct {
state protoimpl.MessageState
sizeCache protoimpl.SizeCache
@@ -926,7 +966,8 @@ type AcquiredJob_TemplateDryRun struct {
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"`
VariableValues []*proto.VariableValue `protobuf:"bytes,3,rep,name=variable_values,json=variableValues,proto3" json:"variable_values,omitempty"`
Metadata *proto.Provision_Metadata `protobuf:"bytes,4,opt,name=metadata,proto3" json:"metadata,omitempty"`
}
func (x *AcquiredJob_TemplateDryRun) Reset() {
@@ -975,6 +1016,13 @@ func (x *AcquiredJob_TemplateDryRun) GetRichParameterValues() []*proto.RichParam
return nil
}
func (x *AcquiredJob_TemplateDryRun) GetVariableValues() []*proto.VariableValue {
if x != nil {
return x.VariableValues
}
return nil
}
func (x *AcquiredJob_TemplateDryRun) GetMetadata() *proto.Provision_Metadata {
if x != nil {
return x.Metadata
@@ -1279,7 +1327,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, 0xd6, 0x08, 0x0a, 0x0b, 0x41, 0x63, 0x71, 0x75, 0x69,
0x05, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x22, 0xaf, 0x0a, 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,
@@ -1307,7 +1355,7 @@ var file_provisionerd_proto_provisionerd_proto_rawDesc = []byte{
0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x41, 0x63, 0x71, 0x75, 0x69, 0x72, 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, 0xd5, 0x02, 0x0a, 0x0e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63,
0x52, 0x75, 0x6e, 0x1a, 0x9a, 0x03, 0x0a, 0x0e, 0x57, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63,
0x65, 0x42, 0x75, 0x69, 0x6c, 0x64, 0x12, 0x2c, 0x0a, 0x12, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70,
0x61, 0x63, 0x65, 0x5f, 0x62, 0x75, 0x69, 0x6c, 0x64, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
0x28, 0x09, 0x52, 0x10, 0x77, 0x6f, 0x72, 0x6b, 0x73, 0x70, 0x61, 0x63, 0x65, 0x42, 0x75, 0x69,
@@ -1323,171 +1371,199 @@ var file_provisionerd_proto_provisionerd_proto_rawDesc = []byte{
0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72,
0x2e, 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, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f,
0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69,
0x6f, 0x6e, 0x2e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74,
0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x06,
0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x1a, 0x4d, 0x0a, 0x0e, 0x54,
0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x70, 0x6f, 0x72, 0x74, 0x12, 0x3b, 0x0a,
0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32,
0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x43, 0x0a, 0x0f, 0x76, 0x61, 0x72, 0x69,
0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28,
0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e,
0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x0e, 0x76,
0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x3b, 0x0a,
0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x06, 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, 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, 0x53, 0x0a, 0x15, 0x72, 0x69, 0x63, 0x68, 0x5f, 0x70, 0x61,
0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02,
0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e,
0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72,
0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x72, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d,
0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 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,
0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x14, 0x0a, 0x05, 0x73, 0x74,
0x61, 0x74, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65,
0x1a, 0x9b, 0x01, 0x0a, 0x0e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x49, 0x6d, 0x70,
0x6f, 0x72, 0x74, 0x12, 0x3b, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18,
0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f,
0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x4d, 0x65,
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
0x12, 0x4c, 0x0a, 0x14, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c,
0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a,
0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72,
0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x75, 0x73, 0x65, 0x72,
0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x1a, 0xaf,
0x02, 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, 0x53, 0x0a, 0x15, 0x72, 0x69, 0x63,
0x68, 0x5f, 0x70, 0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x6c, 0x75,
0x65, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69,
0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x52, 0x69, 0x63, 0x68, 0x50, 0x61, 0x72, 0x61, 0x6d,
0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x13, 0x72, 0x69, 0x63, 0x68, 0x50,
0x61, 0x72, 0x61, 0x6d, 0x65, 0x74, 0x65, 0x72, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x43,
0x0a, 0x0f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65,
0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73,
0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61,
0x6c, 0x75, 0x65, 0x52, 0x0e, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c,
0x75, 0x65, 0x73, 0x12, 0x3b, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18,
0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1f, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f,
0x6e, 0x65, 0x72, 0x2e, 0x50, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x4d, 0x65,
0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61,
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, 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,
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, 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,
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, 0xcf, 0x02, 0x0a, 0x10, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x4a, 0x6f, 0x62, 0x52,
0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x15, 0x0a, 0x06, 0x6a, 0x6f, 0x62, 0x5f, 0x69, 0x64,
0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x6a, 0x6f, 0x62, 0x49, 0x64, 0x12, 0x25, 0x0a,
0x04, 0x6c, 0x6f, 0x67, 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x70, 0x72,
0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x64, 0x2e, 0x4c, 0x6f, 0x67, 0x52, 0x04,
0x6c, 0x6f, 0x67, 0x73, 0x12, 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,
0x4c, 0x0a, 0x12, 0x74, 0x65, 0x6d, 0x70, 0x6c, 0x61, 0x74, 0x65, 0x5f, 0x76, 0x61, 0x72, 0x69,
0x61, 0x62, 0x6c, 0x65, 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x70, 0x72,
0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x54, 0x65, 0x6d, 0x70, 0x6c, 0x61,
0x74, 0x65, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x52, 0x11, 0x74, 0x65, 0x6d, 0x70,
0x6c, 0x61, 0x74, 0x65, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x73, 0x12, 0x4c, 0x0a,
0x14, 0x75, 0x73, 0x65, 0x72, 0x5f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76,
0x61, 0x6c, 0x75, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72,
0x6f, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62,
0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x52, 0x12, 0x75, 0x73, 0x65, 0x72, 0x56, 0x61, 0x72,
0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75, 0x65, 0x73, 0x12, 0x16, 0x0a, 0x06, 0x72,
0x65, 0x61, 0x64, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x0c, 0x52, 0x06, 0x72, 0x65, 0x61,
0x64, 0x6d, 0x65, 0x22, 0xbc, 0x01, 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, 0x12, 0x43, 0x0a,
0x0f, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x5f, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x73,
0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1a, 0x2e, 0x70, 0x72, 0x6f, 0x76, 0x69, 0x73, 0x69,
0x6f, 0x6e, 0x65, 0x72, 0x2e, 0x56, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c,
0x75, 0x65, 0x52, 0x0e, 0x76, 0x61, 0x72, 0x69, 0x61, 0x62, 0x6c, 0x65, 0x56, 0x61, 0x6c, 0x75,
0x65, 0x73, 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 (
@@ -1526,11 +1602,13 @@ var file_provisionerd_proto_provisionerd_proto_goTypes = []interface{}{
(*CompletedJob_TemplateDryRun)(nil), // 18: provisionerd.CompletedJob.TemplateDryRun
(proto.LogLevel)(0), // 19: provisioner.LogLevel
(*proto.ParameterSchema)(nil), // 20: provisioner.ParameterSchema
(*proto.ParameterValue)(nil), // 21: provisioner.ParameterValue
(*proto.RichParameterValue)(nil), // 22: provisioner.RichParameterValue
(*proto.Provision_Metadata)(nil), // 23: provisioner.Provision.Metadata
(*proto.Resource)(nil), // 24: provisioner.Resource
(*proto.RichParameter)(nil), // 25: provisioner.RichParameter
(*proto.TemplateVariable)(nil), // 21: provisioner.TemplateVariable
(*proto.VariableValue)(nil), // 22: provisioner.VariableValue
(*proto.ParameterValue)(nil), // 23: provisioner.ParameterValue
(*proto.RichParameterValue)(nil), // 24: provisioner.RichParameterValue
(*proto.Provision_Metadata)(nil), // 25: provisioner.Provision.Metadata
(*proto.Resource)(nil), // 26: provisioner.Resource
(*proto.RichParameter)(nil), // 27: provisioner.RichParameter
}
var file_provisionerd_proto_provisionerd_proto_depIdxs = []int32{
10, // 0: provisionerd.AcquiredJob.workspace_build:type_name -> provisionerd.AcquiredJob.WorkspaceBuild
@@ -1546,34 +1624,40 @@ var file_provisionerd_proto_provisionerd_proto_depIdxs = []int32{
19, // 10: provisionerd.Log.level:type_name -> provisioner.LogLevel
5, // 11: provisionerd.UpdateJobRequest.logs:type_name -> provisionerd.Log
20, // 12: provisionerd.UpdateJobRequest.parameter_schemas:type_name -> provisioner.ParameterSchema
21, // 13: provisionerd.UpdateJobResponse.parameter_values:type_name -> provisioner.ParameterValue
21, // 14: provisionerd.AcquiredJob.WorkspaceBuild.parameter_values:type_name -> provisioner.ParameterValue
22, // 15: provisionerd.AcquiredJob.WorkspaceBuild.rich_parameter_values:type_name -> provisioner.RichParameterValue
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
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
21, // 13: provisionerd.UpdateJobRequest.template_variables:type_name -> provisioner.TemplateVariable
22, // 14: provisionerd.UpdateJobRequest.user_variable_values:type_name -> provisioner.VariableValue
23, // 15: provisionerd.UpdateJobResponse.parameter_values:type_name -> provisioner.ParameterValue
22, // 16: provisionerd.UpdateJobResponse.variable_values:type_name -> provisioner.VariableValue
23, // 17: provisionerd.AcquiredJob.WorkspaceBuild.parameter_values:type_name -> provisioner.ParameterValue
24, // 18: provisionerd.AcquiredJob.WorkspaceBuild.rich_parameter_values:type_name -> provisioner.RichParameterValue
22, // 19: provisionerd.AcquiredJob.WorkspaceBuild.variable_values:type_name -> provisioner.VariableValue
25, // 20: provisionerd.AcquiredJob.WorkspaceBuild.metadata:type_name -> provisioner.Provision.Metadata
25, // 21: provisionerd.AcquiredJob.TemplateImport.metadata:type_name -> provisioner.Provision.Metadata
22, // 22: provisionerd.AcquiredJob.TemplateImport.user_variable_values:type_name -> provisioner.VariableValue
23, // 23: provisionerd.AcquiredJob.TemplateDryRun.parameter_values:type_name -> provisioner.ParameterValue
24, // 24: provisionerd.AcquiredJob.TemplateDryRun.rich_parameter_values:type_name -> provisioner.RichParameterValue
22, // 25: provisionerd.AcquiredJob.TemplateDryRun.variable_values:type_name -> provisioner.VariableValue
25, // 26: provisionerd.AcquiredJob.TemplateDryRun.metadata:type_name -> provisioner.Provision.Metadata
26, // 27: provisionerd.CompletedJob.WorkspaceBuild.resources:type_name -> provisioner.Resource
26, // 28: provisionerd.CompletedJob.TemplateImport.start_resources:type_name -> provisioner.Resource
26, // 29: provisionerd.CompletedJob.TemplateImport.stop_resources:type_name -> provisioner.Resource
27, // 30: provisionerd.CompletedJob.TemplateImport.rich_parameters:type_name -> provisioner.RichParameter
26, // 31: provisionerd.CompletedJob.TemplateDryRun.resources:type_name -> provisioner.Resource
1, // 32: provisionerd.ProvisionerDaemon.AcquireJob:input_type -> provisionerd.Empty
8, // 33: provisionerd.ProvisionerDaemon.CommitQuota:input_type -> provisionerd.CommitQuotaRequest
6, // 34: provisionerd.ProvisionerDaemon.UpdateJob:input_type -> provisionerd.UpdateJobRequest
3, // 35: provisionerd.ProvisionerDaemon.FailJob:input_type -> provisionerd.FailedJob
4, // 36: provisionerd.ProvisionerDaemon.CompleteJob:input_type -> provisionerd.CompletedJob
2, // 37: provisionerd.ProvisionerDaemon.AcquireJob:output_type -> provisionerd.AcquiredJob
9, // 38: provisionerd.ProvisionerDaemon.CommitQuota:output_type -> provisionerd.CommitQuotaResponse
7, // 39: provisionerd.ProvisionerDaemon.UpdateJob:output_type -> provisionerd.UpdateJobResponse
1, // 40: provisionerd.ProvisionerDaemon.FailJob:output_type -> provisionerd.Empty
1, // 41: provisionerd.ProvisionerDaemon.CompleteJob:output_type -> provisionerd.Empty
37, // [37:42] is the sub-list for method output_type
32, // [32:37] is the sub-list for method input_type
32, // [32:32] is the sub-list for extension type_name
32, // [32:32] is the sub-list for extension extendee
0, // [0:32] is the sub-list for field type_name
}
func init() { file_provisionerd_proto_provisionerd_proto_init() }
+10 -4
View File
@@ -16,16 +16,19 @@ message AcquiredJob {
string workspace_name = 2;
repeated provisioner.ParameterValue parameter_values = 3;
repeated provisioner.RichParameterValue rich_parameter_values = 4;
provisioner.Provision.Metadata metadata = 5;
bytes state = 6;
repeated provisioner.VariableValue variable_values = 5;
provisioner.Provision.Metadata metadata = 6;
bytes state = 7;
}
message TemplateImport {
provisioner.Provision.Metadata metadata = 1;
repeated provisioner.VariableValue user_variable_values = 2;
}
message TemplateDryRun {
repeated provisioner.ParameterValue parameter_values = 1;
repeated provisioner.RichParameterValue rich_parameter_values = 2;
provisioner.Provision.Metadata metadata = 3;
repeated provisioner.VariableValue variable_values = 3;
provisioner.Provision.Metadata metadata = 4;
}
string job_id = 1;
@@ -99,7 +102,9 @@ message UpdateJobRequest {
string job_id = 1;
repeated Log logs = 2;
repeated provisioner.ParameterSchema parameter_schemas = 3;
bytes readme = 4;
repeated provisioner.TemplateVariable template_variables = 4;
repeated provisioner.VariableValue user_variable_values = 5;
bytes readme = 6;
}
message UpdateJobResponse {
@@ -107,6 +112,7 @@ message UpdateJobResponse {
// If parameter schemas are sent, the job will respond
// with resolved parameter values.
repeated provisioner.ParameterValue parameter_values = 2;
repeated provisioner.VariableValue variable_values = 3;
}
message CommitQuotaRequest {
+46 -16
View File
@@ -416,7 +416,9 @@ func (r *Runner) do(ctx context.Context) (*proto.CompletedJob, *proto.FailedJob)
}
switch jobType := r.job.Type.(type) {
case *proto.AcquiredJob_TemplateImport_:
r.logger.Debug(context.Background(), "acquired job is template import")
r.logger.Debug(context.Background(), "acquired job is template import",
slog.F("user_variable_values", redactVariableValues(jobType.TemplateImport.UserVariableValues)),
)
failedJob := r.runReadmeParse(ctx)
if failedJob != nil {
@@ -428,6 +430,7 @@ func (r *Runner) do(ctx context.Context) (*proto.CompletedJob, *proto.FailedJob)
slog.F("workspace_name", jobType.TemplateDryRun.Metadata.WorkspaceName),
slog.F("parameters", jobType.TemplateDryRun.ParameterValues),
slog.F("rich_parameter_values", jobType.TemplateDryRun.RichParameterValues),
slog.F("variable_values", redactVariableValues(jobType.TemplateDryRun.VariableValues)),
)
return r.runTemplateDryRun(ctx)
case *proto.AcquiredJob_WorkspaceBuild_:
@@ -436,6 +439,7 @@ func (r *Runner) do(ctx context.Context) (*proto.CompletedJob, *proto.FailedJob)
slog.F("state_length", len(jobType.WorkspaceBuild.State)),
slog.F("parameters", jobType.WorkspaceBuild.ParameterValues),
slog.F("rich_parameter_values", jobType.WorkspaceBuild.RichParameterValues),
slog.F("variable_values", redactVariableValues(jobType.WorkspaceBuild.VariableValues)),
)
return r.runWorkspaceBuild(ctx)
default:
@@ -538,13 +542,18 @@ func (r *Runner) runTemplateImport(ctx context.Context) (*proto.CompletedJob, *p
Stage: "Parsing template parameters",
CreatedAt: time.Now().UnixMilli(),
})
parameterSchemas, err := r.runTemplateImportParse(ctx)
parameterSchemas, templateVariables, err := r.runTemplateImportParse(ctx)
if err != nil {
return nil, r.failedJobf("run parse: %s", err)
}
// Once Terraform template variables are parsed, the runner can pass variables
// to store in database and filter valid ones.
updateResponse, err := r.update(ctx, &proto.UpdateJobRequest{
JobId: r.job.JobId,
ParameterSchemas: parameterSchemas,
JobId: r.job.JobId,
ParameterSchemas: parameterSchemas,
TemplateVariables: templateVariables,
UserVariableValues: r.job.GetTemplateImport().GetUserVariableValues(),
})
if err != nil {
return nil, r.failedJobf("update job: %s", err)
@@ -568,7 +577,7 @@ func (r *Runner) runTemplateImport(ctx context.Context) (*proto.CompletedJob, *p
Stage: "Detecting persistent resources",
CreatedAt: time.Now().UnixMilli(),
})
startResources, parameters, err := r.runTemplateImportProvision(ctx, updateResponse.ParameterValues, &sdkproto.Provision_Metadata{
startResources, parameters, err := r.runTemplateImportProvision(ctx, updateResponse.ParameterValues, updateResponse.VariableValues, &sdkproto.Provision_Metadata{
CoderUrl: r.job.GetTemplateImport().Metadata.CoderUrl,
WorkspaceTransition: sdkproto.WorkspaceTransition_START,
})
@@ -583,7 +592,7 @@ func (r *Runner) runTemplateImport(ctx context.Context) (*proto.CompletedJob, *p
Stage: "Detecting ephemeral resources",
CreatedAt: time.Now().UnixMilli(),
})
stopResources, _, err := r.runTemplateImportProvision(ctx, updateResponse.ParameterValues, &sdkproto.Provision_Metadata{
stopResources, _, err := r.runTemplateImportProvision(ctx, updateResponse.ParameterValues, updateResponse.VariableValues, &sdkproto.Provision_Metadata{
CoderUrl: r.job.GetTemplateImport().Metadata.CoderUrl,
WorkspaceTransition: sdkproto.WorkspaceTransition_STOP,
})
@@ -603,8 +612,8 @@ func (r *Runner) runTemplateImport(ctx context.Context) (*proto.CompletedJob, *p
}, nil
}
// Parses parameter schemas from source.
func (r *Runner) runTemplateImportParse(ctx context.Context) ([]*sdkproto.ParameterSchema, error) {
// Parses template variables and parameter schemas from source.
func (r *Runner) runTemplateImportParse(ctx context.Context) ([]*sdkproto.ParameterSchema, []*sdkproto.TemplateVariable, error) {
ctx, span := r.startTrace(ctx, tracing.FuncName())
defer span.End()
@@ -612,13 +621,13 @@ func (r *Runner) runTemplateImportParse(ctx context.Context) ([]*sdkproto.Parame
Directory: r.workDirectory,
})
if err != nil {
return nil, xerrors.Errorf("parse source: %w", err)
return nil, nil, xerrors.Errorf("parse source: %w", err)
}
defer stream.Close()
for {
msg, err := stream.Recv()
if err != nil {
return nil, xerrors.Errorf("recv parse source: %w", err)
return nil, nil, xerrors.Errorf("recv parse source: %w", err)
}
switch msgType := msg.Type.(type) {
case *sdkproto.Parse_Response_Log:
@@ -636,11 +645,13 @@ func (r *Runner) runTemplateImportParse(ctx context.Context) ([]*sdkproto.Parame
})
case *sdkproto.Parse_Response_Complete:
r.logger.Info(context.Background(), "parse complete",
slog.F("parameter_schemas", msgType.Complete.ParameterSchemas))
slog.F("parameter_schemas", msgType.Complete.ParameterSchemas),
slog.F("template_variables", msgType.Complete.TemplateVariables),
)
return msgType.Complete.ParameterSchemas, nil
return msgType.Complete.ParameterSchemas, msgType.Complete.TemplateVariables, nil
default:
return nil, xerrors.Errorf("invalid message type %q received from provisioner",
return nil, nil, xerrors.Errorf("invalid message type %q received from provisioner",
reflect.TypeOf(msg.Type).String())
}
}
@@ -649,13 +660,13 @@ 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.
// 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)
func (r *Runner) runTemplateImportProvision(ctx context.Context, values []*sdkproto.ParameterValue, variableValues []*sdkproto.VariableValue, metadata *sdkproto.Provision_Metadata) ([]*sdkproto.Resource, []*sdkproto.RichParameter, error) {
return r.runTemplateImportProvisionWithRichParameters(ctx, values, variableValues, nil, metadata)
}
// Performs a dry-run provision with provided rich parameters.
// This is used to detect resources that would be provisioned for a workspace in various states.
func (r *Runner) runTemplateImportProvisionWithRichParameters(ctx context.Context, values []*sdkproto.ParameterValue, richParameterValues []*sdkproto.RichParameterValue, metadata *sdkproto.Provision_Metadata) ([]*sdkproto.Resource, []*sdkproto.RichParameter, error) {
func (r *Runner) runTemplateImportProvisionWithRichParameters(ctx context.Context, values []*sdkproto.ParameterValue, variableValues []*sdkproto.VariableValue, richParameterValues []*sdkproto.RichParameterValue, metadata *sdkproto.Provision_Metadata) ([]*sdkproto.Resource, []*sdkproto.RichParameter, error) {
ctx, span := r.startTrace(ctx, tracing.FuncName())
defer span.End()
@@ -694,6 +705,7 @@ func (r *Runner) runTemplateImportProvisionWithRichParameters(ctx context.Contex
},
ParameterValues: values,
RichParameterValues: richParameterValues,
VariableValues: variableValues,
},
},
})
@@ -782,6 +794,7 @@ 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.runTemplateImportProvisionWithRichParameters(ctx,
r.job.GetTemplateDryRun().GetParameterValues(),
r.job.GetTemplateDryRun().GetVariableValues(),
r.job.GetTemplateDryRun().GetRichParameterValues(),
metadata,
)
@@ -958,6 +971,7 @@ func (r *Runner) runWorkspaceBuild(ctx context.Context) (*proto.CompletedJob, *p
Config: config,
ParameterValues: r.job.GetWorkspaceBuild().ParameterValues,
RichParameterValues: r.job.GetWorkspaceBuild().RichParameterValues,
VariableValues: r.job.GetWorkspaceBuild().VariableValues,
},
},
})
@@ -1058,3 +1072,19 @@ func (r *Runner) flushQueuedLogs(ctx context.Context) {
r.logger.Error(ctx, "flush queued logs", slog.Error(err))
}
}
func redactVariableValues(variableValues []*sdkproto.VariableValue) []*sdkproto.VariableValue {
var redacted []*sdkproto.VariableValue
for _, v := range variableValues {
if v.Sensitive {
redacted = append(redacted, &sdkproto.VariableValue{
Name: v.Name,
Value: "*redacted*",
Sensitive: true,
})
continue
}
redacted = append(redacted, v)
}
return redacted
}
+641 -419
View File
File diff suppressed because it is too large Load Diff
+19
View File
@@ -52,6 +52,16 @@ message ParameterSchema {
string validation_condition = 11;
}
// TemplateVariable represents a Terraform variable.
message TemplateVariable {
string name = 1;
string description = 2;
string type = 3;
string default_value = 4;
bool required = 5;
bool sensitive = 6;
}
// RichParameterOption represents a singular option that a parameter may expose.
message RichParameterOption {
string name = 1;
@@ -82,6 +92,13 @@ message RichParameterValue {
string value = 2;
}
// VariableValue holds the key/value mapping of a Terraform variable.
message VariableValue {
string name = 1;
string value = 2;
bool sensitive = 3;
}
// LogLevel represents severity of the log.
enum LogLevel {
TRACE = 0;
@@ -175,6 +192,7 @@ message Parse {
string directory = 1;
}
message Complete {
repeated TemplateVariable template_variables = 1;
repeated ParameterSchema parameter_schemas = 2;
}
message Response {
@@ -216,6 +234,7 @@ message Provision {
Config config = 1;
repeated ParameterValue parameter_values = 2;
repeated RichParameterValue rich_parameter_values = 3;
repeated VariableValue variable_values = 4;
}
message Apply {
+19
View File
@@ -187,6 +187,7 @@ export interface CreateTemplateVersionDryRunRequest {
readonly workspace_name: string
readonly parameter_values: CreateParameterRequest[]
readonly rich_parameter_values: WorkspaceBuildParameter[]
readonly user_variable_values?: VariableValue[]
}
// From codersdk/organizations.go
@@ -199,6 +200,7 @@ export interface CreateTemplateVersionRequest {
readonly provisioner: ProvisionerType
readonly tags: Record<string, string>
readonly parameter_values?: CreateParameterRequest[]
readonly user_variable_values?: VariableValue[]
}
// From codersdk/audit.go
@@ -777,6 +779,17 @@ export interface TemplateVersionParameterOption {
readonly icon: string
}
// From codersdk/templateversions.go
export interface TemplateVersionVariable {
readonly name: string
readonly description: string
readonly type: string
readonly value: string
readonly default_value: string
readonly required: boolean
readonly sensitive: boolean
}
// From codersdk/templates.go
export interface TemplateVersionsByTemplateRequest extends Pagination {
readonly template_id: string
@@ -889,6 +902,12 @@ export interface ValidationError {
readonly detail: string
}
// From codersdk/organizations.go
export interface VariableValue {
readonly name: string
readonly value: string
}
// From codersdk/workspaces.go
export interface Workspace {
readonly id: string