mirror of
https://github.com/coder/coder.git
synced 2025-07-03 16:13:58 +00:00
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:
@ -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) {
|
||||
|
Reference in New Issue
Block a user