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
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
5 changes: 5 additions & 0 deletions test/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
state/
.cache
test/test-suite.json
.atmos
test_suite.yaml
204 changes: 204 additions & 0 deletions test/component_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
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"

clusterName := strings.ToLower(random.UniqueId())

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"},
"cluster_name": clusterName,
}
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)

s.DriftTest(component, stack, &inputs)
}

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

clusterName := strings.ToLower(random.UniqueId())

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"},
"cluster_name": clusterName,
}
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)

s.DriftTest(component, stack, &inputs)
}

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

s.VerifyEnabledFlag(component, stack, nil)
}

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)
}
77 changes: 77 additions & 0 deletions test/fixtures/atmos.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
# 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
Loading