Abstract Component
The Abstract Component Design Pattern describes the mechanism of deriving Atmos components from one or more abstract base components ( blueprints), allowing reusing the base components' configurations and prohibiting the abstract base component from being provisioned.
Atmos supports two types of components:
-
real
- is a "concrete" component instance that can be provisioned -
abstract
- a component configuration, which cannot be instantiated directly. The concept is borrowed from "abstract base classes" of Object-Oriented Programming
The type of component is expressed in the metadata.type
parameter of a given component configuration.
For more details, refer to:
Use-cases
Use the Abstract Component pattern when:
-
You need to have reusable base components that serve as blueprints for the derived Atmos components
-
You need to prevent the abstract base components from being provisioned
-
You need to keep the configuration of all components DRY
Benefits
The Abstract Component pattern provides the following benefits:
-
Allows creating very DRY and reusable configurations that are built upon existing abstract base components (blueprints)
-
Prevents the abstract base components from being provisioned
-
The
metadata.type: abstract
attribute serves as a guard against accidentally deploying the components that are not meant to be deployed
Example
The following example shows the Atmos stack and component configurations to provision the vpc
component into
a multi-account, multi-region environment. In the catalog/vpc
folder, we have the defaults.yaml
manifest that configures the base abstract
component vpc/defaults
to be inherited by all the derived VPC components in all stacks. By being abstract, the base component vpc/defaults
is prohibited from being provisioned.
│ # Centralized stacks configuration (stack manifests)
├── stacks
│ ├── catalog # component-specific defaults
│ │ └── vpc
│ │ └── defaults.yaml
│ ├── mixins
│ │ ├── tenant # tenant-specific defaults
│ │ │ └── plat.yaml
│ │ ├── region # region-specific defaults
│ │ │ ├── us-east-2.yaml
│ │ │ └── us-west-2.yaml
│ │ └── stage # stage-specific defaults
│ │ ├── dev.yaml
│ │ ├── staging.yaml
│ │ └── prod.yaml
│ └── orgs # Organizations
│ └── acme
│ ├── _defaults.yaml
│ └── plat # 'plat' represents the "Platform" OU (a.k.a tenant)
│ ├─ ─ _defaults.yaml
│ ├── dev
│ │ ├── _defaults.yaml
│ │ ├── us-east-2.yaml
│ │ └── us-west-2.yaml
│ ├── staging
│ │ ├── _defaults.yaml
│ │ ├── us-east-2.yaml
│ │ └── us-west-2.yaml
│ └── prod
│ ├── _defaults.yaml
│ ├── us-east-2.yaml
│ └── us-west-2.yaml
│ # Centralized components configuration
└── components
└── terraform # Terraform components (a.k.a Terraform "root" modules)
└── vpc
Add the following minimal configuration to atmos.yaml
CLI config file :
components:
terraform:
base_path: "components/terraform"
stacks:
base_path: "stacks"
name_pattern: "{tenant}-{environment}-{stage}"
included_paths:
# Tell Atmos to search for the top-level stack manifests in the `orgs` folder and its sub-folders
- "orgs/**/*"
excluded_paths:
# Tell Atmos that the `defaults` folder and all sub-folders don't contain top-level stack manifests
- "defaults/**/*"
schemas:
jsonschema:
base_path: "stacks/schemas/jsonschema"
opa:
base_path: "stacks/schemas/opa"
atmos:
manifest: "stacks/schemas/atmos/atmos-manifest/1.0/atmos-manifest.json"
Add the following configuration for the abstract base component vpc/defaults
to the stacks/catalog/vpc/defaults.yaml
manifest:
components:
terraform:
vpc/defaults:
metadata:
# Abstract components can't be provisioned, they just serve as base components (blueprints) for real components
# `metadata.type` can be `abstract` or `real`
# `real` is the default and can be omitted
type: abstract
settings:
# All validation steps must succeed to allow the component to be provisioned
validation:
validate-vpc-component-with-jsonschema:
schema_type: jsonschema
schema_path: "vpc/validate-vpc-component.json"
description: Validate 'vpc' component variables using JSON Schema
check-vpc-component-config-with-opa-policy:
schema_type: opa
schema_path: "vpc/validate-vpc-component.rego"
module_paths:
- "catalog/constants"
description: Check 'vpc' component configuration using OPA policy
vars:
enabled: true
name: "common"
max_subnet_count: 3
map_public_ip_on_launch: true
assign_generated_ipv6_cidr_block: false
nat_gateway_enabled: true
nat_instance_enabled: false
vpc_flow_logs_enabled: true
vpc_flow_logs_traffic_type: "ALL"
vpc_flow_logs_log_destination_type: "s3"
nat_eip_aws_shield_protection_enabled: false
subnet_type_tag_key: "acme/subnet/type"
ipv4_primary_cidr_block: 10.0.0.0/18
Configure the vpc
Atmos component in the stacks/orgs/acme/plat/prod/us-east-2.yaml
top-level stack. The vpc
component inherits from
the vpc/defaults
abstract base component:
import:
import:
- orgs/acme/plat/prod/_defaults
- mixins/region/us-east-2
# Import the `vpc/defaults` component from the `catalog/vpc/defaults.yaml` manifest
- catalog/vpc/defaults
components:
terraform:
# Atmos component `vpc`
vpc:
metadata:
# `metadata.type` can be `abstract` or `real`
# `real` is the default and can be omitted
# Real components can be provisioned
type: real
# Point to the Terraform component in `components/terraform/vpc`
component: vpc
# Inherit from the `vpc/defaults` Atmos base component
# This is Single Inheritance: the Atmos component inherits from one base Atmos component
inherits:
- vpc/defaults
# Define/override variables specific to this `vpc` component
vars:
name: my-vpc
vpc_flow_logs_enabled: false
ipv4_primary_cidr_block: 10.9.0.0/18
To provision the vpc
component into the plat-ue2-prod
top-level stack, execute the following command:
atmos terraform apply vpc -s plat-ue2-prod
If you try to execute the following commands to provision the vpc/defaults
abstract base component:
atmos terraform plan vpc/defaults -s plat-ue2-prod
atmos terraform apply vpc/defaults -s plat-ue2-prod
the following error will be thrown:
abstract component 'vpc/defaults' cannot be provisioned since it's explicitly prohibited from
being deployed by 'metadata.type: abstract' attribute
Related Patterns
- Component Inheritance
- Multiple Component Instances
- Component Catalog
- Component Catalog with Mixins
- Component Catalog Template
- Inline Component Configuration
- Inline Component Customization