Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

feat(provisioner): add support for presets to coder provisioners#16574

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
SasSwart merged 8 commits intomainfromjjs/presets-provisioner
Feb 17, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletionscoderd/presets_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -15,8 +15,6 @@ import (
)

func TestTemplateVersionPresets(t *testing.T) {
// TODO (sasswart): Test case: what if a user tries to read presets or preset parameters from a different org?

t.Parallel()

givenPreset := codersdk.Preset{
Expand Down
51 changes: 51 additions & 0 deletionscoderd/provisionerdserver/provisionerdserver.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1340,6 +1340,11 @@ func (s *server) CompleteJob(ctx context.Context, completed *proto.CompletedJob)
}
}

err = InsertWorkspacePresetsAndParameters(ctx, s.Logger, s.Database, jobID, input.TemplateVersionID, jobType.TemplateImport.Presets, s.timeNow())
if err != nil {
return nil, xerrors.Errorf("insert workspace presets and parameters: %w", err)
}

var completedError sql.NullString

for _, externalAuthProvider := range jobType.TemplateImport.ExternalAuthProviders {
Expand DownExpand Up@@ -1809,6 +1814,52 @@ func InsertWorkspaceModule(ctx context.Context, db database.Store, jobID uuid.UU
return nil
}

func InsertWorkspacePresetsAndParameters(ctx context.Context, logger slog.Logger, db database.Store, jobID uuid.UUID, templateVersionID uuid.UUID, protoPresets []*sdkproto.Preset, t time.Time) error {
for _, preset := range protoPresets {
logger.Info(ctx, "inserting template import job preset",
slog.F("job_id", jobID.String()),
slog.F("preset_name", preset.Name),
)
if err := InsertWorkspacePresetAndParameters(ctx, db, templateVersionID, preset, t); err != nil {
return xerrors.Errorf("insert workspace preset: %w", err)
}
}
return nil
}

func InsertWorkspacePresetAndParameters(ctx context.Context, db database.Store, templateVersionID uuid.UUID, protoPreset *sdkproto.Preset, t time.Time) error {
err := db.InTx(func(tx database.Store) error {
dbPreset, err := tx.InsertPreset(ctx, database.InsertPresetParams{
TemplateVersionID: templateVersionID,
Name: protoPreset.Name,
CreatedAt: t,
})
if err != nil {
return xerrors.Errorf("insert preset: %w", err)
}

var presetParameterNames []string
var presetParameterValues []string
for _, parameter := range protoPreset.Parameters {
presetParameterNames = append(presetParameterNames, parameter.Name)
presetParameterValues = append(presetParameterValues, parameter.Value)
}
_, err = tx.InsertPresetParameters(ctx, database.InsertPresetParametersParams{
TemplateVersionPresetID: dbPreset.ID,
Names: presetParameterNames,
Values: presetParameterValues,
})
if err != nil {
return xerrors.Errorf("insert preset parameters: %w", err)
}
return nil
}, nil)
if err != nil {
return xerrors.Errorf("insert preset and parameters: %w", err)
}
return nil
}

func InsertWorkspaceResource(ctx context.Context, db database.Store, jobID uuid.UUID, transition database.WorkspaceTransition, protoResource *sdkproto.Resource, snapshot *telemetry.Snapshot) error {
resource, err := db.InsertWorkspaceResource(ctx, database.InsertWorkspaceResourceParams{
ID: uuid.New(),
Expand Down
150 changes: 150 additions & 0 deletionscoderd/provisionerdserver/provisionerdserver_test.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -30,6 +30,7 @@ import (
"github.com/coder/coder/v2/coderd/database"
"github.com/coder/coder/v2/coderd/database/dbgen"
"github.com/coder/coder/v2/coderd/database/dbmem"
"github.com/coder/coder/v2/coderd/database/dbtestutil"
"github.com/coder/coder/v2/coderd/database/dbtime"
"github.com/coder/coder/v2/coderd/database/pubsub"
"github.com/coder/coder/v2/coderd/externalauth"
Expand DownExpand Up@@ -1708,6 +1709,155 @@ func TestCompleteJob(t *testing.T) {
})
}

func TestInsertWorkspacePresetsAndParameters(t *testing.T) {
t.Parallel()

type testCase struct {
name string
givenPresets []*sdkproto.Preset
}

testCases := []testCase{
{
name: "no presets",
},
{
name: "one preset with no parameters",
givenPresets: []*sdkproto.Preset{
{
Name: "preset1",
},
},
},
{
name: "one preset with multiple parameters",
givenPresets: []*sdkproto.Preset{
{
Name: "preset1",
Parameters: []*sdkproto.PresetParameter{
{
Name: "param1",
Value: "value1",
},
{
Name: "param2",
Value: "value2",
},
},
},
},
},
{
name: "multiple presets with parameters",
givenPresets: []*sdkproto.Preset{
{
Name: "preset1",
Parameters: []*sdkproto.PresetParameter{
{
Name: "param1",
Value: "value1",
},
{
Name: "param2",
Value: "value2",
},
},
},
{
Name: "preset2",
Parameters: []*sdkproto.PresetParameter{
{
Name: "param3",
Value: "value3",
},
{
Name: "param4",
Value: "value4",
},
},
},
},
},
}

for _, c := range testCases {
c := c
t.Run(c.name, func(t *testing.T) {
t.Parallel()

ctx := testutil.Context(t, testutil.WaitLong)
logger := testutil.Logger(t)
db, ps := dbtestutil.NewDB(t)
org := dbgen.Organization(t, db, database.Organization{})
user := dbgen.User(t, db, database.User{})
job := dbgen.ProvisionerJob(t, db, ps, database.ProvisionerJob{
Type: database.ProvisionerJobTypeWorkspaceBuild,
OrganizationID: org.ID,
})
templateVersion := dbgen.TemplateVersion(t, db, database.TemplateVersion{
JobID: job.ID,
OrganizationID: org.ID,
CreatedBy: user.ID,
})

err := provisionerdserver.InsertWorkspacePresetsAndParameters(
ctx,
logger,
db,
job.ID,
templateVersion.ID,
c.givenPresets,
time.Now(),
)
require.NoError(t, err)

gotPresets, err := db.GetPresetsByTemplateVersionID(ctx, templateVersion.ID)
require.NoError(t, err)
require.Len(t, gotPresets, len(c.givenPresets))

for _, givenPreset := range c.givenPresets {
foundMatch := false
for _, gotPreset := range gotPresets {
if givenPreset.Name == gotPreset.Name {
foundMatch = true
break
}
}
require.True(t, foundMatch, "preset %s not found in parameters", givenPreset.Name)
}

gotPresetParameters, err := db.GetPresetParametersByTemplateVersionID(ctx, templateVersion.ID)
require.NoError(t, err)

for _, givenPreset := range c.givenPresets {
for _, givenParameter := range givenPreset.Parameters {
foundMatch := false
for _, gotParameter := range gotPresetParameters {
nameMatches := givenParameter.Name == gotParameter.Name
valueMatches := givenParameter.Value == gotParameter.Value

// ensure that preset parameters are matched to the correct preset:
var gotPreset database.TemplateVersionPreset
for _, preset := range gotPresets {
if preset.ID == gotParameter.TemplateVersionPresetID {
gotPreset = preset
break
}
}
presetMatches := gotPreset.Name == givenPreset.Name

if nameMatches && valueMatches && presetMatches {
foundMatch = true
break
}
}
require.True(t, foundMatch, "preset parameter %s not found in presets", givenParameter.Name)
}
}
})
}
}

func TestInsertWorkspaceResource(t *testing.T) {
t.Parallel()
ctx := context.Background()
Expand Down
1 change: 1 addition & 0 deletionsprovisioner/terraform/executor.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -308,6 +308,7 @@ func (e *executor) plan(ctx, killCtx context.Context, env, vars []string, logr l
Resources: state.Resources,
ExternalAuthProviders: state.ExternalAuthProviders,
Timings: append(e.timings.aggregate(), graphTimings.aggregate()...),
Presets: state.Presets,
}, nil
}

Expand Down
79 changes: 78 additions & 1 deletionprovisioner/terraform/resources.go
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -149,6 +149,7 @@ type resourceMetadataItem struct {
type State struct {
Resources []*proto.Resource
Parameters []*proto.RichParameter
Presets []*proto.Preset
ExternalAuthProviders []*proto.ExternalAuthProviderResource
}

Expand DownExpand Up@@ -176,7 +177,7 @@ func ConvertState(ctx context.Context, modules []*tfjson.StateModule, rawGraph s

// Extra array to preserve the order of rich parameters.
tfResourcesRichParameters := make([]*tfjson.StateResource, 0)

tfResourcesPresets := make([]*tfjson.StateResource, 0)
var findTerraformResources func(mod *tfjson.StateModule)
findTerraformResources = func(mod *tfjson.StateModule) {
for _, module := range mod.ChildModules {
Expand All@@ -186,6 +187,9 @@ func ConvertState(ctx context.Context, modules []*tfjson.StateModule, rawGraph s
if resource.Type == "coder_parameter" {
tfResourcesRichParameters = append(tfResourcesRichParameters, resource)
}
if resource.Type == "coder_workspace_preset" {
tfResourcesPresets = append(tfResourcesPresets, resource)
}

label := convertAddressToLabel(resource.Address)
if tfResourcesByLabel[label] == nil {
Expand DownExpand Up@@ -775,6 +779,78 @@ func ConvertState(ctx context.Context, modules []*tfjson.StateModule, rawGraph s
)
}

var duplicatedPresetNames []string
presets := make([]*proto.Preset, 0)
for _, resource := range tfResourcesPresets {
var preset provider.WorkspacePreset
err = mapstructure.Decode(resource.AttributeValues, &preset)
if err != nil {
return nil, xerrors.Errorf("decode preset attributes: %w", err)
}

var duplicatedPresetParameterNames []string
var nonExistentParameters []string
var presetParameters []*proto.PresetParameter
for name, value := range preset.Parameters {
presetParameter := &proto.PresetParameter{
Name: name,
Value: value,
}

formattedName := fmt.Sprintf("%q", name)
if !slice.Contains(duplicatedPresetParameterNames, formattedName) &&
slice.ContainsCompare(presetParameters, presetParameter, func(a, b *proto.PresetParameter) bool {
return a.Name == b.Name
}) {
duplicatedPresetParameterNames = append(duplicatedPresetParameterNames, formattedName)
}
if !slice.ContainsCompare(parameters, &proto.RichParameter{Name: name}, func(a, b *proto.RichParameter) bool {
return a.Name == b.Name
}) {
nonExistentParameters = append(nonExistentParameters, name)
}

presetParameters = append(presetParameters, presetParameter)
}

if len(duplicatedPresetParameterNames) > 0 {
s := ""
if len(duplicatedPresetParameterNames) == 1 {
s = "s"
}
return nil, xerrors.Errorf(
"coder_workspace_preset parameters must be unique but %s appear%s multiple times", stringutil.JoinWithConjunction(duplicatedPresetParameterNames), s,
)
}

if len(nonExistentParameters) > 0 {
logger.Warn(
ctx,
"coder_workspace_preset defines preset values for at least one parameter that is not defined by the template",
slog.F("parameters", stringutil.JoinWithConjunction(nonExistentParameters)),
)
}

protoPreset := &proto.Preset{
Name: preset.Name,
Parameters: presetParameters,
}
if slice.Contains(duplicatedPresetNames, preset.Name) {
duplicatedPresetNames = append(duplicatedPresetNames, preset.Name)
}
presets = append(presets, protoPreset)
}
if len(duplicatedPresetNames) > 0 {
s := ""
if len(duplicatedPresetNames) == 1 {
s = "s"
}
return nil, xerrors.Errorf(
"coder_workspace_preset names must be unique but %s appear%s multiple times",
stringutil.JoinWithConjunction(duplicatedPresetNames), s,
)
}

// A map is used to ensure we don't have duplicates!
externalAuthProvidersMap := map[string]*proto.ExternalAuthProviderResource{}
for _, tfResources := range tfResourcesByLabel {
Expand DownExpand Up@@ -808,6 +884,7 @@ func ConvertState(ctx context.Context, modules []*tfjson.StateModule, rawGraph s
return &State{
Resources: resources,
Parameters: parameters,
Presets: presets,
ExternalAuthProviders: externalAuthProviders,
}, nil
}
Expand Down
Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp