Skip to content

Commit 7587850

Browse files
authored
feat: import value from legacy variable to build parameter (#6556)
1 parent bc26c4a commit 7587850

24 files changed

+576
-296
lines changed

coderd/apidoc/docs.go

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/apidoc/swagger.json

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/dbfake/databasefake.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2826,6 +2826,7 @@ func (q *fakeQuerier) InsertTemplateVersionParameter(_ context.Context, arg data
28262826
ValidationMax: arg.ValidationMax,
28272827
ValidationMonotonic: arg.ValidationMonotonic,
28282828
Required: arg.Required,
2829+
LegacyVariableName: arg.LegacyVariableName,
28292830
}
28302831
q.templateVersionParameters = append(q.templateVersionParameters, param)
28312832
return param, nil

coderd/database/dump.sql

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
ALTER TABLE template_version_parameters DROP COLUMN legacy_variable_name;
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
ALTER TABLE template_version_parameters ADD COLUMN legacy_variable_name text NOT NULL DEFAULT '';
2+
3+
COMMENT ON COLUMN template_version_parameters.legacy_variable_name IS 'Name of the legacy variable for migration purposes';

coderd/database/models.go

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries.sql.go

Lines changed: 10 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

coderd/database/queries/templateversionparameters.sql

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ INSERT INTO
1414
validation_max,
1515
validation_error,
1616
validation_monotonic,
17-
required
17+
required,
18+
legacy_variable_name
1819
)
1920
VALUES
2021
(
@@ -31,7 +32,8 @@ VALUES
3132
$11,
3233
$12,
3334
$13,
34-
$14
35+
$14,
36+
$15
3537
) RETURNING *;
3638

3739
-- name: GetTemplateVersionParameters :many

coderd/provisionerdserver/provisionerdserver.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -835,6 +835,7 @@ func (server *Server) CompleteJob(ctx context.Context, completed *proto.Complete
835835
ValidationMax: richParameter.ValidationMax,
836836
ValidationMonotonic: richParameter.ValidationMonotonic,
837837
Required: richParameter.Required,
838+
LegacyVariableName: richParameter.LegacyVariableName,
838839
})
839840
if err != nil {
840841
return nil, xerrors.Errorf("insert parameter: %w", err)

coderd/templateversions.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1622,6 +1622,7 @@ func convertTemplateVersionParameter(param database.TemplateVersionParameter) (c
16221622
ValidationError: param.ValidationError,
16231623
ValidationMonotonic: codersdk.ValidationMonotonicOrder(param.ValidationMonotonic),
16241624
Required: param.Required,
1625+
LegacyVariableName: param.LegacyVariableName,
16251626
}, nil
16261627
}
16271628

coderd/workspacebuilds.go

Lines changed: 33 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,39 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
496496
}
497497
apiLastBuildParameters := convertWorkspaceBuildParameters(lastBuildParameters)
498498

499+
legacyParameters, err := api.Database.ParameterValues(ctx, database.ParameterValuesParams{
500+
Scopes: []database.ParameterScope{database.ParameterScopeWorkspace},
501+
ScopeIds: []uuid.UUID{workspace.ID},
502+
})
503+
if err != nil && !xerrors.Is(err, sql.ErrNoRows) {
504+
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
505+
Message: "Error fetching previous legacy parameters.",
506+
Detail: err.Error(),
507+
})
508+
return
509+
}
510+
511+
// Rich parameters migration: include legacy variables to the last build parameters
512+
for _, templateVersionParameter := range templateVersionParameters {
513+
// Check if parameter is defined in previous build
514+
if _, found := findWorkspaceBuildParameter(apiLastBuildParameters, templateVersionParameter.Name); found {
515+
continue
516+
}
517+
518+
// Check if legacy variable is defined
519+
for _, legacyParameter := range legacyParameters {
520+
if legacyParameter.Name != templateVersionParameter.LegacyVariableName {
521+
continue
522+
}
523+
524+
apiLastBuildParameters = append(apiLastBuildParameters, codersdk.WorkspaceBuildParameter{
525+
Name: templateVersionParameter.Name,
526+
Value: legacyParameter.SourceValue,
527+
})
528+
break
529+
}
530+
}
531+
499532
err = codersdk.ValidateWorkspaceBuildParameters(templateVersionParameters, createBuild.RichParameterValues, apiLastBuildParameters)
500533
if err != nil {
501534
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
@@ -525,26 +558,6 @@ func (api *API) postWorkspaceBuilds(rw http.ResponseWriter, r *http.Request) {
525558
}
526559
}
527560

