Output: ==> Installing Ruby and dependencies...
Successfully installed bundler-2.4.22
Parsing documentation for bundler-2.4.22
Done installing documentation for bundler after 0 seconds
1 gem installed
Bundle complete! 13 Gemfile dependencies, 53 gems now installed.
Bundled gems are installed into `../../../.bundles`

==> Installing Terraform and dependencies...
Terraform v1.9.8 is already installed
[*] Checking out 0.17.0 from git@github.com:cloudposse/terraform-aws-codebuild.git
[*] Checking out 2.1.0 from git@github.com:dxw/terraform-aws-github-ci.git
[*] Checking out 3cc589ecb5bf70fbd1188c47c915550235d4714b from git@github.com:dxw/terraform-aws-s3-bucket.git
[*] Checking out v2.70.0 from git@github.com:terraform-aws-modules/terraform-aws-vpc
[*] Checking out v5.7.0 from git@github.com:dxw/tf_aws_ecs.git
[*] Checking out 1.1.0 from git@github.com:dxw/terraform-aws-cloudtrail
[*] Checking out 0.28.2 from git@github.com:cloudposse/terraform-aws-efs
[*] Checking out v1.3.0 from git@github.com:claranet/terraform-aws-lambda
[*] Checking out v5.2.2 from git@github.com:terraform-aws-modules/terraform-aws-rds
[*] Checking out v8.3.1 from git@github.com:terraform-aws-modules/terraform-aws-rds-aurora.git

==> Checking for a 'dalmatian.yml' in the root...
Found: /Users/bob/git/dxw/dalmatian-config/dalmatian.yml

==> Linting YAML...

==> Linting shell scripts...

==> Checking Terraform for JSON errors...
- Checking ./terraform/policies/iam-read.json... Passed
- Checking ./terraform/policies/s3-rw-with-versioning.json... Passed
- Checking ./terraform/policies/codestar-connection-use.json... Passed
- Checking ./terraform/policies/iam-create-access-key.json... Passed
- Checking ./terraform/policies/codebuild.json... Passed
- Checking ./terraform/policies/kms-encrypt-decrypt.json... Passed
- Checking ./terraform/policies/iam-change-password.json... Passed
- Checking ./terraform/policies/administrator-access.json... Passed
- Checking ./terraform/policies/assume_roles/aws-backup.json... Passed
- Checking ./terraform/policies/assume_roles/autoscaling.json... Passed
- Checking ./terraform/policies/assume_roles/events.json... Passed
- Checking ./terraform/policies/assume_roles/ecs.json... Passed
- Checking ./terraform/policies/assume_roles/codepipeline.json... Passed
- Checking ./terraform/policies/iam-mfa.json... Passed
- Checking ./terraform/policies/route53-read.json... Passed
- Checking ./terraform/policies/s3-full-access.json... Passed
- Checking ./terraform/policies/parameter-store-read-decrypt.json... Passed
- Checking ./terraform/policies/s3-read.json... Passed
- Checking ./terraform/policies/parameter-store-RW-encrypt-decrypt.json... Passed
- Checking ./terraform/policies/all-read-with-billing.json... Passed
- Checking ./terraform/policies/codebuild-start-build.json... Passed
- Checking ./terraform/policies/all-read.json... Passed

==> Linting Terraform...

==> Running Ruby tests...
/Users/bob/.rbenv/versions/2.7.1/bin/ruby -I/Users/bob/.bundles/ruby/2.7.0/gems/rspec-core-3.12.2/lib:/Users/bob/.bundles/ruby/2.7.0/gems/rspec-support-3.12.1/lib /Users/bob/.bundles/ruby/2.7.0/gems/rspec-core-3.12.2/exe/rspec --pattern spec/\*\*\{,/\*/\*\*\}/\*_spec.rb

tests local configuration
  use of "terraform apply"
    passes the hosted zone config to "terraform apply"
    passes the s3 config to "terraform apply"
    passes the vpn customer gateway config to "terraform apply"
    passes the base config to "terraform apply"
    passes the waf config to "terraform apply"
    passes the rds config to "terraform apply"
    passes the elasticache config to "terraform apply"
    passes the opensearch config to "terraform apply"
    passes the service config to "terraform apply"
    passes the loadbalancer config to "terraform apply"
    passes the cluster 2 config to "terraform apply"
    passes the cluster 3 config to "terraform apply"
    passes the cluster 4 config to "terraform apply"

tests remote configuration
  retrieves the remotely held full configuration
  proceeds with deploying the infrastructure as per the cached full configuration

tests local configuration
  invokes  "terraform validate" with the expected cluster options
  invokes  "terraform validate" with the expected source options
  use of "terraform plan"
    passes the hosted zone config to "terraform plan"
    passes the s3 config to "terraform plan"
    passes the vpn customer gateway config to "terraform plan"
    passes the base config to "terraform plan"
    passes the waf config to "terraform plan"
    passes the rds config to "terraform plan"
    passes the elasticache config to "terraform plan"
    passes the opensearch config to "terraform plan"
    passes the services config to "terraform plan"
    passes the loadbalancer config to "terraform plan"
    passes the cluster 2 config to "terraform plan"
    passes the cluster 3 config to "terraform plan"
    passes the cluster 4 config to "terraform plan"

Dalmatian::Account
  initialisation
    gathering user input
      asks the user for AWS credentials
      asks the user for the AWS account id to use
      asks the user for an account alias
  #call
    changes to the bootstrapping directory
    runs terraform init with upgrade option
    creates the new workspace using the given aws account id and alias
    runs terraform apply with the user-supplied vars

Dalmatian::CacheHandlerSelector
  ::new_for(remote_reference)
    when the remote reference is for a git repo
      asks for an instance of GitCacheHandler
    when the remote reference is for an S3 bucket
      asks for an instance of S3CacheHandler
    when the remote reference is for a URL
      asks for an instance of UrlCacheHandler
    when the type is unknown
      raises an error

CacheHandler
  when a subclass class does not implement #cache_remote_configuration
    raises a helpful error

Dalmatian::CI
  CI::PATH
    is a constant
  #deploy
    changes to the ci directory
    runs terraform init with upgrade option
    creates the new workspace using the given aws account id and alias
    runs terraform apply with the user-supplied vars
  #test
    runs terraform plan with the user-supplied vars

Dalmatian::ClusterDeployment
  #call
    changes to the ecs directory
    asks Terraform to ensure that the workspace is in place
    when the environment includes a git reference as "track_revision"
      does NOT attempt to check out that commit
    when in _plan_ mode
      invokes Terraform.plan using the _dalmatian-read_ role
    when NOT in _plan_ mode
      invokes Terraform.apply using the _dalmatian-admin_
      when in _auto_approve_ mode
        asks Terraform to use auto_approve mode

Dalmatian::Cluster
  on initialisation
    makes Hosted zones, S3, Sources, Services, Loadbalancers, WAF and Rds
  #target_directory
    is a standard _ecs_ path
  #id
    is the primary key of the cluster definition is used
  #name
    when the cluster has an explicitly provided _name_ property
      that property is used
    when the cluster does not have an explicitly provided _name_ property
      the primary key of the cluster definition is used
  #account_id
    is the aws account key for deployment
  #sources
    represents any links to remote sources
  #environments
    represents the attributes of each environment's cluster section
  #fetch
    when the source is remotely held
      logs the plan to clone the source into the infrastructure pth
      deletes any existing source at the infrastructure location
      clones each source into the infrastructure location
      changes to the infrastructure directory for each source
      runs rake terrafile
      changes back to the APP_ROOT
    when the source is a local file path
      does not re-clone the source
      does not run terrafile
      when the specified local directory exists
        logs the fact that the local source is in place
      when the specificed local directory does not exist
        logs an error that the local source is missing
  #deploy
    deploys source infrastructure for each source and each service in each environment
    when a cluster should be created
      deploys cluster infrastructure for each environment
      when the _plan_ option IS invoked
        creates Cluster Deployments with plan settings
      when the _auto_approve_ option IS invoked
        creates Cluster Deployments with auto_approve settings
      handling of tests
        when the _test_ option is NOT invoked
          does not run cluster tests
          does not run cluster tests
          does not run cluster tests
          does not run source tests
          does not run waf tests
          does not run rds tests
          does not run service tests
          does not run service tests
        when the test option IS invoked
          runs tests
    when a cluster should NOT be created
      does not deploy cluster infrastructure
    when test option is invoked
      tests sources and services for each environment

Dalmatian::ClusterTest
  #call
    changes to the ecs directory
    logs our intention to run Terraform init
    runs Terraform init, with upgrade option
    ensures presence of workspace
    logs our intention to run Terraform fmt
    runs Terraform fmt with check and diff options
    logs our intention to run Terraform validate
    runs Terraform validate, with upgrade option
    changes back to the app root directory
    when the environment includes a git reference as "track_revision"
      does NOT attempt to check out that commit

Dalmatian::ConfigurationReader
  when a full configuration is provided in a local file
    #call
      has no need to use a cache handler
      returns the loaded configuration
  when a reference to a remote configuration is provided
    and the reference is provided in a local file
      uses the CacheHandlerSelector to provide the appropriate retrieval mechanism
      calls on the selected cache handler
      returns the configuration returned by the cache_handler
    and the reference is provided using environment variables
      passes the provided remote reference to the CacheHandlerSelector
    and references are provided in both environment variables and config file
      prefers the environment variable references over the config file
    and no references are provided
      raises an error
    and the remote reference is missing its _type_
      raises an error
  #ci
    when a parameter path prefix is given
      overwrites the ci:variables config with those retrieved from the param store
      leaves other ci:variables in place
    when a parameter path prefix is NOT given
      does NOT overwrite any ci:variables from the param store

Dalmatian::ElasticacheCluster
  #identifier
    uses elasticache identifier
  #in_use_by
    uses elasticache_cluster in_use_by list
  #node_type
    uses elasticache_cluster node_type
  #node_count
    uses elasticache_cluster node_count
  #engine
    uses elasticache_cluster engine
  #engine_version
    uses the elasticache_cluster engine_version
  #parameters
    uses the elasticache_cluster parameters list
  #port
    uses the elasticache_cluster port
  #maintenance_window
    uses the elasticache_cluster maintenance_window
  #snapshot_window
    uses the elasticache_cluster snapshot_window
  #parameter_store_path_elasticache_cluster_url_name
    uses the elasticache_cluster parameter_store_path_elasticache_cluster_url_name
  #to_params
    provides a hash of attributes for use in deployment

Dalmatian::ElasticacheClusterTest
  #call
    changes to the elasticache-cluster directory
    logs our intention to run Terraform init
    runs Terraform init, with upgrade option
    ensures presence of workspace
    logs our intention to run Terraform fmt
    runs Terraform fmt with check and diff options
    logs our intention to run Terraform validate
    runs Terraform validate, with upgrade option
    changes back to the app root directory

Dalmatian::GitCacheHandler
  #call
    deletes any old cache
    uses git clone to save the remote config to a local cache
    logs the cloning action
    logs the path to the cached configuration
    returns the cached full configuration to the caller (configuration reader)
    reads the cached full configuration from the disk in order to return to caller
    when no special cache path is given
      uses the default cache path of ./.dalmatian_cache/remote_config

Dalmatian::Helper
  ::git_clone(source, destination)
    when source and destination args are not provided
      raises an error with usage info
    when given source and destination args
      passes the request to the git CLI
  ::git_checkout(revision)
    checks out the given revision using run!
  ::get(source, destination)
    when source and destination args are not provided
      raises an error with usage info
    when given source and destination args
      opens the source url
      opens a new file at the destination
      writes the source resource into that file
      reads the information from the fetched resource
  ::run!
    passes given cmd to Kernel.system
    when the call to Kernel.system returns _false_
      raise a helpful error
  ::run_with_output!(cmd)
    passes given cmd to Open3.capture3
    when the system call returns a zero exit status
      returns the systems output to STDOUT
    when the system call returns a non-zero exit status
      also returns STDOUT ignoring the exit code and STDERR
    when the system call raises an ENOENT error
      catches this and raises a helpful Error
  ::change_to(path)
    passes the given path to Dir.chdir
  ::to_bool(str)
    when given nil
      returns false
    when given an empty string
      returns false
    when given lower case string _true_
      returns true
    when given mixed case string _True_
      returns true
    when given the object true
      returns true
    when given the object false
      returns false
  ::tflint
    runs the tflint cmd
  ::terrafile
    runs rake terrafile
  ::ask
    delegates to HighLine#ask
  ::ask_in_confidence
    delegates to HighLine#ask
    passes a block to mask the answer

Dalmatian::HostedZoneDeployment
  #call
    changes to hosted-zone infrastructure directory
    asks Terraform to ensure that the workspace is in place
    when in _plan_ mode
      invokes Terraform.plan with the _dalmatian-read_ role
    when NOT in _plan_ mode
      invokes Terraform.apply with the _dalmatian-admin_ role
      when in _auto_approve_ mode
        asks Terraform to use auto_approve mode

Dalmatian::HostedZone
  #domain
    uses hosted_zone domain
  #ns_records
    uses hosted_zone ns_records
  #a_records
    uses hosted_zone a_records
  #alias_records
    uses hosted_zone alias_records
  #cname_records
    uses hosted_zone cname_records
  #mx_records
    uses hosted_zone mx_records
  #txt_records
    uses hosted_zone txt_records
  #srv_records
    uses hosted_zone srv_records
  #to_params
    provides a hash of attributes for use in deployment

Dalmatian::HostedZoneTest
  #call
    changes to the hosted-zone directory
    logs our intention to run Terraform init
    runs Terraform init, with upgrade option
    ensures presence of workspace
    logs our intention to run Terraform fmt
    runs Terraform fmt with check and diff options
    logs our intention to run Terraform validate
    runs Terraform validate, with upgrade option
    changes back to the app root directory

Dalmatian::Infrastructure
  Infrastructure::PATH
    is a constant
  Infrastructure::APP_ROOT
    is a constant
  initialisation
    when configuration is not provided
      builds one using the defaults
  #clusters
    creates one cluster for each cluster description provided
  key operations on clusters
    #fetch
      asks all clusters to #fetch
    #test
      asks all clusters to #deploy with _plan_ and _test_ options
    #deploy
      when no parameters given
        asks all clusters to #deploy with _plan_, _test_ and _auto-approve_ disabled
      when parameters are given
        asks all clusters to #deploy with the given options
    when a particular infrastructure is named for deployment
      asks only the named cluster to #deploy with the given options

Dalmatian::Logger
  ::error(msg)
    raises an error with a red message
  ::info(msg)
    puts the given given message in white
  ::success(msg)
    puts the given given message in green
  ::warn(msg)
    puts the given given message in yellow

Dalmatian::OpensearchCluster
  #identifier
    uses opensearch identifier
  #in_use_by
    uses opensearch_cluster in_use_by list
  #version
    uses opensearch_cluster version
  #master_enabled
    uses opensearch_cluster master_enabled bool
  #master_count
    uses opensearch_cluster master_count
  #master_type
    uses opensearch_cluster master_type
  #instance_count
    uses opensearch_cluster instance_count
  #instance_type
    uses opensearch_cluster instance_type
  #warm_enabled
    uses opensearch_cluster warm_enabled bool
  #warm_count
    uses opensearch_cluster warm_count
  #warm_type
    uses opensearch_cluster warm_type
  #parameter_store_path_opensearch_cluster_url_name
    uses opensearch_cluster parameter_store_path_opensearch_cluster_url_name
  #volume_size
    uses opensearch_cluster volume_size
  #to_params
    provides a hash of attributes for use in deployment

Dalmatian::OpensearchClusterTest
  #call
    changes to the opensearch-cluster directory
    logs our intention to run Terraform init
    runs Terraform init, with upgrade option
    ensures presence of workspace
    logs our intention to run Terraform fmt
    runs Terraform fmt with check and diff options
    logs our intention to run Terraform validate
    runs Terraform validate, with upgrade option
    changes back to the app root directory

Dalmatian::ParameterStore
  ::get_parameter(name: "", with_decryption: true)
    when getting a single parameter from Parameter Store
      runs aws ssm get-parameter
  ::get_parameters_by_path(path: "", with_decryption: true)
    when getting parameters by path from Parameter Store
      runs aws ssm get-parameter

Dalmatian::RdsDeployment
  #call
    changes to rds infrastructure directory
    asks Terraform to ensure that the workspace is in place
    when in _plan_ mode
      invokes Terraform.plan with the _dalmatian-read_ role
    when NOT in _plan_ mode
      invokes Terraform.apply with the _dalmatian-admin_ role
      when in _auto_approve_ mode
        asks Terraform to use auto_approve mode

Dalmatian::Rds
  #identifier
    uses rds identifier
  #in_use_by
    uses rds in_use_by list
  #clusters_in_use
    uses rds clusters_in_use list
  #instance_class
    uses rds instance_class
  #engine
    uses rds engine
  #engine_version
    uses the rds engine_version
  #allocated_storage
    uses the rds allocated_storage
  #storage_encrypted
    uses the rds storage_encrypted bool
  #storage_type
    uses the rds storage_type gp3
  #db_name
    uses the rds db_name
  #port
    uses the rds port
  #maintenance_window
    uses the rds maintenance_window
  #backup_window
    uses the rds backup_window
  #backup_retention_period
    uses the rds backup_retention_period
  #force_ssl
    uses the rds force_ssl bool
  #parameter_store_path_db_url_name
    uses the rds parameter_store_path_db_url_name
  #sql_backup_scheduled_task_environment_variables
    uses the rds sql_backup_scheduled_task_environment_variables
  #check_sql_backup_scheduled_task_environment_variables
    uses the rds check_sql_backup_scheduled_task_environment_variables
  #sync_sql_backup_to_azure
    will have offsite backups disabled by default
  #replication_bucket_destination_arn
    uses the rds replication_bucket_destination_arn
  #replication_kms_key_id
    uses the rds replication_kms_key_id
  #codebuild_access
    uses the rds codebuild_access
  #to_params
    provides a hash of attributes for use in deployment

Dalmatian::RdsTest
  #call
    changes to the ecs-services directory
    logs our intention to run Terraform init
    runs Terraform init, with upgrade option
    ensures presence of workspace
    logs our intention to run Terraform fmt
    runs Terraform fmt with check and diff options
    logs our intention to run Terraform validate
    runs Terraform validate, with upgrade option
    changes back to the app root directory

Dalmatian::RemoteReferenceValues
  when the reference is for a git repo
    returns a git shaped configuration
    if _filename_ is not present
      supplies the default of _dalmatian.yml_
  when the reference is for an S3 bucket
    returns an S3 shaped configuration
    if _key_ is not present
      supplies the default of _dalmatian.yml_
  when the reference is for a URL
    returns a git shaped configuration

Dalmatian::S3CacheHandler
  #call
    deletes any old cache
    uses the AWS S3 cmd to save the remote config to a local cache
    logs the cloning action
    logs the path to the cached configuration
    returns the cached full configuration to the caller (configuration reader)
    reads the cached full configuration from the disk in order to return to caller

Dalmatian::S3Deployment
  #call
    changes to s3 infrastructure directory
    asks Terraform to ensure that the workspace is in place
    when in _plan_ mode
      invokes Terraform.plan with the _dalmatian-read_ role
    when NOT in _plan_ mode
      invokes Terraform.apply with the _dalmatian-admin_ role
      when in _auto_approve_ mode
        asks Terraform to use auto_approve mode

Dalmatian::S3
  #name
    uses s3 name
  #enable_s3_versioning
    uses enable_s3_versioning bool
  #encrypted
    uses s3 encrypted bool
  #acl
    uses s3 acl
  #policy
    uses s3 policy
  #service_cloudfront_read_access
    uses s3 service_cloudfront_read_access
  #cloudfront
    uses s3 cloudfront
  #to_params
    provides a hash of attributes for use in deployment

Dalmatian::S3Test
  #call
    changes to the s3 directory
    logs our intention to run Terraform init
    runs Terraform init, with upgrade option
    ensures presence of workspace
    logs our intention to run Terraform fmt
    runs Terraform fmt with check and diff options
    logs our intention to run Terraform validate
    runs Terraform validate, with upgrade option
    changes back to the app root directory

Dalmatian::ServiceDeployment
  #call
    changes to ecs-services infrastructure directory
    asks Terraform to ensure that the workspace is in place
    when in _plan_ mode
      invokes Terraform.plan with the _dalmatian-read_ role
    when NOT in _plan_ mode
      invokes Terraform.apply with the _dalmatian-admin_ role
      when in _auto_approve_ mode
        asks Terraform to use auto_approve mode

Dalmatian::Service
  #name
    uses service name
  #blue_green
    uses the service blue_green map
  #parameter_store_path
    uses service parameter_store_path
  #parameter_store_key
    uses service parameter_store_key
  #daemon
    uses the service daemon bool
  #monitoring
    uses the service monitoring hash
  #cloudfront
    recasts the service config in environment groups
    includes the appropriate "custom_origins" values in each environment
    Uses an AWS cloudfront managed cache policy
    Uses an AWS cloudfront managed origin policy
    Uses an AWS cloudfront managed response headers policy
    mirroring of elements into each environment group
      includes the "create" value
      includes the "tls_protocol_version" value
      includes the "origin_keepalive_timeout" value
      includes the "origin_read_timeout" value
      includes the "basic_auth" value
      includes the "basic_auth_users_extra" value
      includes the "viewer_request_functions" values
      includes the "offline_page_http_status" value
    bypass_protection
      uses the "bypass_protection" configuration
    custom_behaviors
      converts list of "path_patterns" to a single "path_pattern"
  #shared_loadbalancer_name
    returns shared loadbalancer name if the service is in use by a shared loadbalancer
    returns empty string if the service is not in use by a shared loadbalancer
  #s3_policy
    uses the service s3_policy map
  #lb_ip_whitelistt
    uses the service lb_ip_whitelist list
  #lb_idle_timeout
    uses the service lb_idle_timeout
  #global_accelerator
    uses service global_accelerator value
  #health_check_path
    uses the service health_check_path
  #health_check_grace_period
    uses the service health_check_grace_period
  #deregistration_delay
    uses the service deregistration_delay
  #serve_from_subdirectory
    uses the service serve_from_subdirectory
  #domain_names
    groups the domain names from the service domain_list into environments
  #proxy_configuration
    groups the proxy configurations from the service proxy_configuration list into environments
  #home_directory
    uses the service home_directory
  #lb_ssl_certificate
    groups the certificate arns from the service lb_ssl_certificate list into environments
  #lb_ssl_policy
    sets the default ssl policy for each environment
  #cloudfront_ssl_certificate
    groups the certificate arns from the service cloudfront_ssl_certificate list into environments
  #image_source
    uses the service image source
  #launch_on
    uses the service 'launch_on' specification
  #launch_on_cluster
    uses the service 'launch_on_cluster' string
  #cluster_min_servers
    uses the service 'cluster_min_servers' string
  #image_location
    uses the service image location
  #track_revision
    uses the service track_revision string
  #custom_codestar_connection_arn
    uses the service custom_codestar_connection_arn
  #codepipeline_use_github_v1
    uses the service codepipeline_use_github_v1
  #codepipeline_codebuild_run_in_vpc
    uses the service codepipeline_codebuild_run_in_vpc
  #codepipeline_codebuild_use_service_env
    uses the service codepipeline_codebuild_use_service_env
  #buildspec
    uses the service buildspec
  #container_port
    uses the service container port
  #container_command
    uses the service container command
  #container_volumes
    uses the service container volumes
  #container_extra_hosts
    uses the service container extra hosts
  #container_count
    uses the service container_count
  #enable_max_one_container_per_instance
    uses the service enable_max_one_container_per_instance
  #scheduled_tasks
    uses the service scheduled tasks
  #workers
    uses the service workers
  #cluster_name
    delegates to the cluster
  #cluster_id
    delegates to the cluster
  #account_id
    delegates to the cluster
  #to_params
    provides a hash of attributes for use in deployment

