Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
21 changes: 15 additions & 6 deletions api/v1alpha1/blueprint_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ type TerraformComponent struct {
// Destroy determines if the component should be destroyed during down operations.
// Defaults to true if not specified.
Destroy *bool `yaml:"destroy,omitempty"`

// Parallelism limits the number of concurrent operations as Terraform walks the graph.
// This corresponds to the -parallelism flag in terraform apply/destroy commands.
Parallelism *int `yaml:"parallelism,omitempty"`
}

// Kustomization defines a kustomization config in a blueprint.
Expand Down Expand Up @@ -241,12 +245,13 @@ func (b *Blueprint) DeepCopy() *Blueprint {
dependsOnCopy := append([]string{}, component.DependsOn...)

terraformComponentsCopy[i] = TerraformComponent{
Source: component.Source,
Path: component.Path,
FullPath: component.FullPath,
DependsOn: dependsOnCopy,
Values: valuesCopy,
Destroy: component.Destroy,
Source: component.Source,
Path: component.Path,
FullPath: component.FullPath,
DependsOn: dependsOnCopy,
Values: valuesCopy,
Destroy: component.Destroy,
Parallelism: component.Parallelism,
}
}

Expand Down Expand Up @@ -355,6 +360,10 @@ func (b *Blueprint) Merge(overlay *Blueprint) {
mergedComponent.Destroy = overlayComponent.Destroy
}

if overlayComponent.Parallelism != nil {
mergedComponent.Parallelism = overlayComponent.Parallelism
}

b.TerraformComponents = append(b.TerraformComponents, mergedComponent)
} else {
b.TerraformComponents = append(b.TerraformComponents, overlayComponent)
Expand Down
77 changes: 77 additions & 0 deletions api/v1alpha1/blueprint_types_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -408,6 +408,83 @@ func TestBlueprint_Merge(t *testing.T) {
}
})

t.Run("ParallelismFieldMerge", func(t *testing.T) {
tests := []struct {
name string
dst *int
overlay *int
expected *int
}{
{
name: "BothNil",
dst: nil,
overlay: nil,
expected: nil,
},
{
name: "DstNilOverlaySet",
dst: nil,
overlay: ptrInt(5),
expected: ptrInt(5),
},
{
name: "DstSetOverlayNil",
dst: ptrInt(10),
overlay: nil,
expected: ptrInt(10),
},
{
name: "BothSet",
dst: ptrInt(10),
overlay: ptrInt(5),
expected: ptrInt(5),
},
}

for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
dst := &Blueprint{
TerraformComponents: []TerraformComponent{
{
Source: "source1",
Path: "module/path1",
Parallelism: tt.dst,
},
},
}

overlay := &Blueprint{
TerraformComponents: []TerraformComponent{
{
Source: "source1",
Path: "module/path1",
Parallelism: tt.overlay,
},
},
}

dst.Merge(overlay)

if len(dst.TerraformComponents) != 1 {
t.Fatalf("Expected 1 TerraformComponent, but got %d", len(dst.TerraformComponents))
}

component := dst.TerraformComponents[0]
if tt.expected == nil {
if component.Parallelism != nil {
t.Errorf("Expected Parallelism to be nil, but got %v", component.Parallelism)
}
} else {
if component.Parallelism == nil {
t.Errorf("Expected Parallelism to be %v, but got nil", *tt.expected)
} else if *component.Parallelism != *tt.expected {
t.Errorf("Expected Parallelism to be %v, but got %v", *tt.expected, *component.Parallelism)
}
}
})
}
})

t.Run("OverlayComponentWithDifferentSource", func(t *testing.T) {
base := &Blueprint{
TerraformComponents: []TerraformComponent{{Path: "mod", Source: "A"}},
Expand Down
4 changes: 4 additions & 0 deletions api/v1alpha1/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,7 @@ func ptrString(s string) *string {
func ptrBool(b bool) *bool {
return &b
}

func ptrInt(i int) *int {
return &i
}
2 changes: 2 additions & 0 deletions docs/reference/blueprint.md
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ terraform:

# A Terraform module defined within the current blueprint source
- path: apps/my-infra
parallelism: 5
```

| Field | Type | Description |
Expand All @@ -122,6 +123,7 @@ terraform:
| `path` | `string` | Path of the Terraform module relative to the `terraform/` folder. |
| `values` | `map[string]any` | Configuration values for the module. |
| `variables`| `map[string]TerraformVariable` | Input variables for the module. |
| `parallelism`| `int` | Limits the number of concurrent operations as Terraform walks the graph. Corresponds to the `-parallelism` flag. |

### Kustomization
For more information on Flux Kustomizations, which are sets of resources and configurations applied to a Kubernetes cluster, visit [Flux Kustomizations Documentation](https://fluxcd.io/flux/components/kustomize/kustomizations/). Most parameters are not necessary to define.
Expand Down
28 changes: 21 additions & 7 deletions pkg/env/terraform_env.go
Original file line number Diff line number Diff line change
Expand Up @@ -133,9 +133,9 @@ func (e *TerraformEnvPrinter) Print() error {
return e.BaseEnvPrinter.Print(envVars)
}

// GenerateTerraformArgs constructs Terraform CLI argument lists and environment variables for the specified project and module paths.
// It resolves configuration root, locates relevant tfvars files, generates backend configuration arguments, and assembles
// all required CLI and environment variable values for Terraform operations. Returns a TerraformArgs struct or error.
// GenerateTerraformArgs constructs Terraform CLI arguments and environment variables for given project and module paths.
// Resolves config root, locates tfvars files, generates backend config args, and assembles all CLI/env values needed
// for Terraform operations. Returns a TerraformArgs struct or error.
func (e *TerraformEnvPrinter) GenerateTerraformArgs(projectPath, modulePath string) (*TerraformArgs, error) {
configRoot, err := e.configHandler.GetConfigRoot()
if err != nil {
Expand Down Expand Up @@ -182,8 +182,7 @@ func (e *TerraformEnvPrinter) GenerateTerraformArgs(projectPath, modulePath stri
planArgs := []string{fmt.Sprintf("-out=%s", tfPlanPath)}
planArgs = append(planArgs, varFileArgs...)

applyArgs := []string{tfPlanPath}

applyArgs := []string{}
refreshArgs := []string{}
refreshArgs = append(refreshArgs, varFileArgs...)

Expand All @@ -193,14 +192,29 @@ func (e *TerraformEnvPrinter) GenerateTerraformArgs(projectPath, modulePath stri
destroyArgs := []string{"-auto-approve"}
destroyArgs = append(destroyArgs, varFileArgs...)

var parallelismArg string
if e.blueprintHandler != nil {
components := e.blueprintHandler.GetTerraformComponents()
for _, component := range components {
if component.Path == projectPath && component.Parallelism != nil {
parallelismArg = fmt.Sprintf(" -parallelism=%d", *component.Parallelism)
applyArgs = append(applyArgs, fmt.Sprintf("-parallelism=%d", *component.Parallelism))
destroyArgs = append(destroyArgs, fmt.Sprintf("-parallelism=%d", *component.Parallelism))
break
}
}
}

applyArgs = append(applyArgs, tfPlanPath)

terraformVars := make(map[string]string)
terraformVars["TF_DATA_DIR"] = strings.TrimSpace(tfDataDir)
terraformVars["TF_CLI_ARGS_init"] = strings.TrimSpace(fmt.Sprintf("-backend=true -force-copy %s", strings.Join(backendConfigArgsForEnv, " ")))
terraformVars["TF_CLI_ARGS_plan"] = strings.TrimSpace(fmt.Sprintf("-out=\"%s\" %s", tfPlanPath, strings.Join(varFileArgsForEnv, " ")))
terraformVars["TF_CLI_ARGS_apply"] = strings.TrimSpace(fmt.Sprintf("\"%s\"", tfPlanPath))
terraformVars["TF_CLI_ARGS_apply"] = strings.TrimSpace(fmt.Sprintf("\"%s\"%s", tfPlanPath, parallelismArg))
terraformVars["TF_CLI_ARGS_refresh"] = strings.TrimSpace(strings.Join(varFileArgsForEnv, " "))
terraformVars["TF_CLI_ARGS_import"] = strings.TrimSpace(strings.Join(varFileArgsForEnv, " "))
terraformVars["TF_CLI_ARGS_destroy"] = strings.TrimSpace(strings.Join(varFileArgsForEnv, " "))
terraformVars["TF_CLI_ARGS_destroy"] = strings.TrimSpace(fmt.Sprintf("%s%s", strings.Join(varFileArgsForEnv, " "), parallelismArg))
terraformVars["TF_VAR_context_path"] = strings.TrimSpace(filepath.ToSlash(configRoot))
terraformVars["TF_VAR_context_id"] = strings.TrimSpace(e.configHandler.GetString("id", ""))

Expand Down
Loading
Loading