528-
legacyParameters, err := api.Database.ParameterValues(ctx, database.ParameterValuesParams{
529-
Scopes: []database.ParameterScope{database.ParameterScopeWorkspace},
530-
ScopeIds: []uuid.UUID{workspace.ID},
531-
})
532-
if err != nil && !xerrors.Is(err, sql.ErrNoRows) {
533-
httpapi.Write(ctx, rw, http.StatusInternalServerError, codersdk.Response{
534-
Message: "Error fetching previous legacy parameters.",
535-
Detail: err.Error(),
536-
})
537-
return
538-
}
539-
540-
if createBuild.Transition == codersdk.WorkspaceTransitionStart &&
541-
len(legacyParameters) > 0 && len(parameters) > 0 {
542-
httpapi.Write(ctx, rw, http.StatusBadRequest, codersdk.Response{
543-
Message: "Rich parameters can't be used together with legacy parameters.",
544-
})
545-
return
546-
}
547-
548561
var workspaceBuild database.WorkspaceBuild
549562
var provisionerJob database.ProvisionerJob
550563
// This must happen in a transaction to ensure history can be inserted, and

coderd/workspacebuilds_test.go

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -971,3 +971,170 @@ func TestWorkspaceBuildValidateRichParameters(t *testing.T) {
971971
}
972972
})
973973
}
974+
975+
func TestMigrateLegacyToRichParameters(t *testing.T) {
976+
t.Parallel()
977+
978+
client := coderdtest.New(t, &coderdtest.Options{IncludeProvisionerDaemon: true})
979+
user := coderdtest.CreateFirstUser(t, client)
980+
981+
ctx, cancel := context.WithTimeout(context.Background(), testutil.WaitLong)
982+
defer cancel()
983+
984+
// 1. Prepare a template with legacy parameters.
985+
templateVersion := coderdtest.CreateTemplateVersion(t, client, user.OrganizationID, &echo.Responses{
986+
Parse: []*proto.Parse_Response{{
987+
Type: &proto.Parse_Response_Complete{
988+
Complete: &proto.Parse_Complete{
989+
ParameterSchemas: []*proto.ParameterSchema{
990+
{
991+
AllowOverrideSource: true,
992+
Name: "example",
993+
Description: "description 1",
994+
DefaultSource: &proto.ParameterSource{
995+
Scheme: proto.ParameterSource_DATA,
996+
Value: "tomato",
997+
},
998+
DefaultDestination: &proto.ParameterDestination{
999+
Scheme: proto.ParameterDestination_PROVISIONER_VARIABLE,
1000+
},
1001+
},
1002+
},
1003+
},
1004+
},
1005+
}},
1006+
ProvisionApply: echo.ProvisionComplete,
1007+
ProvisionPlan: echo.ProvisionComplete,
1008+
})
1009+
coderdtest.AwaitTemplateVersionJob(t, client, templateVersion.ID)
1010+
template := coderdtest.CreateTemplate(t, client, user.OrganizationID, templateVersion.ID)
1011+
1012+
// Create a workspace
1013+
workspace := coderdtest.CreateWorkspace(t, client, user.OrganizationID, template.ID, func(cwr *codersdk.CreateWorkspaceRequest) {
1014+
cwr.ParameterValues = []codersdk.CreateParameterRequest{
1015+
{
1016+
Name: "example",
1017+
SourceValue: "carrot",
1018+
SourceScheme: codersdk.ParameterSourceSchemeData,
1019+
DestinationScheme: codersdk.ParameterDestinationSchemeEnvironmentVariable,
1020+
},
1021+
}
1022+
})
1023+
workspaceBuild := coderdtest.AwaitWorkspaceBuildJob(t, client, workspace.LatestBuild.ID)
1024+
require.Equal(t, codersdk.WorkspaceStatusRunning, workspaceBuild.Status)
1025+
1026+
// 2. Upload the template with legacy and rich parameters.
1027+
templateWithParameters := &echo.Responses{
1028+
Parse: []*proto.Parse_Response{{
1029+
Type: &proto.Parse_Response_Complete{
1030+
Complete: &proto.Parse_Complete{
1031+
ParameterSchemas: []*proto.ParameterSchema{
1032+
{
1033+
AllowOverrideSource: true,
1034+
Name: "example",
1035+
Description: "description 1",
1036+
DefaultSource: &proto.ParameterSource{
1037+
Scheme: proto.ParameterSource_DATA,
1038+
Value: "tomato",
1039+
},
1040+
DefaultDestination: &proto.ParameterDestination{
1041+
Scheme: proto.ParameterDestination_PROVISIONER_VARIABLE,
1042+
},
1043+
},
1044+
},
1045+
},
1046+
},
1047+
}},
1048+
ProvisionPlan: []*proto.Provision_Response{
1049+
{
1050+
Type: &proto.Provision_Response_Complete{
1051+
Complete: &proto.Provision_Complete{
1052+
Parameters: []*proto.RichParameter{
1053+
{
1054+
Name: "new_example",
1055+
Type: "string",
1056+
Mutable: true,
1057+
Required: true,
1058+
LegacyVariableName: "example",
1059+
},
1060+
},
1061+
},
1062+
},
1063+
},
1064+
},
1065+
ProvisionApply: echo.ProvisionComplete,
1066+
}
1067+
templateVersion = coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, templateWithParameters, template.ID)
1068+
coderdtest.AwaitTemplateVersionJob(t, client, templateVersion.ID)
1069+
1070+
// Check if rich parameters are expected
1071+
richParameters, err := client.TemplateVersionRichParameters(ctx, templateVersion.ID)
1072+
require.NoError(t, err)
1073+
require.Len(t, richParameters, 1)
1074+
require.Equal(t, "new_example", richParameters[0].Name)
1075+
1076+
// Update workspace to use rich parameters and template variables
1077+
workspaceBuild, err = client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{
1078+
TemplateVersionID: templateVersion.ID,
1079+
Transition: codersdk.WorkspaceTransitionStart,
1080+
})
1081+
require.NoError(t, err)
1082+
require.Eventually(t, func() bool {
1083+
workspaceBuild = coderdtest.AwaitWorkspaceBuildJob(t, client, workspaceBuild.ID)
1084+
return codersdk.WorkspaceStatusRunning == workspaceBuild.Status
1085+
}, testutil.WaitLong, testutil.IntervalFast)
1086+
1087+
// Check if variable value has been imported
1088+
buildParameters, err := client.WorkspaceBuildParameters(ctx, workspaceBuild.ID)
1089+
require.NoError(t, err)
1090+
require.Len(t, buildParameters, 1)
1091+
require.Equal(t, "carrot", buildParameters[0].Value)
1092+
1093+
// 3. Upload the template with rich parameters only
1094+
templateWithParameters = &echo.Responses{
1095+
Parse: echo.ParseComplete,
1096+
ProvisionPlan: []*proto.Provision_Response{
1097+
{
1098+
Type: &proto.Provision_Response_Complete{
1099+
Complete: &proto.Provision_Complete{
1100+
Parameters: []*proto.RichParameter{
1101+
{
1102+
Name: "new_example",
1103+
Type: "string",
1104+
Mutable: true,
1105+
Required: true,
1106+
LegacyVariableName: "example",
1107+
},
1108+
},
1109+
},
1110+
},
1111+
},
1112+
},
1113+
ProvisionApply: echo.ProvisionComplete,
1114+
}
1115+
templateVersion = coderdtest.UpdateTemplateVersion(t, client, user.OrganizationID, templateWithParameters, template.ID)
1116+
coderdtest.AwaitTemplateVersionJob(t, client, templateVersion.ID)
1117+
1118+
// Check if rich parameters are expected
1119+
richParameters, err = client.TemplateVersionRichParameters(ctx, templateVersion.ID)
1120+
require.NoError(t, err)
1121+
require.Len(t, richParameters, 1)
1122+
require.Equal(t, "new_example", richParameters[0].Name)
1123+
1124+
// Update workspace to use rich parameters and template variables
1125+
workspaceBuild, err = client.CreateWorkspaceBuild(ctx, workspace.ID, codersdk.CreateWorkspaceBuildRequest{
1126+
TemplateVersionID: templateVersion.ID,
1127+
Transition: codersdk.WorkspaceTransitionStart,
1128+
})
1129+
require.NoError(t, err)
1130+
require.Eventually(t, func() bool {
1131+
workspaceBuild = coderdtest.AwaitWorkspaceBuildJob(t, client, workspaceBuild.ID)
1132+
return codersdk.WorkspaceStatusRunning == workspaceBuild.Status
1133+
}, testutil.WaitLong, testutil.IntervalFast)
1134+
1135+
// Check if build parameters have been pulled from last build
1136+
buildParameters, err = client.WorkspaceBuildParameters(ctx, workspaceBuild.ID)
1137+
require.NoError(t, err)
1138+
require.Len(t, buildParameters, 1)
1139+
require.Equal(t, "carrot", buildParameters[0].Value)
1140+
}

0 commit comments

Comments
 (0)