Dalmatian::ServiceTest
  #call
    changes to the ecs-services directory
    logs our intention to run Terraform init
    runs Terraform init, with upgrade option
    ensures presence of workspace
    logs our intention to run Terraform fmt
    runs Terraform fmt with check and diff options
    logs our intention to run Terraform validate
    runs Terraform validate, with upgrade option
    changes back to the app root directory

Dalmatian::SharedLoadbalancerDeployment
  #call
    changes to shared-loadbalancer infrastructure directory
    asks Terraform to ensure that the workspace is in place
    when in _plan_ mode
      invokes Terraform.plan with the _dalmatian-read_ role
    when NOT in _plan_ mode
      invokes Terraform.apply with the _dalmatian-admin_ role
      when in _auto_approve_ mode
        asks Terraform to use auto_approve mode

Dalmatian::SharedLoadbalancer
  #name
    uses shared_loadbalancer name
  #in_use_by
    uses shared_loadbalancer in_use_by list
  #clusters_in_use
    uses shared_loadbalancer clusters_in_use list
  #subnets_name
    uses shared_loadbalancer subnets_name value
  #domain_names
    uses shared_loadbalancer domain_names list provided by Services
  #internal
    uses shared_loadbalancer internal value
  #ip_whitelist
    uses shared_loadbalancer ip_whitelist list
  #idle_timeout
    uses shared_loadbalancer idle_timeout value
  #global_accelerator
    uses shared_loadbalancer global_accelerator value
  #ssl_policy
    has the default ssl policy defined
  #to_params
    provides a hash of attributes for use in deployment

Dalmatian::SharedLoadbalancerTest
  #call
    changes to the shared-loadbalancer directory
    logs our intention to run Terraform init
    runs Terraform init, with upgrade option
    ensures presence of workspace
    logs our intention to run Terraform fmt
    runs Terraform fmt with check and diff options
    logs our intention to run Terraform validate
    runs Terraform validate, with upgrade option
    changes back to the app root directory

Dalmatian::SourceDeployment
  #call
    changes to infrastructure config directory
    asks Terraform to ensure that the workspace is in place
    when the environment includes a git reference as "track_revision"
      checks out that commit
      passes the "track_revision" reference along to Terraform
    when in _plan_ mode
      invokes Terraform.plan with the _dalmatian-read_ role
    when NOT in _plan_ mode
      invokes Terraform.apply with the _dalmatian-admin_ role
      when in _auto_approve_ mode
        asks Terraform to use auto_approve mode

Dalmatian::Source
  #name
    uses the cluster name and its own position in the cluster's list of sources
  #cluster_name
    delegates to the cluster
  #cluster_id
    delegates to the cluster
  #account_id
    delegates to the cluster

Dalmatian::SourceTest
  #call
    changes to the ecs directory
    logs our intention to run Terraform init
    runs Terraform init, with upgrade option
    ensures presence of workspace
    logs our intention to run Terraform fmt
    runs Terraform fmt with check and diff options
    logs our intention to run Terraform validate
    runs Terraform validate, with upgrade option
    changes back to the app root directory
  when the environment includes a git reference as "track_revision"
    checks out that commit
    passes the "track_revision" reference along to Terraform.validate

Dalmatian::Terraform
  ::init(upgrade: false)
    when asked to upgrade
      passes terraform init the upgrade flag
    when not asked to upgrade
      does not pass terraform init the upgrade flag
  ::fmt(args = nil)
    when passed some additional arguments
      passes terraform fmt the upgrade flag
    when passed NO additional arguments
      invokes terraform fmt with no arguments
  ::validate(tfvars)
    passes the given _var-file_ to terraform
    reformats the given tfvars and passes them to terraform as args
  ::ensure_presence_of_workspace(workspace_name)
    logs our intention to create the workspace
    asks Terraform to create the workspace
    when the workspace already exists (and an error is rescued)
      logs our intention to _select_ rather than _create_ the workspace
      asks Terraform to select the existing workspace
  ::plan(tfvars)
    passes the given _var-file_ to terraform
    reformats the given tfvars and passes them to terraform as args
  ::apply(tfvars, auto_approve=false)
    passes the given _var-file_ to terraform
    reformats the given tfvars and passes them to terraform as args
    when auto-approve is set to true
      passes the _auto-approve_ flag to terraform apply
  ::destroy(tfvars)
    passes the given _var-file_ to terraform
    reformats the given tfvars and passes them to terraform as args
  ::list_workspaces
    changes to the bootstrapping directory
    runs the terraform cmd to list workspaces

Dalmatian::UrlCacheHandler
  #call
    deletes any old cache
    uses the helper to GET a URI
    logs the cloning action
    logs the path to the cached configuration
    returns the cached full configuration to the caller (configuration reader)
    reads the cached full configuration from the disk in order to return to caller

Dalmatian::VpnCustomerGatewayDeployment
  #call
    changes to vpn-customer-gateway infrastructure directory
    asks Terraform to ensure that the workspace is in place
    when in _plan_ mode
      invokes Terraform.plan with the _dalmatian-read_ role
    when NOT in _plan_ mode
      invokes Terraform.apply with the _dalmatian-admin_ role
      when in _auto_approve_ mode
        asks Terraform to use auto_approve mode

Dalmatian::VpnCustomerGateway
  #name
    uses vpn_customer_gateway name
  #bgp_asn
    uses vpn_customer_gateway bgp_asn
  #ip_address
    uses vpn_customer_gateway ip_address
  #to_params
    provides a hash of attributes for use in deployment

