Skip to content

Commit 398b999

Browse files
authored
chore: pass previous values into terraform apply (#17696)
Pass previous workspace build parameter values into the terraform `plan/apply`. Enforces monotonicity in terraform as well as `coderd`.
1 parent d0ab91c commit 398b999

File tree

9 files changed

+515
-440
lines changed

9 files changed

+515
-440
lines changed

coderd/provisionerdserver/provisionerdserver.go

Lines changed: 31 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,30 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo
549549
return nil, failJob(fmt.Sprintf("convert workspace transition: %s", err))
550550
}
551551

552+
// A previous workspace build exists
553+
var lastWorkspaceBuildParameters []database.WorkspaceBuildParameter
554+
if workspaceBuild.BuildNumber > 1 {
555+
// TODO: Should we fetch the last build that succeeded? This fetches the
556+
// previous build regardless of the status of the build.
557+
buildNum := workspaceBuild.BuildNumber - 1
558+
previous, err := s.Database.GetWorkspaceBuildByWorkspaceIDAndBuildNumber(ctx, database.GetWorkspaceBuildByWorkspaceIDAndBuildNumberParams{
559+
WorkspaceID: workspaceBuild.WorkspaceID,
560+
BuildNumber: buildNum,
561+
})
562+
563+
// If the error is ErrNoRows, then assume previous values are empty.
564+
if err != nil && !xerrors.Is(err, sql.ErrNoRows) {
565+
return nil, xerrors.Errorf("get last build with number=%d: %w", buildNum, err)
566+
}
567+
568+
if err == nil {
569+
lastWorkspaceBuildParameters, err = s.Database.GetWorkspaceBuildParameters(ctx, previous.ID)
570+
if err != nil {
571+
return nil, xerrors.Errorf("get last build parameters %q: %w", previous.ID, err)
572+
}
573+
}
574+
}
575+
552576
workspaceBuildParameters, err := s.Database.GetWorkspaceBuildParameters(ctx, workspaceBuild.ID)
553577
if err != nil {
554578
return nil, failJob(fmt.Sprintf("get workspace build parameters: %s", err))
@@ -625,12 +649,13 @@ func (s *server) acquireProtoJob(ctx context.Context, job database.ProvisionerJo
625649

626650
protoJob.Type = &proto.AcquiredJob_WorkspaceBuild_{
627651
WorkspaceBuild: &proto.AcquiredJob_WorkspaceBuild{
628-
WorkspaceBuildId: workspaceBuild.ID.String(),
629-
WorkspaceName: workspace.Name,
630-
State: workspaceBuild.ProvisionerState,
631-
RichParameterValues: convertRichParameterValues(workspaceBuildParameters),
632-
VariableValues: asVariableValues(templateVariables),
633-
ExternalAuthProviders: externalAuthProviders,
652+
WorkspaceBuildId: workspaceBuild.ID.String(),
653+
WorkspaceName: workspace.Name,
654+
State: workspaceBuild.ProvisionerState,
655+
RichParameterValues: convertRichParameterValues(workspaceBuildParameters),
656+
PreviousParameterValues: convertRichParameterValues(lastWorkspaceBuildParameters),
657+
VariableValues: asVariableValues(templateVariables),
658+
ExternalAuthProviders: externalAuthProviders,
634659
Metadata: &sdkproto.Metadata{
635660
CoderUrl: s.AccessURL.String(),
636661
WorkspaceTransition: transition,

provisioner/terraform/provision.go

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,7 @@ func (s *server) Plan(
152152

153153
s.logger.Debug(ctx, "ran initialization")
154154

155-
env, err := provisionEnv(sess.Config, request.Metadata, request.RichParameterValues, request.ExternalAuthProviders)
155+
env, err := provisionEnv(sess.Config, request.Metadata, request.PreviousParameterValues, request.RichParameterValues, request.ExternalAuthProviders)
156156
if err != nil {
157157
return provisionersdk.PlanErrorf("setup env: %s", err)
158158
}
@@ -205,7 +205,7 @@ func (s *server) Apply(
205205

206206
// Earlier in the session, Plan() will have written the state file and the plan file.
207207
statefilePath := getStateFilePath(sess.WorkDirectory)
208-
env, err := provisionEnv(sess.Config, request.Metadata, nil, nil)
208+
env, err := provisionEnv(sess.Config, request.Metadata, nil, nil, nil)
209209
if err != nil {
210210
return provisionersdk.ApplyErrorf("provision env: %s", err)
211211
}
@@ -236,7 +236,7 @@ func planVars(plan *proto.PlanRequest) ([]string, error) {
236236

237237
func provisionEnv(
238238
config *proto.Config, metadata *proto.Metadata,
239-
richParams []*proto.RichParameterValue, externalAuth []*proto.ExternalAuthProvider,
239+
previousParams, richParams []*proto.RichParameterValue, externalAuth []*proto.ExternalAuthProvider,
240240
) ([]string, error) {
241241
env := safeEnviron()
242242
ownerGroups, err := json.Marshal(metadata.GetWorkspaceOwnerGroups())
@@ -280,6 +280,9 @@ func provisionEnv(
280280
for key, value := range provisionersdk.AgentScriptEnv() {
281281
env = append(env, key+"="+value)
282282
}
283+
for _, param := range previousParams {
284+
env = append(env, provider.ParameterEnvironmentVariablePrevious(param.Name)+"="+param.Value)
285+
}
283286
for _, param := range richParams {
284287
env = append(env, provider.ParameterEnvironmentVariable(param.Name)+"="+param.Value)
285288
}

provisionerd/proto/provisionerd.pb.go

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

provisionerd/proto/provisionerd.proto

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,10 @@ message AcquiredJob {
2222
provisioner.Metadata metadata = 7;
2323
bytes state = 8;
2424
string log_level = 9;
25+
// previous_parameter_values is used to pass the values of the previous
26+
// workspace build. Omit these values if the workspace is being created
27+
// for the first time.
28+
repeated provisioner.RichParameterValue previous_parameter_values = 10;
2529
}
2630
message TemplateImport {
2731
provisioner.Metadata metadata = 1;

provisionerd/proto/version.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ import "github.com/coder/coder/v2/apiversion"
1616
// API v1.5:
1717
// - Add new field named `prebuilt_workspace_build_stage` enum in the Metadata message.
1818
// - Add `plan` and `module_files` fields to `CompletedJob.TemplateImport`.
19+
// - Add previous parameter values to 'WorkspaceBuild' jobs. Provisioner passes
20+
// the previous values for the `terraform apply` to enforce monotonicity
21+
// in the terraform provider.
1922
const (
2023
CurrentMajor = 1
2124
CurrentMinor = 5

provisionerd/runner/runner.go

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -691,7 +691,9 @@ func (r *Runner) runTemplateImportProvisionWithRichParameters(
691691
err := r.session.Send(&sdkproto.Request{Type: &sdkproto.Request_Plan{Plan: &sdkproto.PlanRequest{
692692
Metadata: metadata,
693693
RichParameterValues: richParameterValues,
694-
VariableValues: variableValues,
694+
// Template import has no previous values
695+
PreviousParameterValues: make([]*sdkproto.RichParameterValue, 0),
696+
VariableValues: variableValues,
695697
}}})
696698
if err != nil {
697699
return nil, xerrors.Errorf("start provision: %w", err)
@@ -960,10 +962,11 @@ func (r *Runner) runWorkspaceBuild(ctx context.Context) (*proto.CompletedJob, *p
960962
resp, failed := r.buildWorkspace(ctx, "Planning infrastructure", &sdkproto.Request{
961963
Type: &sdkproto.Request_Plan{
962964
Plan: &sdkproto.PlanRequest{
963-
Metadata: r.job.GetWorkspaceBuild().Metadata,
964-
RichParameterValues: r.job.GetWorkspaceBuild().RichParameterValues,
965-
VariableValues: r.job.GetWorkspaceBuild().VariableValues,
966-
ExternalAuthProviders: r.job.GetWorkspaceBuild().ExternalAuthProviders,
965+
Metadata: r.job.GetWorkspaceBuild().Metadata,
966+
RichParameterValues: r.job.GetWorkspaceBuild().RichParameterValues,
967+
PreviousParameterValues: r.job.GetWorkspaceBuild().PreviousParameterValues,
968+
VariableValues: r.job.GetWorkspaceBuild().VariableValues,
969+
ExternalAuthProviders: r.job.GetWorkspaceBuild().ExternalAuthProviders,
967970
},
968971
},
969972
})

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy