Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ aws-assumed-role/
*.iml
.direnv
.envrc
.cache

# Compiled and auto-generated files
# Note that the leading "**/" appears necessary for Docker even if not for Git
Expand Down
2 changes: 1 addition & 1 deletion README.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ description: |-
cluster_size: 0 # serverless
scaling_configuration:
- auto_pause: true
max_capacity: 5
max_capacity: 4
min_capacity: 2
seconds_until_auto_pause: 300
timeout_action: null
Expand Down
2 changes: 1 addition & 1 deletion src/cluster-regional.tf
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ module "aurora_postgres_cluster" {
publicly_accessible = var.publicly_accessible
db_port = var.database_port
vpc_id = local.vpc_id
subnets = local.private_subnet_ids
subnets = var.publicly_accessible ? local.public_subnet_ids : local.private_subnet_ids
zone_id = local.zone_id
cluster_dns_name = local.cluster_dns_name
reader_dns_name = local.reader_dns_name
Expand Down
1 change: 1 addition & 0 deletions src/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ locals {

vpc_id = module.vpc.outputs.vpc_id
private_subnet_ids = module.vpc.outputs.private_subnet_ids
public_subnet_ids = module.vpc.outputs.public_subnet_ids

eks_security_group_enabled = local.enabled && var.eks_security_group_enabled
allowed_eks_security_groups = [
Expand Down
8 changes: 4 additions & 4 deletions src/remote-state.tf
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module "vpc" {
source = "cloudposse/stack-config/yaml//modules/remote-state"
version = "1.5.0"
version = "1.8.0"

component = var.vpc_component_name

Expand All @@ -9,7 +9,7 @@ module "vpc" {

module "vpc_ingress" {
source = "cloudposse/stack-config/yaml//modules/remote-state"
version = "1.5.0"
version = "1.8.0"

for_each = {
for i, account in var.allow_ingress_from_vpc_accounts :
Expand All @@ -27,7 +27,7 @@ module "vpc_ingress" {

module "eks" {
source = "cloudposse/stack-config/yaml//modules/remote-state"
version = "1.5.0"
version = "1.8.0"

for_each = local.eks_security_group_enabled ? var.eks_component_names : toset([])
component = each.value
Expand All @@ -38,7 +38,7 @@ module "eks" {

module "dns_gbl_delegated" {
source = "cloudposse/stack-config/yaml//modules/remote-state"
version = "1.5.0"
version = "1.8.0"

component = "dns-delegated"
environment = var.dns_gbl_delegated_environment_name
Expand Down
4 changes: 4 additions & 0 deletions test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
state/
.cache
test/test-suite.json
.atmos
196 changes: 196 additions & 0 deletions test/component_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
package test

import (
"fmt"
"strings"
"testing"

"github.com/cloudposse/test-helpers/pkg/atmos"
helper "github.com/cloudposse/test-helpers/pkg/atmos/component-helper"
"github.com/gruntwork-io/terratest/modules/aws"
"github.com/stretchr/testify/assert"
"github.com/gruntwork-io/terratest/modules/random"
)

type ComponentSuite struct {
helper.TestSuite
}

func (s *ComponentSuite) TestBasic() {
const component = "aurora-postgres/basic"
const stack = "default-test"
const awsRegion = "us-east-2"

defer s.DestroyAtmosComponent(s.T(), component, stack, nil)
inputs := map[string]interface{}{
"name": "db",
"database_name": "postgres",
"admin_user": "postgres",
"database_port": 5432,
"publicly_accessible": true,
"allowed_cidr_blocks": []string{"0.0.0.0/0"},
}
componentInstance, _ := s.DeployAtmosComponent(s.T(), component, stack, &inputs)
assert.NotNil(s.T(), componentInstance)

databaseName := atmos.Output(s.T(), componentInstance, "database_name")
assert.Equal(s.T(), "postgres", databaseName)

adminUsername := atmos.Output(s.T(), componentInstance, "admin_username")
assert.Equal(s.T(), "postgres", adminUsername)

delegatedDnsOptions := s.GetAtmosOptions("dns-delegated", stack, nil)
delegatedDomainName := atmos.Output(s.T(), delegatedDnsOptions, "default_domain_name")
delegatedDomainNZoneId := atmos.Output(s.T(), delegatedDnsOptions, "default_dns_zone_id")

masterHostname := atmos.Output(s.T(), componentInstance, "master_hostname")
expectedMasterHostname := fmt.Sprintf("%s-%s-writer.%s", inputs["name"], componentInstance.Vars["cluster_name"], delegatedDomainName)
assert.Equal(s.T(), expectedMasterHostname, masterHostname)

replicasHostname := atmos.Output(s.T(), componentInstance, "replicas_hostname")
expectedReplicasHostname := fmt.Sprintf("%s-%s-reader.%s", inputs["name"], componentInstance.Vars["cluster_name"], delegatedDomainName)
assert.Equal(s.T(), expectedReplicasHostname, replicasHostname)

ssmKeyPaths := atmos.OutputList(s.T(), componentInstance, "ssm_key_paths")
assert.Equal(s.T(), 7, len(ssmKeyPaths))

kmsKeyArn := atmos.Output(s.T(), componentInstance, "kms_key_arn")
assert.NotEmpty(s.T(), kmsKeyArn)

allowedSecurityGroups := atmos.OutputList(s.T(), componentInstance, "allowed_security_groups")
assert.Equal(s.T(), 0, len(allowedSecurityGroups))

clusterIdentifier := atmos.Output(s.T(), componentInstance, "cluster_identifier")

configMap := map[string]interface{}{}
atmos.OutputStruct(s.T(), componentInstance, "config_map", &configMap)

assert.Equal(s.T(), clusterIdentifier, configMap["cluster"])
assert.Equal(s.T(), databaseName, configMap["database"])
assert.Equal(s.T(), masterHostname, configMap["hostname"])
assert.EqualValues(s.T(), inputs["database_port"], configMap["port"])
assert.Equal(s.T(), adminUsername, configMap["username"])

masterHostnameDNSRecord := aws.GetRoute53Record(s.T(), delegatedDomainNZoneId, masterHostname, "CNAME", awsRegion)
assert.Equal(s.T(), *masterHostnameDNSRecord.ResourceRecords[0].Value, configMap["endpoint"])

passwordSSMKey, ok := configMap["password_ssm_key"].(string)
assert.True(s.T(), ok, "password_ssm_key should be a string")

adminUserPassword := aws.GetParameter(s.T(), awsRegion, passwordSSMKey)

dbUrl, ok := configMap["endpoint"].(string)
assert.True(s.T(), ok, "endpoint should be a string")

dbPort, ok := inputs["database_port"].(int)
assert.True(s.T(), ok, "database_port should be an int")

schemaExistsInRdsInstance := aws.GetWhetherSchemaExistsInRdsPostgresInstance(s.T(), dbUrl, int32(dbPort), adminUsername, adminUserPassword, databaseName)
assert.True(s.T(), schemaExistsInRdsInstance)

schemaExistsInRdsInstance = aws.GetWhetherSchemaExistsInRdsPostgresInstance(s.T(), masterHostname, int32(dbPort), adminUsername, adminUserPassword, databaseName)
assert.True(s.T(), schemaExistsInRdsInstance)

schemaExistsInRdsInstance = aws.GetWhetherSchemaExistsInRdsPostgresInstance(s.T(), replicasHostname, int32(dbPort), adminUsername, adminUserPassword, databaseName)
assert.True(s.T(), schemaExistsInRdsInstance)
}

func (s *ComponentSuite) TestServerless() {
const component = "aurora-postgres/serverless"
const stack = "default-test"
const awsRegion = "us-east-2"

defer s.DestroyAtmosComponent(s.T(), component, stack, nil)
inputs := map[string]interface{}{
"name": "db",
"database_name": "postgres",
"admin_user": "postgres",
"database_port": 5432,
"publicly_accessible": true,
"allowed_cidr_blocks": []string{"0.0.0.0/0"},
}
componentInstance, _ := s.DeployAtmosComponent(s.T(), component, stack, &inputs)
assert.NotNil(s.T(), componentInstance)

databaseName := atmos.Output(s.T(), componentInstance, "database_name")
assert.Equal(s.T(), "postgres", databaseName)

adminUsername := atmos.Output(s.T(), componentInstance, "admin_username")
assert.Equal(s.T(), "postgres", adminUsername)

delegatedDnsOptions := s.GetAtmosOptions("dns-delegated", stack, nil)
delegatedDomainName := atmos.Output(s.T(), delegatedDnsOptions, "default_domain_name")
delegatedDomainNZoneId := atmos.Output(s.T(), delegatedDnsOptions, "default_dns_zone_id")

masterHostname := atmos.Output(s.T(), componentInstance, "master_hostname")
expectedMasterHostname := fmt.Sprintf("%s-%s-writer.%s", inputs["name"], componentInstance.Vars["cluster_name"], delegatedDomainName)
assert.Equal(s.T(), expectedMasterHostname, masterHostname)

ssmKeyPaths := atmos.OutputList(s.T(), componentInstance, "ssm_key_paths")
assert.Equal(s.T(), 7, len(ssmKeyPaths))

kmsKeyArn := atmos.Output(s.T(), componentInstance, "kms_key_arn")
assert.NotEmpty(s.T(), kmsKeyArn)

allowedSecurityGroups := atmos.OutputList(s.T(), componentInstance, "allowed_security_groups")
assert.Equal(s.T(), 0, len(allowedSecurityGroups))

clusterIdentifier := atmos.Output(s.T(), componentInstance, "cluster_identifier")

configMap := map[string]interface{}{}
atmos.OutputStruct(s.T(), componentInstance, "config_map", &configMap)

assert.Equal(s.T(), clusterIdentifier, configMap["cluster"])
assert.Equal(s.T(), databaseName, configMap["database"])
assert.Equal(s.T(), masterHostname, configMap["hostname"])
assert.EqualValues(s.T(), inputs["database_port"], configMap["port"])
assert.Equal(s.T(), adminUsername, configMap["username"])

masterHostnameDNSRecord := aws.GetRoute53Record(s.T(), delegatedDomainNZoneId, masterHostname, "CNAME", awsRegion)
assert.Equal(s.T(), *masterHostnameDNSRecord.ResourceRecords[0].Value, configMap["endpoint"])

passwordSSMKey, ok := configMap["password_ssm_key"].(string)
assert.True(s.T(), ok, "password_ssm_key should be a string")

adminUserPassword := aws.GetParameter(s.T(), awsRegion, passwordSSMKey)

dbUrl, ok := configMap["endpoint"].(string)
assert.True(s.T(), ok, "endpoint should be a string")

dbPort, ok := inputs["database_port"].(int)
assert.True(s.T(), ok, "database_port should be an int")

schemaExistsInRdsInstance := aws.GetWhetherSchemaExistsInRdsPostgresInstance(s.T(), dbUrl, int32(dbPort), adminUsername, adminUserPassword, databaseName)
assert.True(s.T(), schemaExistsInRdsInstance)

schemaExistsInRdsInstance = aws.GetWhetherSchemaExistsInRdsPostgresInstance(s.T(), masterHostname, int32(dbPort), adminUsername, adminUserPassword, databaseName)
assert.True(s.T(), schemaExistsInRdsInstance)
}

func (s *ComponentSuite) TestDisabled() {
const component = "aurora-postgres/disabled"
const stack = "default-test"
const awsRegion = "us-east-2"

defer s.DestroyAtmosComponent(s.T(), component, stack, nil)
componentInstance, _ := s.DeployAtmosComponent(s.T(), component, stack, nil)
assert.Nil(s.T(), componentInstance)
}

func TestRunSuite(t *testing.T) {
suite := new(ComponentSuite)

suite.AddDependency(t, "vpc", "default-test", nil)

subdomain := strings.ToLower(random.UniqueId())
inputs := map[string]interface{}{
"zone_config": []map[string]interface{}{
{
"subdomain": subdomain,
"zone_name": "components.cptest.test-automation.app",
},
},
}
suite.AddDependency(t, "dns-delegated", "default-test", &inputs)
helper.Run(t, suite)
}
87 changes: 87 additions & 0 deletions test/fixtures/atmos.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# CLI config is loaded from the following locations (from lowest to highest priority):
# system dir (`/usr/local/etc/atmos` on Linux, `%LOCALAPPDATA%/atmos` on Windows)
# home dir (~/.atmos)
# current directory
# ENV vars
# Command-line arguments
#
# It supports POSIX-style Globs for file names/paths (double-star `**` is supported)
# https://en.wikipedia.org/wiki/Glob_(programming)

# Base path for components, stacks and workflows configurations.
# Can also be set using `ATMOS_BASE_PATH` ENV var, or `--base-path` command-line argument.
# Supports both absolute and relative paths.
# If not provided or is an empty string, `components.terraform.base_path`, `components.helmfile.base_path`, `stacks.base_path` and `workflows.base_path`
# are independent settings (supporting both absolute and relative paths).
# If `base_path` is provided, `components.terraform.base_path`, `components.helmfile.base_path`, `stacks.base_path` and `workflows.base_path`
# are considered paths relative to `base_path`.
base_path: ""

components:
terraform:
# Can also be set using `ATMOS_COMPONENTS_TERRAFORM_BASE_PATH` ENV var, or `--terraform-dir` command-line argument
# Supports both absolute and relative paths
base_path: "components/terraform"
# Can also be set using `ATMOS_COMPONENTS_TERRAFORM_APPLY_AUTO_APPROVE` ENV var
apply_auto_approve: true
# Can also be set using `ATMOS_COMPONENTS_TERRAFORM_DEPLOY_RUN_INIT` ENV var, or `--deploy-run-init` command-line argument
deploy_run_init: true
# Can also be set using `ATMOS_COMPONENTS_TERRAFORM_INIT_RUN_RECONFIGURE` ENV var, or `--init-run-reconfigure` command-line argument
init_run_reconfigure: true
# Can also be set using `ATMOS_COMPONENTS_TERRAFORM_AUTO_GENERATE_BACKEND_FILE` ENV var, or `--auto-generate-backend-file` command-line argument
auto_generate_backend_file: true

stacks:
# Can also be set using `ATMOS_STACKS_BASE_PATH` ENV var, or `--config-dir` and `--stacks-dir` command-line arguments
# Supports both absolute and relative paths
base_path: "stacks"
# Can also be set using `ATMOS_STACKS_INCLUDED_PATHS` ENV var (comma-separated values string)
# Since we are distinguishing stacks based on namespace, and namespace is not part
# of the stack name, we have to set `included_paths` via the ENV var in the Dockerfile
included_paths:
- "orgs/**/*"

# Can also be set using `ATMOS_STACKS_EXCLUDED_PATHS` ENV var (comma-separated values string)
excluded_paths:
- "**/_defaults.yaml"

# Can also be set using `ATMOS_STACKS_NAME_PATTERN` ENV var
name_pattern: "{tenant}-{stage}"

workflows:
# Can also be set using `ATMOS_WORKFLOWS_BASE_PATH` ENV var, or `--workflows-dir` command-line arguments
# Supports both absolute and relative paths
base_path: "stacks/workflows"

# https://github.com/cloudposse/atmos/releases/tag/v1.33.0
logs:
file: "/dev/stdout"
# Supported log levels: Trace, Debug, Info, Warning, Off
level: Info

settings:
# Can also be set using 'ATMOS_SETTINGS_LIST_MERGE_STRATEGY' environment variable, or '--settings-list-merge-strategy' command-line argument
list_merge_strategy: replace

# `Go` templates in Atmos manifests
# https://atmos.tools/core-concepts/stacks/templating
# https://pkg.go.dev/text/template
templates:
settings:
enabled: true
# https://masterminds.github.io/sprig
sprig:
enabled: true
# https://docs.gomplate.ca
gomplate:
enabled: true

commands:
- name: "test-components"
description: "List the Atmos virtual components configured for testing"
steps:
- >
atmos describe stacks --format json --sections=component,metadata --components=component -s sandbox
| jq '.[] | .components.terraform | to_entries |
map(select(.value.component == "component" and (.value.metadata.type != "abstract" or .value.metadata.type == null)))
| .[].key'
Loading