Dalmatian::VpnCustomerGatewayTest
  #call
    changes to the vpn-customer-gateway directory
    logs our intention to run Terraform init
    runs Terraform init, with upgrade option
    ensures presence of workspace
    logs our intention to run Terraform fmt
    runs Terraform fmt with check and diff options
    logs our intention to run Terraform validate
    runs Terraform validate, with upgrade option
    changes back to the app root directory

Dalmatian::WAFDeployment
  #call
    changes to waf infrastructure directory
    asks Terraform to ensure that the workspace is in place
    when in _plan_ mode
      invokes Terraform.plan with the _dalmatian-read_ role
    when NOT in _plan_ mode
      invokes Terraform.apply with the _dalmatian-admin_ role
      when in _auto_approve_ mode
        asks Terraform to use auto_approve mode

Dalmatian::WAF
  #name
    uses waf name
  #action
    uses waf action
  #ip_deny_list
    has a list of IP addresses to block
  #aws_managed_rules
    uses waf aws_managed_rules list
  #associations
    uses waf associations list
  #to_params
    provides a hash of attributes for use in deployment

Dalmatian::WAFTest
  #call
    changes to the ecs-services directory
    logs our intention to run Terraform init
    runs Terraform init, with upgrade option
    ensures presence of workspace
    logs our intention to run Terraform fmt
    runs Terraform fmt with check and diff options
    logs our intention to run Terraform validate
    runs Terraform validate, with upgrade option
    changes back to the app root directory

Finished in 3.23 seconds (files took 0.7882 seconds to load)
478 examples, 0 failures

Coverage report generated for RSpec to /Users/bob/git/dxw/dalmatian/coverage. 4310 / 4389 LOC (98.2%) covered.

==> Linting markdown...

==> Fetching Dalmatian config for 'dxw-pentest'...

==> Testing Dalmatian for 'dxw-pentest'...
[*] Running terraform init for dxw-pentest-pentestvone-rds-staging
Initializing the backend...
Upgrading modules...
- rds in ../../../vendor/terraform_modules/terraform-aws-rds
- rds.db_instance in ../../../vendor/terraform_modules/terraform-aws-rds/modules/db_instance
- rds.db_option_group in ../../../vendor/terraform_modules/terraform-aws-rds/modules/db_option_group
- rds.db_parameter_group in ../../../vendor/terraform_modules/terraform-aws-rds/modules/db_parameter_group
- rds.db_subnet_group in ../../../vendor/terraform_modules/terraform-aws-rds/modules/db_subnet_group
Initializing provider plugins...
- Finding hashicorp/aws versions matching ">= 4.45.0, ~> 4.45"...
- Finding hashicorp/random versions matching ">= 3.1.0"...
- Using previously-installed hashicorp/aws v4.67.0
- Using previously-installed hashicorp/random v3.8.1

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
[*] Creating dxw-pentest-pentestvone-rds-staging workspace
Workspace "dxw-pentest-pentestvone-rds-staging" already exists
[*] Selecting dxw-pentest-pentestvone-rds-staging workspace
[*] Running terraform fmt for dxw-pentest-pentestvone-rds-staging
[*] Running terraform validate for dxw-pentest-pentestvone-rds-staging
Success! The configuration is valid.

