diff --git a/README.md b/README.md index 6457e31..47bd123 100644 --- a/README.md +++ b/README.md @@ -52,138 +52,13 @@ go test -v -timeout 30m -run TestHelloWorldAppExample go test -v -timeout 30m -parallel 2 ``` -## Dir structure +### Integration tests + +For testing multiple modules in the staging environment, extract the state S3 config into a separate file. +This will prevent overwriting the state file and can be used manually: ```bash -[4.0K] ./ -├── [4.0K] global/ -│ ├── [4.0K] ghAction/ -│ │ ├── [1.6K] main.tf -│ │ ├── [ 535] outputs.tf -│ │ ├── [ 411] terraform.tf -│ │ ├── [ 992] tf-apply.yml -│ │ └── [ 308] variables.tf -│ ├── [4.0K] iam/ -│ │ ├── [1.2K] main.tf -│ │ ├── [1.7K] outputs.tf -│ │ ├── [ 375] terraform.tf -│ │ └── [ 472] variables.tf -│ └── [4.0K] s3/ -│ ├── [ 930] main.tf -│ ├── [ 259] outputs.tf -│ ├── [ 374] terraform.tf -│ └── [ 330] variables.tf -├── [4.0K] modules/ -│ ├── [4.0K] examples/ -│ │ ├── [4.0K] alb/ -│ │ │ ├── [ 207] dependencies.tf -│ │ │ ├── [ 177] main.tf -│ │ │ ├── [ 382] outputs.tf -│ │ │ ├── [ 320] terraform.tf -│ │ │ ├── [5.9K] terraform.tfstate -│ │ │ ├── [ 181] terraform.tfstate.backup -│ │ │ └── [ 116] variables.tf -│ │ ├── [4.0K] asg/ -│ │ │ └── [4.0K] one-instance/ -│ │ │ ├── [ 439] dependencies.tf -│ │ │ ├── [ 370] main.tf -│ │ │ ├── [ 111] outputs.tf -│ │ │ ├── [ 321] terraform.tf -│ │ │ └── [ 79] variables.tf -│ │ └── [4.0K] hello-world-app/ -│ │ └── [4.0K] standalone/ -│ │ ├── [ 721] dependencies.tf -│ │ ├── [ 422] main.tf -│ │ ├── [ 109] outputs.tf -│ │ ├── [ 319] terraform.tf -│ │ ├── [ 29K] terraform.tfstate -│ │ ├── [1.0K] terraform.tfstate.backup -│ │ └── [ 625] variables.tf -│ ├── [4.0K] modules/ -│ │ ├── [4.0K] cluster/ -│ │ │ └── [4.0K] asg-rolling-deploy/ -│ │ │ ├── [ 80] dependencies.tf -│ │ │ ├── [3.5K] main.tf -│ │ │ ├── [ 274] outputs.tf -│ │ │ ├── [ 159] terraform.tf -│ │ │ └── [1.9K] variables.tf -│ │ ├── [4.0K] data-stores/ -│ │ │ └── [4.0K] mysql/ -│ │ │ ├── [ 669] main.tf -│ │ │ ├── [ 338] outputs.tf -│ │ │ ├── [ 159] terraform.tf -│ │ │ └── [1.3K] variables.tf -│ │ ├── [4.0K] eks-cluster/ -│ │ │ ├── [ 233] dependencies.tf -│ │ │ ├── [2.3K] main.tf -│ │ │ ├── [ 517] outputs.tf -│ │ │ ├── [ 159] terraform.tf -│ │ │ └── [ 583] variables.tf -│ │ ├── [4.0K] k8s/ -│ │ │ ├── [1.3K] main.tf -│ │ │ ├── [ 368] outputs.tf -│ │ │ ├── [ 159] terraform.tf -│ │ │ └── [ 662] variables.tf -│ │ ├── [4.0K] networking/ -│ │ │ └── [4.0K] alb/ -│ │ │ ├── [1.2K] main.tf -│ │ │ ├── [ 367] outputs.tf -│ │ │ ├── [ 158] terraform.tf -│ │ │ └── [ 187] variables.tf -│ │ └── [4.0K] services/ -│ │ └── [4.0K] hello-world-app/ -│ │ ├── [ 797] dependencies.tf -│ │ ├── [1.4K] main.tf -│ │ ├── [ 389] outputs.tf -│ │ ├── [ 159] terraform.tf -│ │ ├── [ 168] user-data.sh -│ │ └── [2.0K] variables.tf -│ └── [4.0K] test/ -│ ├── [ 870] alb_example_test.go -│ ├── [2.6K] go.mod -│ ├── [ 94K] go.sum -│ └── [1.0K] hello_world_test.go -├── [4.0K] packer/ -│ ├── [ 576] webserver.json -│ └── [ 724] webserver.json.pkr.hcl -├── [4.0K] prod/ -│ ├── [4.0K] data-stores/ -│ │ └── [4.0K] mysql/ -│ │ ├── [ 626] main.tf -│ │ ├── [ 783] output.tf -│ │ ├── [ 712] terraform.tf -│ │ └── [ 265] variables.tf -│ └── [4.0K] services/ -│ ├── [4.0K] eks-cluster/ -│ │ ├── [ 81] dependencies.tf -│ │ ├── [ 693] main.tf -│ │ ├── [ 257] outputs.tf -│ │ └── [ 776] terraform.tf -│ └── [4.0K] hello-world-app/ -│ ├── [ 202] dependencies.tf -│ ├── [ 572] main.tf -│ ├── [ 111] outputs.tf -│ └── [ 538] terraform.tf -├── [4.0K] stage/ -│ ├── [4.0K] data-stores/ -│ │ └── [4.0K] mysql/ -│ │ ├── [ 389] main.tf -│ │ ├── [ 337] output.tf -│ │ ├── [ 648] terraform.tf -│ │ └── [ 266] variables.tf -│ └── [4.0K] services/ -│ ├── [4.0K] hello-world-app/ -│ │ ├── [ 202] dependencies.tf -│ │ ├── [ 587] main.tf -│ │ ├── [ 109] outputs.tf -│ │ └── [ 656] terraform.tf -│ └── [4.0K] k8s/ -│ ├── [ 420] main.tf -│ ├── [ 127] outputs.tf -│ └── [ 571] terraform.tf -├── [1.0K] LICENSE.txt -├── [5.7K] README.md -└── [ 180] terraform.tfstate +terraform init -backend-config=backend.hcl ``` ## License diff --git a/modules/modules/services/hello-world-app/variables.tf b/modules/modules/services/hello-world-app/variables.tf index fc2e07a..b90e081 100644 --- a/modules/modules/services/hello-world-app/variables.tf +++ b/modules/modules/services/hello-world-app/variables.tf @@ -19,7 +19,7 @@ variable "db_remote_state_key" { variable "server_text" { description = "Text the web server should return" type = string - default = "Hello World tag 0.1.1" + default = "Hello, World" } variable "environment" { diff --git a/modules/test/hello_world_integration_test.go b/modules/test/hello_world_integration_test.go new file mode 100644 index 0000000..0d99610 --- /dev/null +++ b/modules/test/hello_world_integration_test.go @@ -0,0 +1,88 @@ +package test + +import ( + "fmt" + "strings" + "testing" + "time" + + "github.com/gruntwork-io/terratest/modules/http-helper" + "github.com/gruntwork-io/terratest/modules/random" + "github.com/gruntwork-io/terratest/modules/terraform" +) + +const ( + dbDirStage = "../../stage/data-stores/mysql/" + appDirStage = "../../stage/services/hello-world-app/" +) + +func TestHelloWorldAppStage(t *testing.T) { + t.Parallel() + + dbOpts := createDbOpts(t, dbDirStage) + defer terraform.Destroy(t, dbOpts) + terraform.InitAndApply(t, dbOpts) + + helloOpts := createHelloOpts(dbOpts, appDirStage) + defer terraform.Destroy(t, helloOpts) + terraform.InitAndApply(t, helloOpts) + + validateHelloApp(t, helloOpts) +} + +func createDbOpts(t *testing.T, terraformDir string) *terraform.Options { + uniqueId := random.UniqueId() + bucketTesting := "tf-state-ujstor" + bucketRegionTesting := "us-east-1" + dynamodbTable := "terraform-state-locks" + + dbStateKey := fmt.Sprintf("%s/%s/terraform.tfstate", t.Name(), uniqueId) + + return &terraform.Options{ + TerraformDir: terraformDir, + + Vars: map[string]interface{}{ + "db_name": fmt.Sprintf("testdb%s", uniqueId), + "db_username": "admin", + "db_password": "password", + }, + BackendConfig: map[string]interface{}{ + "bucket": bucketTesting, + "region": bucketRegionTesting, + "key": dbStateKey, + "dynamodb_table": dynamodbTable, + "encrypt": true, + }, + } +} + +func createHelloOpts(dbOpts *terraform.Options, terraformDir string) *terraform.Options { + return &terraform.Options{ + TerraformDir: terraformDir, + + Vars: map[string]interface{}{ + "db_remote_state_bucket": dbOpts.BackendConfig["bucket"], + "db_remote_state_key": dbOpts.BackendConfig["key"], + "environment": dbOpts.Vars["db_name"], + }, + } +} + +func validateHelloApp(t *testing.T, helloOpts *terraform.Options) { + albDnsName := terraform.OutputRequired(t, helloOpts, "alb_dns_name") + url := fmt.Sprintf("http://%s", albDnsName) + maxRetries := 10 + timeBetweenRetries := 10 * time.Second + + http_helper.HttpGetWithRetryWithCustomValidation( + t, + url, + nil, + maxRetries, + timeBetweenRetries, + func(status int, body string) bool { + return status == 200 && + strings.Contains(body, "Hello, World") + }, + ) +} diff --git a/stage/data-stores/mysql/.terraform.lock.hcl b/stage/data-stores/mysql/.terraform.lock.hcl index 78d3c55..fe5a966 100644 --- a/stage/data-stores/mysql/.terraform.lock.hcl +++ b/stage/data-stores/mysql/.terraform.lock.hcl @@ -2,24 +2,24 @@ # Manual edits may be lost in future updates. provider "registry.terraform.io/hashicorp/aws" { - version = "4.67.0" - constraints = "~> 4.0" + version = "5.54.1" + constraints = "~> 5.0" hashes = [ - "h1:dCRc4GqsyfqHEMjgtlM1EympBcgTmcTkWaJmtd91+KA=", - "zh:0843017ecc24385f2b45f2c5fce79dc25b258e50d516877b3affee3bef34f060", - "zh:19876066cfa60de91834ec569a6448dab8c2518b8a71b5ca870b2444febddac6", - "zh:24995686b2ad88c1ffaa242e36eee791fc6070e6144f418048c4ce24d0ba5183", - "zh:4a002990b9f4d6d225d82cb2fb8805789ffef791999ee5d9cb1fef579aeff8f1", - "zh:559a2b5ace06b878c6de3ecf19b94fbae3512562f7a51e930674b16c2f606e29", - "zh:6a07da13b86b9753b95d4d8218f6dae874cf34699bca1470d6effbb4dee7f4b7", - "zh:768b3bfd126c3b77dc975c7c0e5db3207e4f9997cf41aa3385c63206242ba043", - "zh:7be5177e698d4b547083cc738b977742d70ed68487ce6f49ecd0c94dbf9d1362", - "zh:8b562a818915fb0d85959257095251a05c76f3467caa3ba95c583ba5fe043f9b", + "h1:SOdZNOAcBvbrkV6V1S7UiGh9K//O66qfyXpHgyXeBeI=", + "zh:37c09b9a0a0a2f7854fe52c6adb15f71593810b458a8283ed71d68036af7ba3a", + "zh:42fe11d87723d4e43b9c6224ae6bacdcb53faee8abc58f0fc625a161d1f71cb1", + "zh:57c6dfc46f28c9c2737559bd84acbc05aeae90431e731bb72a0024028a2d2412", + "zh:5ba9665a4ca0e182effd75575b19a4d47383ec02662024b9fe26f78286c36619", "zh:9b12af85486a96aedd8d7984b0ff811a4b42e3d88dad1a3fb4c0b580d04fa425", - "zh:9c385d03a958b54e2afd5279cd8c7cbdd2d6ca5c7d6a333e61092331f38af7cf", - "zh:b3ca45f2821a89af417787df8289cb4314b273d29555ad3b2a5ab98bb4816b3b", - "zh:da3c317f1db2469615ab40aa6baba63b5643bae7110ff855277a1fb9d8eb4f2c", - "zh:dc6430622a8dc5cdab359a8704aec81d3825ea1d305bbb3bbd032b1c6adfae0c", - "zh:fac0d2ddeadf9ec53da87922f666e1e73a603a611c57bcbc4b86ac2821619b1d", + "zh:b55980be0237644123a02a30b56d4cc03863ef29036c47d6e8ab5429ab45adf5", + "zh:b81e7664f10855a3a6fc234a18b4c4f1456273126a40c41516f2061696fb9870", + "zh:bd09736ffafd92af104c3c34b5add138ae8db4402eb687863ce472ca7e5ff2e2", + "zh:cc2eb1c62fba2a11d1f239e650cc2ae94bcab01c907384dcf2e213a6ee1bd5b2", + "zh:e5dc40205d9cf6f353c0ca532ae29afc6c83928bc9bcca47d74b640d3bb5a38c", + "zh:ebf1acdcd13f10db1b9c85050ddaadc70ab269c47c5a240753362446442d8371", + "zh:f2fc28a4ad94af5e6144a7309286505e3eb7a94d9dc106722b506c372ff7f591", + "zh:f49445e8435944df122aa89853260a2716ba8b73d6a6a70cae1661554926d5a2", + "zh:fc3b5046e60ae7cab20715be23de8436eb12736136fd6d0f0cc1549ebda6cc73", + "zh:fdb98a53500e245a3b5bec077b994da6959dba8fc4eb7534528658d820e06bd5", ] } diff --git a/stage/data-stores/mysql/backend.hcl b/stage/data-stores/mysql/backend.hcl new file mode 100644 index 0000000..52e3964 --- /dev/null +++ b/stage/data-stores/mysql/backend.hcl @@ -0,0 +1,5 @@ +bucket = "tf-state-ujstor" +key = "stage/data-stores/mysql/terraform.tfstate" +region = "us-east-1" +dynamodb_table = "terraform-state-locks" +encrypt = true diff --git a/stage/data-stores/mysql/main.tf b/stage/data-stores/mysql/main.tf index ae33b2a..4cdd6e9 100644 --- a/stage/data-stores/mysql/main.tf +++ b/stage/data-stores/mysql/main.tf @@ -1,6 +1,6 @@ module "mysql_db_stage" { - source = "github.com/ujstor/aws-terraform//modules/modules/data-stores/mysql?ref=v0.1.3" - # source = "../../../modules/modules/data-stores/mysql" + # source = "github.com/ujstor/aws-terraform//modules/modules/data-stores/mysql?ref=v0.1.3" + source = "../../../modules/modules/data-stores/mysql" providers = { aws = aws.stage @@ -8,8 +8,8 @@ module "mysql_db_stage" { identifier_prefix = "stage-mysql" instance_class = "db.t3.micro" - db_name = "stageDB" + db_name = var.db_name db_username = var.db_username db_password = var.db_password } diff --git a/stage/data-stores/mysql/terraform.tf b/stage/data-stores/mysql/terraform.tf index 4927685..326adbc 100644 --- a/stage/data-stores/mysql/terraform.tf +++ b/stage/data-stores/mysql/terraform.tf @@ -1,10 +1,5 @@ terraform { backend "s3" { - bucket = "tf-state-ujstor" - key = "stage/data-stores/mysql/terraform.tfstate" - region = "us-east-1" - dynamodb_table = "terraform-state-locks" - encrypt = true } required_providers { aws = { diff --git a/stage/data-stores/mysql/variables.tf b/stage/data-stores/mysql/variables.tf index bab1585..2476b81 100644 --- a/stage/data-stores/mysql/variables.tf +++ b/stage/data-stores/mysql/variables.tf @@ -10,3 +10,8 @@ variable "db_password" { sensitive = true } +variable "db_name" { + description = "Name of the database to create" + type = string + default = "stageDb" +} diff --git a/stage/services/hello-world-app/backend.hcl b/stage/services/hello-world-app/backend.hcl new file mode 100644 index 0000000..6c24a87 --- /dev/null +++ b/stage/services/hello-world-app/backend.hcl @@ -0,0 +1,5 @@ +bucket = "tf-state-ujstor" +key = "stage/services/webserver-cluster/terraform.tfstate" +region = "us-east-1" +dynamodb_table = "terraform-state-locks" +encrypt = true diff --git a/stage/services/hello-world-app/main.tf b/stage/services/hello-world-app/main.tf index 65b0c06..ae5f847 100644 --- a/stage/services/hello-world-app/main.tf +++ b/stage/services/hello-world-app/main.tf @@ -1,17 +1,17 @@ module "hello-world-app" { - source = "github.com/ujstor/aws-terraform//modules/modules/services/hello-world-app?ref=v0.1.3" - # source = "../../../modules/modules/services/hello-world-app/" + # source = "github.com/ujstor/aws-terraform//modules/modules/services/hello-world-app?ref=v0.1.3" + source = "../../../modules/modules/services/hello-world-app/" providers = { aws = aws.stage } - environment = "stage" + environment = var.environment image_id = data.aws_ami.ubuntu.id instance_type = "t2.micro" - db_remote_state_bucket = "tf-state-ujstor" - db_remote_state_key = "stage/data-stores/mysql/terraform.tfstate" + db_remote_state_bucket = var.db_remote_state_bucket + db_remote_state_key = var.db_remote_state_key min_size = 2 max_size = 5 diff --git a/stage/services/hello-world-app/variables.tf b/stage/services/hello-world-app/variables.tf new file mode 100644 index 0000000..f32aa3e --- /dev/null +++ b/stage/services/hello-world-app/variables.tf @@ -0,0 +1,15 @@ +variable "environment" { + description = "The name of the environment we're deploying to" + type = string + default = "stage" +} + +variable "db_remote_state_bucket" { + description = "The name of the S3 bucket for the database's remote state" + type = string +} + +variable "db_remote_state_key" { + description = "The path for the database's remote state in S3" + type = string +}