Skip to content
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Skip component if metadata.enabled is set to false #756

Merged
merged 18 commits into from
Nov 8, 2024
Merged
Show file tree
Hide file tree
Changes from 16 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
5 changes: 5 additions & 0 deletions internal/exec/helmfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,11 @@ func ExecuteHelmfile(info schema.ConfigAndStacksInfo) error {
return errors.New("stack must be specified")
}

if !info.ComponentIsEnabled {
u.LogInfo(cliConfig, fmt.Sprintf("component '%s' is not enabled and skipped", info.ComponentFromArg))
return nil
}

err = checkHelmfileConfig(cliConfig)
if err != nil {
return err
Expand Down
12 changes: 9 additions & 3 deletions internal/exec/stack_utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,13 +54,14 @@ func BuildTerraformWorkspace(cliConfig schema.CliConfiguration, configAndStacksI
return strings.Replace(workspace, "/", "-", -1), nil
}

// ProcessComponentMetadata processes component metadata and returns a base component (if any) and whether the component is real or abstract
// ProcessComponentMetadata processes component metadata and returns a base component (if any) and whether the component is real or abstract and whether the component is disabled or not
func ProcessComponentMetadata(
component string,
componentSection map[string]any,
) (map[string]any, string, bool) {
) (map[string]any, string, bool, bool) {
baseComponentName := ""
componentIsAbstract := false
componentIsEnabled := true
pkbhowmick marked this conversation as resolved.
Show resolved Hide resolved
var componentMetadata map[string]any

// Find base component in the `component` attribute
Expand All @@ -75,6 +76,11 @@ func ProcessComponentMetadata(
componentIsAbstract = true
}
}
if enabledValue, exists := componentMetadata["enabled"]; exists {
if enabled, ok := enabledValue.(bool); ok && !enabled {
componentIsEnabled = false
}
}
// Find base component in the `metadata.component` attribute
// `metadata.component` overrides `component`
if componentMetadataComponent, componentMetadataComponentExists := componentMetadata[cfg.ComponentSectionName].(string); componentMetadataComponentExists {
Expand All @@ -87,7 +93,7 @@ func ProcessComponentMetadata(
baseComponentName = ""
}

return componentMetadata, baseComponentName, componentIsAbstract
return componentMetadata, baseComponentName, componentIsAbstract, componentIsEnabled
}

// BuildDependentStackNameFromDependsOnLegacy builds the dependent stack name from "settings.spacelift.depends_on" config
Expand Down
5 changes: 5 additions & 0 deletions internal/exec/terraform.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,11 @@ func ExecuteTerraform(info schema.ConfigAndStacksInfo) error {
return errors.New("stack must be specified")
}

if !info.ComponentIsEnabled {
u.LogInfo(cliConfig, fmt.Sprintf("component '%s' is not enabled and skipped", info.ComponentFromArg))
return nil
}

err = checkTerraformConfig(cliConfig)
if err != nil {
return err
Expand Down
8 changes: 5 additions & 3 deletions internal/exec/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,8 @@ func ProcessComponentConfig(
}

// Process component metadata and find a base component (if any) and whether the component is real or abstract
componentMetadata, baseComponentName, componentIsAbstract := ProcessComponentMetadata(component, componentSection)
componentMetadata, baseComponentName, componentIsAbstract, componentIsEnabled := ProcessComponentMetadata(component, componentSection)
configAndStacksInfo.ComponentIsEnabled = componentIsEnabled

// Remove the ENV vars that are set to `null` in the `env` section.
// Setting an ENV var to `null` in stack config has the effect of unsetting it
Expand Down Expand Up @@ -391,7 +392,7 @@ func ProcessStacks(
}
}

if foundStackCount == 0 {
if foundStackCount == 0 && configAndStacksInfo.ComponentIsEnabled {
cliConfigYaml := ""

if cliConfig.Logs.Level == u.LogLevelTrace {
Expand Down Expand Up @@ -573,8 +574,9 @@ func ProcessStacks(
configAndStacksInfo.ComponentEnvList = u.ConvertEnvVars(configAndStacksInfo.ComponentEnvSection)

// Process component metadata
_, baseComponentName, _ := ProcessComponentMetadata(configAndStacksInfo.ComponentFromArg, configAndStacksInfo.ComponentSection)
_, baseComponentName, _, componentIsEnabled := ProcessComponentMetadata(configAndStacksInfo.ComponentFromArg, configAndStacksInfo.ComponentSection)
configAndStacksInfo.BaseComponentPath = baseComponentName
configAndStacksInfo.ComponentIsEnabled = componentIsEnabled

// Process component path and name
configAndStacksInfo.ComponentFolderPrefix = ""
Expand Down
1 change: 1 addition & 0 deletions pkg/schema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ type ConfigAndStacksInfo struct {
ComponentImportsSection []string
NeedHelp bool
ComponentIsAbstract bool
ComponentIsEnabled bool
ComponentMetadataSection AtmosSectionMapType
TerraformWorkspace string
JsonSchemaDir string
Expand Down
4 changes: 2 additions & 2 deletions pkg/spacelift/spacelift_stack_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,9 @@ func TransformStackConfigToSpaceliftStacks(
}

// Process component metadata and find a base component (if any) and whether the component is real or abstract
componentMetadata, baseComponentName, componentIsAbstract := e.ProcessComponentMetadata(component, componentMap)
componentMetadata, baseComponentName, componentIsAbstract, componentIsEnabled := e.ProcessComponentMetadata(component, componentMap)

if componentIsAbstract {
if componentIsAbstract || !componentIsEnabled {
continue
}

Expand Down
22 changes: 22 additions & 0 deletions website/docs/core-concepts/stacks/define-components.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -212,3 +212,25 @@ There are two types of components:
<dt>`abstract`</dt>
<dd>An `abstract` component is more like a blueprint. It can’t be deployed on its own. Instead, it’s a base configuration that needs to be extended or inherited by other components. This is similar to an ["abstract base classes"](https://en.wikipedia.org/wiki/Abstract_type) in programming—it defines reusable configurations, but it’s not complete enough to be deployed directly.</dd>
</dl>

### Disabling Components with `metadata.enabled`

The `metadata.enabled` parameter controls whether a component is included in deployment. By default, components are enabled. Setting `metadata.enabled` to `false` skips the component entirely—no workspace is created, and no Terraform commands are executed. Disabling a component does not cause deletion. It just signals that it's no longer managed by Atmos.

<Note>
This should not be confused with [Cloud Posse's conventions and best practices](/best-practices/terraform/) of having modules and components define a [Terraform input named `enabled`](/best-practices/terraform/#use-feature-flags-list-or-map-inputs-for-optional-functionality). This is a general convention and `vars.enabled` is not a special variable. Atmos does not treat it differently from any other variable.
</Note>

**Example**:
```yaml
# Disable a component in a specific environment
components:
terraform:
vpc:
metadata:
type: real
enabled: false
vars:
name: primary-vpc
```
Using the `metadata.enabled` flag makes it easy to ensure that only the intended components are active in each environment.
Loading