[*] Creating dxw-pentest-pentestvone-rds-staging workspace
Workspace "dxw-pentest-pentestvone-rds-staging" already exists
[*] Selecting dxw-pentest-pentestvone-rds-staging workspace
random_password.rds_password: Refreshing state... [id=none]
module.rds.module.db_instance.random_id.snapshot_identifier[0]: Refreshing state... [id=lmwwSA]
data.aws_caller_identity.current: Reading...
data.aws_caller_identity.current: Read complete after 0s [id=511700466171]
module.rds.module.db_instance.data.aws_partition.current: Reading...
data.aws_launch_template.ecs_launch_template: Reading...
data.aws_kms_alias.ssm: Reading...
module.rds.module.db_instance.data.aws_partition.current: Read complete after 0s [id=aws]
aws_cloudwatch_event_rule.check_sql_backup_scheduled_task: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-csb-st]
data.aws_s3_bucket.transfer: Reading...
aws_iam_role.sql_backup_scheduled_task_ecs: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-sb-ecs]
module.rds.module.db_parameter_group.aws_db_parameter_group.this[0]: Refreshing state... [id=dxwpentestpentestvonestaging-20250630133224710900000001]
aws_s3_bucket.sql_backups: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-sql-backup]
module.rds.module.db_instance.data.aws_iam_policy_document.enhanced_monitoring: Reading...
aws_iam_role.check_sql_backup_scheduled_task_ecs_execution: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-csb-ecs-execution]
module.rds.module.db_instance.data.aws_iam_policy_document.enhanced_monitoring: Read complete after 0s [id=1813475199]
module.rds.module.db_option_group.aws_db_option_group.this[0]: Refreshing state... [id=dxwpentestpentestvonestaging-20250630133225312500000002]
aws_kms_key.rds_ssm: Refreshing state... [id=0aa5dca8-ddcc-4258-bf28-a561b9a8ef87]
data.aws_kms_alias.ssm: Read complete after 0s [id=arn:aws:kms:eu-west-2:932446864135:alias/aws/ssm]
aws_iam_role.check_sql_backup_scheduled_task_cloudwatch: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-csb-cw]
data.aws_s3_bucket.transfer: Read complete after 0s [id=dxw-pentest-ecs-staging-dalmatian-transfer]
aws_iam_role.check_sql_backup_scheduled_task_ecs: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-csb-ecs]
data.aws_security_group.ecs_security_group: Reading...
aws_cloudwatch_event_rule.sql_backup_scheduled_task: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-sb-st]
data.aws_ecs_cluster.cluster: Reading...
data.aws_launch_template.ecs_launch_template: Read complete after 0s [id=lt-0fba00b394755128b]
aws_iam_role.sql_backup_scheduled_task_ecs_execution: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-sb-ecs-execution]
data.aws_vpc.vpc: Reading...
aws_iam_role.sql_backup_scheduled_task_cloudwatch: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-sb-cw]
data.aws_ecs_cluster.cluster: Read complete after 0s [id=arn:aws:ecs:eu-west-2:932446864135:cluster/dxw-pentest-staging]
aws_kms_alias.rds_ssm: Refreshing state... [id=alias/dxw-pentest-pentestvone-rds-staging-rds-values-ssm]
data.aws_iam_instance_profile.ecs_launch_template_iam_instance_profile: Reading...
data.aws_security_group.ecs_security_group: Read complete after 0s [id=sg-09323ac1b18adbf47]
aws_ssm_parameter.rds_db_password: Refreshing state... [id=/dxw-pentest/dxwpentestpentestvonestaging-rds/password]
aws_s3_bucket_public_access_block.sql_backups: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-sql-backup]
aws_s3_bucket_server_side_encryption_configuration.sql_backups: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-sql-backup]
aws_s3_bucket_lifecycle_configuration.sql_backups: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-sql-backup]
aws_s3_bucket_acl.sql_backups: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-sql-backup,private]
data.aws_vpc.vpc: Read complete after 0s [id=vpc-08160529b0069a9a4]
aws_s3_bucket_policy.sql_backups_bucket: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-sql-backup]
aws_iam_policy.ecs_cluster_sql_backup_s3_policy: Refreshing state... [id=arn:aws:iam::932446864135:policy/dxw-pentest-pentestvone-rds-staging-ecs-cluster-sql-backups-s3-policy]
aws_security_group.rds: Refreshing state... [id=sg-03c7b2d71eea98557]
data.aws_iam_instance_profile.ecs_launch_template_iam_instance_profile: Read complete after 0s [id=AIPA5SGRKAMD3YWY6PA25]
data.aws_subnet.ecs_private[0]: Reading...
data.aws_subnet.ecs_private[1]: Reading...
data.aws_subnet.ecs_private[0]: Read complete after 0s [id=subnet-0615109dfd24f74b5]
data.aws_subnet.ecs_private[2]: Reading...
data.aws_subnet.ecs_private[1]: Read complete after 0s [id=subnet-0606eeedab5dea6c7]
data.aws_subnet.extra_public[1]: Reading...
data.aws_subnet.ecs_private[2]: Read complete after 0s [id=subnet-01660d0866e86d9b6]
data.aws_subnet.extra_public[0]: Reading...
data.aws_subnet.extra_public[1]: Read complete after 0s [id=subnet-0295a7cf928d802eb]
data.aws_subnet.extra_public[2]: Reading...
aws_security_group_rule.transition_rds_postgresql_sg_rule[0]: Refreshing state... [id=sgrule-4074910867]
aws_iam_role_policy.check_sql_backup_scheduled_task_ecs_execution_role_policy: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-csb-ecs-execution:dxw-pentest-dxwpentestpentestvonestaging-csb-ecs-execution-policy]
data.aws_route_table.private_subnet_route_table: Reading...
data.aws_subnet.extra_public[0]: Read complete after 0s [id=subnet-019286daa18327178]
aws_iam_role_policy_attachment.ecs_cluster_sql_backup_s3_policy: Refreshing state... [id=tf-ECSInRole-dxw-pentest-staging20250630094259383100000001-20250630133227029100000004]
data.aws_subnet.extra_public[2]: Read complete after 0s [id=subnet-0e6866a5f131efdeb]
aws_iam_role_policy.sql_backup_scheduled_task_ecs_role_allow_s3_policy: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-sb-ecs:dxw-pentest-dxwpentestpentestvonestaging-sb-ecs-allow-s3-policy]
aws_iam_role_policy.check_sql_backup_scheduled_task_cloudwatch_role_policy: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-csb-cw:dxw-pentest-dxwpentestpentestvonestaging-csb-cw-policy]
data.aws_route_table.private_subnet_route_table: Read complete after 1s [id=rtb-092cddc21bbb96803]
module.rds.module.db_subnet_group.aws_db_subnet_group.this[0]: Refreshing state... [id=dxwpentestpentestvonestaging-20250630133225841900000003]
aws_iam_role_policy.check_sql_backup_transfer_scheduled_task_ecs_role_allow_s3_policy: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-csb-ecs:dxw-pentest-dxwpentestpentestvonestaging-csbt-ecs-allow-s3-policy]
aws_iam_role_policy.check_sql_backup_scheduled_task_ecs_role_allow_s3_policy: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-csb-ecs:dxw-pentest-dxwpentestpentestvonestaging-csb-ecs-allow-s3-policy]
aws_ecs_task_definition.check_sql_backup_scheduled_task: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-csb-st]
aws_iam_role_policy.sql_backup_scheduled_task_ecs_execution_role_policy: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-sb-ecs-execution:dxw-pentest-dxwpentestpentestvonestaging-sb-ecs-execution-policy]
aws_iam_role_policy.sql_backup_scheduled_task_ecs_execution_role_ssm_policy: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-sb-ecs-execution:dxw-pentest-dxwpentestpentestvonestaging-sb-ecs-execution-ssm-policy]
aws_iam_role_policy.sql_backup_scheduled_task_cloudwatch_role_policy: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-sb-cw:dxw-pentest-dxwpentestpentestvonestaging-sb-cw-policy]
aws_cloudwatch_event_target.check_sql_backup_scheduled_task: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-csb-st-dxw-pentest-dxwpentestpentestvonestaging-csb-st-target]
module.rds.module.db_instance.aws_db_instance.this[0]: Refreshing state... [id=dxwpentestpentestvonestaging]
aws_ssm_document.rds_db_list: Refreshing state... [id=dxwpentestpentestvonestaging-rds-db-list]
aws_ssm_document.rds_sql_import: Refreshing state... [id=dxwpentestpentestvonestaging-rds-sql-import]
aws_ecs_task_definition.sql_backup_scheduled_task: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-sb-st]
aws_ssm_document.rds_sql_dump: Refreshing state... [id=dxwpentestpentestvonestaging-rds-sql-dump]
aws_ssm_document.rds_shell: Refreshing state... [id=dxwpentestpentestvonestaging-rds-shell]
aws_ssm_document.rds_db_creation: Refreshing state... [id=dxwpentestpentestvonestaging-rds-db-creation]
aws_cloudwatch_event_target.sql_backup_scheduled_task: Refreshing state... [id=dxw-pentest-dxwpentestpentestvonestaging-sb-st-dxw-pentest-dxwpentestpentestvonestaging-sb-st-target]

Note: Objects have changed outside of Terraform

Terraform detected the following changes made outside of
Terraform since the last "terraform apply" which may have
affected this plan:

  # module.rds.module.db_instance.aws_db_instance.this[0] has changed
  ~ resource "aws_db_instance" "this" {
      ~ engine_version_actual                 = "8.0.41" -> "8.0.42"
        id                                    = "dxwpentestpentestvonestaging"
        name                                  = "saluki"
        tags                                  = {}
        # (65 unchanged attributes hidden)

        # (1 unchanged block hidden)
    }


Unless you have made equivalent changes to your configuration,
or ignored the relevant attributes using ignore_changes, the
following plan may include actions to undo or respond to these
changes.

───────────────────────────────────────────────────────────────

Terraform used the selected providers to generate the following
execution plan. Resource actions are indicated with the
following symbols:
  + create

Terraform will perform the following actions:

  # aws_iam_policy.replication[0] will be created
  + resource "aws_iam_policy" "replication" {
      + arn         = (known after apply)
      + id          = (known after apply)
      + name        = "dxw-pentest-dxwpentestpentestvonestaging-sql-backup-replication-policy"
      + name_prefix = (known after apply)
      + path        = "/"
      + policy      = jsonencode(
            {
              + Statement = [
                  + {
                      + Action   = [
                          + "s3:GetReplicationConfiguration",
                          + "s3:ListBucket",
                        ]
                      + Effect   = "Allow"
                      + Resource = [
                          + "arn:aws:s3:::dxw-pentest-dxwpentestpentestvonestaging-sql-backup",
                        ]
                    },
                  + {
                      + Action   = [
                          + "s3:GetObjectVersionForReplication",
                          + "s3:GetObjectVersionAcl",
                          + "s3:GetObjectVersionTagging",
                        ]
                      + Effect   = "Allow"
                      + Resource = [
                          + "arn:aws:s3:::dxw-pentest-dxwpentestpentestvonestaging-sql-backup/*",
                        ]
                    },
                  + {
                      + Action   = [
                          + "s3:ReplicateObject",
                          + "s3:ReplicateDelete",
                          + "s3:ReplicateTags",
                          + "s3:ObjectOwnerOverrideToBucketOwner",
                        ]
                      + Effect   = "Allow"
                      + Resource = "arn:aws:s3:::wai4vub1-mtvh-replication-test/*"
                    },
                  + {
                      + Action    = [
                          + "kms:Decrypt",
                        ]
                      + Condition = {
                          + StringLike = {
                              + "kms:EncryptionContext:aws:s3:arn" = [
                                  + "arn:aws:s3:::dxw-pentest-dxwpentestpentestvonestaging-sql-backup/*",
                                ]
                              + "kms:ViaService"                   = "s3.eu-west-2.amazonaws.com"
                            }
                        }
                      + Effect    = "Allow"
                      + Resource  = "*"
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + policy_id   = (known after apply)
      + tags_all    = (known after apply)
    }

  # aws_iam_role.replication[0] will be created
  + resource "aws_iam_role" "replication" {
      + arn                   = (known after apply)
      + assume_role_policy    = jsonencode(
            {
              + Statement = [
                  + {
                      + Action    = "sts:AssumeRole"
                      + Effect    = "Allow"
                      + Principal = {
                          + Service = "s3.amazonaws.com"
                        }
                      + Sid       = ""
                    },
                ]
              + Version   = "2012-10-17"
            }
        )
      + create_date           = (known after apply)
      + force_detach_policies = false
      + id                    = (known after apply)
      + managed_policy_arns   = (known after apply)
      + max_session_duration  = 3600
      + name                  = "dxw-pentest-dxwpentestpentestvonestaging-sql-backup-replication"
      + name_prefix           = (known after apply)
      + path                  = "/"
      + role_last_used        = (known after apply)
      + tags_all              = (known after apply)
      + unique_id             = (known after apply)

      + inline_policy (known after apply)
    }

  # aws_iam_role_policy_attachment.replication[0] will be created
  + resource "aws_iam_role_policy_attachment" "replication" {
      + id         = (known after apply)
      + policy_arn = (known after apply)
      + role       = "dxw-pentest-dxwpentestpentestvonestaging-sql-backup-replication"
    }

  # aws_s3_bucket_replication_configuration.sql_backups[0] will be created
  + resource "aws_s3_bucket_replication_configuration" "sql_backups" {
      + bucket = "dxw-pentest-dxwpentestpentestvonestaging-sql-backup"
      + id     = (known after apply)
      + role   = (known after apply)

      + rule {
          + id     = "replication"
          + status = "Enabled"

          + destination {
              + bucket        = "arn:aws:s3:::wai4vub1-mtvh-replication-test"
              + storage_class = "STANDARD"

              + access_control_translation {
                  + owner = "Destination"
                }
            }

          + source_selection_criteria {
              + sse_kms_encrypted_objects {
                  + status = "Enabled"
                }
            }
        }
    }

  # aws_s3_bucket_versioning.sql_backups[0] will be created
  + resource "aws_s3_bucket_versioning" "sql_backups" {
      + bucket = "dxw-pentest-dxwpentestpentestvonestaging-sql-backup"
      + id     = (known after apply)

      + versioning_configuration {
          + mfa_delete = (known after apply)
          + status     = "Enabled"
        }
    }

Plan: 5 to add, 0 to change, 0 to destroy.

───────────────────────────────────────────────────────────────

Note: You didn't use the -out option to save this plan, so
Terraform can't guarantee to take exactly these actions if you
run "terraform apply" now.
Process Group PGID: 67132