From 8dd76c7053a57cf83d0bfa150ca5902085cae849 Mon Sep 17 00:00:00 2001 From: Robert Hutto Date: Mon, 17 Aug 2020 21:22:41 -0400 Subject: [PATCH] fixed issue #206 * added inital tf-test, a groovy fluent api library for testing Terraform * added Example of using tf-cmd-api show command to write pre-provision test similar to sentinel using groovy and spock authored-by: robert --- examples/tf-s3/pom.xml | 5 + .../src/main/tf/s3_sentinel_demo/main.tf | 31 + .../test/groovy/tf/s3/S3SentinelSpec.groovy | 63 ++ .../tf-s3/src/test/groovy/tf/s3/S3Spec.groovy | 2 - .../src/test/resources/tf_show_example.json | 945 ++++++++++++++++++ tf-build-tools/pom.xml | 3 +- tf-build-tools/tf-cmd-api/pom.xml | 4 +- .../terraform/TerraformUtils.java | 5 +- .../terraform/api/TerraformShow.java | 8 +- .../terraform/api/TerraformCleanTest.java | 2 +- tf-build-tools/tf-maven-plugin/pom.xml | 4 +- tf-build-tools/tf-s3-archetype/pom.xml | 2 +- tf-build-tools/tf-test/pom.xml | 156 +++ .../terraform/fluent/api/Terraform.groovy | 67 ++ .../terraform/fluent/api/TfPlan.groovy | 27 + .../terraform/fluent/api/TfState.groovy | 14 + .../terraform/fluent/api/TerraformSpec.groovy | 44 + .../terraform/fluent/api/TfPlanTest.groovy | 42 + .../terraform/fluent/api/TfStateTest.groovy | 16 + .../tf-test/src/test/resources/tf/main.tf | 3 + .../src/test/resources/tf_show_example.json | 945 ++++++++++++++++++ 21 files changed, 2369 insertions(+), 19 deletions(-) create mode 100644 examples/tf-s3/src/main/tf/s3_sentinel_demo/main.tf create mode 100644 examples/tf-s3/src/test/groovy/tf/s3/S3SentinelSpec.groovy create mode 100644 examples/tf-s3/src/test/resources/tf_show_example.json create mode 100644 tf-build-tools/tf-test/pom.xml create mode 100644 tf-build-tools/tf-test/src/main/groovy/com/deliveredtechnologies/terraform/fluent/api/Terraform.groovy create mode 100644 tf-build-tools/tf-test/src/main/groovy/com/deliveredtechnologies/terraform/fluent/api/TfPlan.groovy create mode 100644 tf-build-tools/tf-test/src/main/groovy/com/deliveredtechnologies/terraform/fluent/api/TfState.groovy create mode 100644 tf-build-tools/tf-test/src/test/groovy/com/deliveredtechnologies/terraform/fluent/api/TerraformSpec.groovy create mode 100644 tf-build-tools/tf-test/src/test/groovy/com/deliveredtechnologies/terraform/fluent/api/TfPlanTest.groovy create mode 100644 tf-build-tools/tf-test/src/test/groovy/com/deliveredtechnologies/terraform/fluent/api/TfStateTest.groovy create mode 100644 tf-build-tools/tf-test/src/test/resources/tf/main.tf create mode 100644 tf-build-tools/tf-test/src/test/resources/tf_show_example.json diff --git a/examples/tf-s3/pom.xml b/examples/tf-s3/pom.xml index 0bed9693..a082367b 100644 --- a/examples/tf-s3/pom.xml +++ b/examples/tf-s3/pom.xml @@ -27,6 +27,11 @@ tf-cmd-api ${tf-maven-version} + + com.deliveredtechnologies + tf-test + ${tf-maven-version} + org.codehaus.groovy diff --git a/examples/tf-s3/src/main/tf/s3_sentinel_demo/main.tf b/examples/tf-s3/src/main/tf/s3_sentinel_demo/main.tf new file mode 100644 index 00000000..348c7e71 --- /dev/null +++ b/examples/tf-s3/src/main/tf/s3_sentinel_demo/main.tf @@ -0,0 +1,31 @@ +provider "aws" { + region = "us-east-1" +} + +resource "aws_s3_bucket" "bucket1" { + bucket = "bucket1" + + versioning { + enabled = true + } + + tags = { + application_id = "cna" + stack_name = "stacked" + created_by = "rhutto@deliveredtech.com" + } +} + +resource "aws_s3_bucket" "bucket2" { + bucket = "bucket2" + + versioning { + enabled = true + } + + tags = { + application_id = "cna" + stack_name = "stacked" + created_by = "rhutto@deliveredtech.com" + } +} diff --git a/examples/tf-s3/src/test/groovy/tf/s3/S3SentinelSpec.groovy b/examples/tf-s3/src/test/groovy/tf/s3/S3SentinelSpec.groovy new file mode 100644 index 00000000..bf1cf2d0 --- /dev/null +++ b/examples/tf-s3/src/test/groovy/tf/s3/S3SentinelSpec.groovy @@ -0,0 +1,63 @@ +package tf.s3 + + +import com.deliveredtechnologies.terraform.fluent.api.Terraform +import com.deliveredtechnologies.terraform.fluent.api.TfPlan +import spock.lang.Shared +import spock.lang.Specification +import spock.lang.Unroll + +class S3SentinelSpec extends Specification { + + @Shared + TfPlan tfplan; + @Shared + mandatory_tags = [ + "application_id", + "stack_name", + "created_by", + ] + + @Unroll("#s3Bucket.address has all the mandatory tags") + def "S3 resources have all mandatory tags"() { + + expect: + hasMandatoryTags(s3Bucket) + + where: + s3Bucket << tfplan.getResourcesByType("aws_s3_bucket") + } + + @Unroll("#s3Bucket.address versioning enabled == true") + def "S3 versioning enabled"() { + + expect: + isVersioningEnabled(s3Bucket) + + where: + s3Bucket << tfplan.getResourcesByType("aws_s3_bucket") + } + + void isVersioningEnabled(Map resource) { + Map m = resource.change.after + assert m.containsKey("versioning") + assert m.versioning[0].enabled == true + } + + void hasMandatoryTags(Map resource) { + mandatory_tags.each {tag -> + Map resourceTags = resource.change.after.tags + assert resourceTags.containsKey(tag) + } + } + + def setupSpec() { + + Terraform terraform = new Terraform().withRootDir('s3_sentinel_demo') + .withProperties([ + noColor: true, + ]) + tfplan = terraform.initAndPlan() + } + +} diff --git a/examples/tf-s3/src/test/groovy/tf/s3/S3Spec.groovy b/examples/tf-s3/src/test/groovy/tf/s3/S3Spec.groovy index 78ad2e27..585d3556 100644 --- a/examples/tf-s3/src/test/groovy/tf/s3/S3Spec.groovy +++ b/examples/tf-s3/src/test/groovy/tf/s3/S3Spec.groovy @@ -6,8 +6,6 @@ import com.deliveredtechnologies.terraform.api.TerraformApply import com.deliveredtechnologies.terraform.api.TerraformDestroy import com.deliveredtechnologies.terraform.api.TerraformInit import com.deliveredtechnologies.terraform.api.TerraformOutput -import com.deliveredtechnologies.terraform.api.TerraformPlan -import groovy.json.JsonOutput import groovy.json.JsonSlurper import spock.lang.Specification diff --git a/examples/tf-s3/src/test/resources/tf_show_example.json b/examples/tf-s3/src/test/resources/tf_show_example.json new file mode 100644 index 00000000..df4c43eb --- /dev/null +++ b/examples/tf-s3/src/test/resources/tf_show_example.json @@ -0,0 +1,945 @@ +{ + "format_version": "0.1", + "terraform_version": "0.12.25", + "variables": { + "bucket_name": { + "value": "" + }, + "environment": { + "value": "dev" + }, + "is_versioned": { + "value": "false" + }, + "kms_key_arn": { + "value": "" + }, + "region": { + "value": "us-east-1" + } + }, + "planned_values": { + "outputs": { + "bucket": { + "sensitive": false, + "value": { + "acceleration_status": "", + "acl": "private", + "arn": "arn:aws:s3:::bucket-bb8937d0c3d09cab", + "bucket": "bucket-bb8937d0c3d09cab", + "bucket_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "bucket_prefix": null, + "bucket_regional_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "cors_rule": [], + "force_destroy": true, + "grant": [], + "hosted_zone_id": "Z3AQBSTGFYJSTF", + "id": "bucket-bb8937d0c3d09cab", + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "policy": null, + "region": "us-east-1", + "replication_configuration": [], + "request_payer": "BucketOwner", + "server_side_encryption_configuration": [], + "tags": { + "environment": "dev" + }, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [], + "website_domain": null, + "website_endpoint": null + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_s3_bucket.bucket", + "mode": "managed", + "type": "aws_s3_bucket", + "name": "bucket", + "provider_name": "aws", + "schema_version": 0, + "values": { + "acceleration_status": "", + "acl": "private", + "arn": "arn:aws:s3:::bucket-bb8937d0c3d09cab", + "bucket": "bucket-bb8937d0c3d09cab", + "bucket_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "bucket_prefix": null, + "bucket_regional_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "cors_rule": [], + "force_destroy": true, + "grant": [], + "hosted_zone_id": "Z3AQBSTGFYJSTF", + "id": "bucket-bb8937d0c3d09cab", + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "policy": null, + "region": "us-east-1", + "replication_configuration": [], + "request_payer": "BucketOwner", + "server_side_encryption_configuration": [], + "tags": { + "environment": "dev" + }, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [], + "website_domain": null, + "website_endpoint": null + } + }, + { + "address": "random_id.bucket_name", + "mode": "managed", + "type": "random_id", + "name": "bucket_name", + "provider_name": "random", + "schema_version": 0, + "values": { + "b64": "bucket-u4k30MPQnKs", + "b64_std": "bucket-u4k30MPQnKs=", + "b64_url": "bucket-u4k30MPQnKs", + "byte_length": 8, + "dec": "bucket-13513393526679837867", + "hex": "bucket-bb8937d0c3d09cab", + "id": "u4k30MPQnKs", + "keepers": null, + "prefix": "bucket-" + } + } + ], + "child_modules": [ + { + "resources": [ + { + "address": "module.pet.random_pet.pet", + "mode": "managed", + "type": "random_pet", + "name": "pet", + "provider_name": "random", + "schema_version": 0, + "values": { + "id": "proud-caribou", + "keepers": null, + "length": 2, + "prefix": null, + "separator": "-" + } + } + ], + "address": "module.pet", + "child_modules": [ + { + "resources": [ + { + "address": "module.pet.module.bar.random_integer.random", + "mode": "managed", + "type": "random_integer", + "name": "random", + "provider_name": "random", + "schema_version": 0, + "values": { + "id": "6", + "keepers": null, + "max": 10, + "min": 0, + "result": 6, + "seed": null + } + } + ], + "address": "module.pet.module.bar" + } + ] + }, + { + "resources": [ + { + "address": "module.pet2.random_pet.pet", + "mode": "managed", + "type": "random_pet", + "name": "pet", + "provider_name": "random", + "schema_version": 0, + "values": { + "id": "touched-monster", + "keepers": null, + "length": 2, + "prefix": null, + "separator": "-" + } + } + ], + "address": "module.pet2", + "child_modules": [ + { + "resources": [ + { + "address": "module.pet2.module.bar.random_integer.random", + "mode": "managed", + "type": "random_integer", + "name": "random", + "provider_name": "random", + "schema_version": 0, + "values": { + "id": "9", + "keepers": null, + "max": 10, + "min": 0, + "result": 9, + "seed": null + } + } + ], + "address": "module.pet2.module.bar" + } + ] + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_s3_bucket.bucket", + "mode": "managed", + "type": "aws_s3_bucket", + "name": "bucket", + "provider_name": "aws", + "change": { + "actions": [ + "no-op" + ], + "before": { + "acceleration_status": "", + "acl": "private", + "arn": "arn:aws:s3:::bucket-bb8937d0c3d09cab", + "bucket": "bucket-bb8937d0c3d09cab", + "bucket_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "bucket_prefix": null, + "bucket_regional_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "cors_rule": [], + "force_destroy": true, + "grant": [], + "hosted_zone_id": "Z3AQBSTGFYJSTF", + "id": "bucket-bb8937d0c3d09cab", + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "policy": null, + "region": "us-east-1", + "replication_configuration": [], + "request_payer": "BucketOwner", + "server_side_encryption_configuration": [], + "tags": { + "environment": "dev" + }, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [], + "website_domain": null, + "website_endpoint": null + }, + "after": { + "acceleration_status": "", + "acl": "private", + "arn": "arn:aws:s3:::bucket-bb8937d0c3d09cab", + "bucket": "bucket-bb8937d0c3d09cab", + "bucket_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "bucket_prefix": null, + "bucket_regional_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "cors_rule": [], + "force_destroy": true, + "grant": [], + "hosted_zone_id": "Z3AQBSTGFYJSTF", + "id": "bucket-bb8937d0c3d09cab", + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "policy": null, + "region": "us-east-1", + "replication_configuration": [], + "request_payer": "BucketOwner", + "server_side_encryption_configuration": [], + "tags": { + "environment": "dev" + }, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [], + "website_domain": null, + "website_endpoint": null + }, + "after_unknown": {} + } + }, + { + "address": "module.pet.module.bar.random_integer.random", + "module_address": "module.pet.module.bar", + "mode": "managed", + "type": "random_integer", + "name": "random", + "provider_name": "random", + "change": { + "actions": [ + "no-op" + ], + "before": { + "id": "6", + "keepers": null, + "max": 10, + "min": 0, + "result": 6, + "seed": null + }, + "after": { + "id": "6", + "keepers": null, + "max": 10, + "min": 0, + "result": 6, + "seed": null + }, + "after_unknown": {} + } + }, + { + "address": "module.pet.random_pet.pet", + "module_address": "module.pet", + "mode": "managed", + "type": "random_pet", + "name": "pet", + "provider_name": "random", + "change": { + "actions": [ + "no-op" + ], + "before": { + "id": "proud-caribou", + "keepers": null, + "length": 2, + "prefix": null, + "separator": "-" + }, + "after": { + "id": "proud-caribou", + "keepers": null, + "length": 2, + "prefix": null, + "separator": "-" + }, + "after_unknown": {} + } + }, + { + "address": "module.pet2.module.bar.random_integer.random", + "module_address": "module.pet2.module.bar", + "mode": "managed", + "type": "random_integer", + "name": "random", + "provider_name": "random", + "change": { + "actions": [ + "no-op" + ], + "before": { + "id": "9", + "keepers": null, + "max": 10, + "min": 0, + "result": 9, + "seed": null + }, + "after": { + "id": "9", + "keepers": null, + "max": 10, + "min": 0, + "result": 9, + "seed": null + }, + "after_unknown": {} + } + }, + { + "address": "module.pet2.random_pet.pet", + "module_address": "module.pet2", + "mode": "managed", + "type": "random_pet", + "name": "pet", + "provider_name": "random", + "change": { + "actions": [ + "no-op" + ], + "before": { + "id": "touched-monster", + "keepers": null, + "length": 2, + "prefix": null, + "separator": "-" + }, + "after": { + "id": "touched-monster", + "keepers": null, + "length": 2, + "prefix": null, + "separator": "-" + }, + "after_unknown": {} + } + }, + { + "address": "random_id.bucket_name", + "mode": "managed", + "type": "random_id", + "name": "bucket_name", + "provider_name": "random", + "change": { + "actions": [ + "no-op" + ], + "before": { + "b64": "bucket-u4k30MPQnKs", + "b64_std": "bucket-u4k30MPQnKs=", + "b64_url": "bucket-u4k30MPQnKs", + "byte_length": 8, + "dec": "bucket-13513393526679837867", + "hex": "bucket-bb8937d0c3d09cab", + "id": "u4k30MPQnKs", + "keepers": null, + "prefix": "bucket-" + }, + "after": { + "b64": "bucket-u4k30MPQnKs", + "b64_std": "bucket-u4k30MPQnKs=", + "b64_url": "bucket-u4k30MPQnKs", + "byte_length": 8, + "dec": "bucket-13513393526679837867", + "hex": "bucket-bb8937d0c3d09cab", + "id": "u4k30MPQnKs", + "keepers": null, + "prefix": "bucket-" + }, + "after_unknown": {} + } + } + ], + "output_changes": { + "bucket": { + "actions": [ + "create" + ], + "before": null, + "after": { + "acceleration_status": "", + "acl": "private", + "arn": "arn:aws:s3:::bucket-bb8937d0c3d09cab", + "bucket": "bucket-bb8937d0c3d09cab", + "bucket_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "bucket_prefix": null, + "bucket_regional_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "cors_rule": [], + "force_destroy": true, + "grant": [], + "hosted_zone_id": "Z3AQBSTGFYJSTF", + "id": "bucket-bb8937d0c3d09cab", + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "policy": null, + "region": "us-east-1", + "replication_configuration": [], + "request_payer": "BucketOwner", + "server_side_encryption_configuration": [], + "tags": { + "environment": "dev" + }, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [], + "website_domain": null, + "website_endpoint": null + }, + "after_unknown": false + } + }, + "prior_state": { + "format_version": "0.1", + "terraform_version": "0.12.25", + "values": { + "outputs": { + "bucket": { + "sensitive": false, + "value": { + "acceleration_status": "", + "acl": "private", + "arn": "arn:aws:s3:::bucket-bb8937d0c3d09cab", + "bucket": "bucket-bb8937d0c3d09cab", + "bucket_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "bucket_prefix": null, + "bucket_regional_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "cors_rule": [], + "force_destroy": true, + "grant": [], + "hosted_zone_id": "Z3AQBSTGFYJSTF", + "id": "bucket-bb8937d0c3d09cab", + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "policy": null, + "region": "us-east-1", + "replication_configuration": [], + "request_payer": "BucketOwner", + "server_side_encryption_configuration": [], + "tags": { + "environment": "dev" + }, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [], + "website_domain": null, + "website_endpoint": null + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_s3_bucket.bucket", + "mode": "managed", + "type": "aws_s3_bucket", + "name": "bucket", + "provider_name": "aws", + "schema_version": 0, + "values": { + "acceleration_status": "", + "acl": "private", + "arn": "arn:aws:s3:::bucket-bb8937d0c3d09cab", + "bucket": "bucket-bb8937d0c3d09cab", + "bucket_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "bucket_prefix": null, + "bucket_regional_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "cors_rule": [], + "force_destroy": true, + "grant": [], + "hosted_zone_id": "Z3AQBSTGFYJSTF", + "id": "bucket-bb8937d0c3d09cab", + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "policy": null, + "region": "us-east-1", + "replication_configuration": [], + "request_payer": "BucketOwner", + "server_side_encryption_configuration": [], + "tags": { + "environment": "dev" + }, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [], + "website_domain": null, + "website_endpoint": null + }, + "depends_on": [ + "random_id.bucket_name" + ] + }, + { + "address": "random_id.bucket_name", + "mode": "managed", + "type": "random_id", + "name": "bucket_name", + "provider_name": "random", + "schema_version": 0, + "values": { + "b64": "bucket-u4k30MPQnKs", + "b64_std": "bucket-u4k30MPQnKs=", + "b64_url": "bucket-u4k30MPQnKs", + "byte_length": 8, + "dec": "bucket-13513393526679837867", + "hex": "bucket-bb8937d0c3d09cab", + "id": "u4k30MPQnKs", + "keepers": null, + "prefix": "bucket-" + } + } + ], + "child_modules": [ + { + "resources": [ + { + "address": "random_pet.pet", + "mode": "managed", + "type": "random_pet", + "name": "pet", + "provider_name": "random", + "schema_version": 0, + "values": { + "id": "touched-monster", + "keepers": null, + "length": 2, + "prefix": null, + "separator": "-" + } + } + ], + "address": "module.pet2", + "child_modules": [ + { + "resources": [ + { + "address": "random_integer.random", + "mode": "managed", + "type": "random_integer", + "name": "random", + "provider_name": "random", + "schema_version": 0, + "values": { + "id": "9", + "keepers": null, + "max": 10, + "min": 0, + "result": 9, + "seed": null + } + } + ], + "address": "module.pet2.module.bar" + } + ] + }, + { + "resources": [ + { + "address": "random_pet.pet", + "mode": "managed", + "type": "random_pet", + "name": "pet", + "provider_name": "random", + "schema_version": 0, + "values": { + "id": "proud-caribou", + "keepers": null, + "length": 2, + "prefix": null, + "separator": "-" + } + } + ], + "address": "module.pet", + "child_modules": [ + { + "resources": [ + { + "address": "random_integer.random", + "mode": "managed", + "type": "random_integer", + "name": "random", + "provider_name": "random", + "schema_version": 0, + "values": { + "id": "6", + "keepers": null, + "max": 10, + "min": 0, + "result": 6, + "seed": null + } + } + ], + "address": "module.pet.module.bar" + } + ] + } + ] + } + } + }, + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "version_constraint": "~\u003e 2.49", + "expressions": { + "region": { + "references": [ + "var.region" + ] + } + } + } + }, + "root_module": { + "outputs": { + "bucket": { + "expression": { + "references": [ + "aws_s3_bucket.bucket" + ] + }, + "description": "bucket object" + } + }, + "resources": [ + { + "address": "aws_s3_bucket.bucket", + "mode": "managed", + "type": "aws_s3_bucket", + "name": "bucket", + "provider_config_key": "aws", + "expressions": { + "acl": { + "constant_value": "private" + }, + "bucket": { + "references": [ + "local.bucket_name" + ] + }, + "force_destroy": { + "constant_value": "true" + }, + "tags": { + "references": [ + "var.environment" + ] + }, + "versioning": [ + { + "enabled": { + "references": [ + "var.is_versioned" + ] + } + } + ] + }, + "schema_version": 0 + }, + { + "address": "random_id.bucket_name", + "mode": "managed", + "type": "random_id", + "name": "bucket_name", + "provider_config_key": "random", + "expressions": { + "byte_length": { + "constant_value": 8 + }, + "prefix": { + "constant_value": "bucket-" + } + }, + "schema_version": 0 + } + ], + "module_calls": { + "pet": { + "source": "../foo", + "expressions": { + "input": { + "constant_value": "foo" + } + }, + "module": { + "outputs": { + "output": { + "expression": { + "references": [ + "random_pet.pet" + ] + } + } + }, + "resources": [ + { + "address": "random_pet.pet", + "mode": "managed", + "type": "random_pet", + "name": "pet", + "provider_config_key": "pet:random", + "schema_version": 0 + } + ], + "module_calls": { + "bar": { + "source": "../bar", + "expressions": { + "input": { + "constant_value": "test" + } + }, + "module": { + "outputs": { + "output": { + "expression": { + "references": [ + "random_integer.random" + ] + } + } + }, + "resources": [ + { + "address": "random_integer.random", + "mode": "managed", + "type": "random_integer", + "name": "random", + "provider_config_key": "bar:random", + "expressions": { + "max": { + "constant_value": 10 + }, + "min": { + "constant_value": 0 + } + }, + "schema_version": 0 + } + ], + "variables": { + "input": {} + } + } + } + }, + "variables": { + "input": {} + } + } + }, + "pet2": { + "source": "../foo", + "expressions": { + "input": { + "constant_value": "bar" + } + }, + "module": { + "outputs": { + "output": { + "expression": { + "references": [ + "random_pet.pet" + ] + } + } + }, + "resources": [ + { + "address": "random_pet.pet", + "mode": "managed", + "type": "random_pet", + "name": "pet", + "provider_config_key": "pet2:random", + "schema_version": 0 + } + ], + "module_calls": { + "bar": { + "source": "../bar", + "expressions": { + "input": { + "constant_value": "test" + } + }, + "module": { + "outputs": { + "output": { + "expression": { + "references": [ + "random_integer.random" + ] + } + } + }, + "resources": [ + { + "address": "random_integer.random", + "mode": "managed", + "type": "random_integer", + "name": "random", + "provider_config_key": "bar:random", + "expressions": { + "max": { + "constant_value": 10 + }, + "min": { + "constant_value": 0 + } + }, + "schema_version": 0 + } + ], + "variables": { + "input": {} + } + } + } + }, + "variables": { + "input": {} + } + } + } + }, + "variables": { + "bucket_name": { + "default": "", + "description": "name of the bucket; defaults to a 'bucket-{random id}'" + }, + "environment": { + "default": "dev", + "description": "value of the 'Environment' tag" + }, + "is_versioned": { + "default": "false", + "description": "true if versioning is to be enabled, otherwise false; defaults to false" + }, + "kms_key_arn": { + "default": "", + "description": "if set, kms bucket encryption is used with the key arn supplied" + }, + "region": { + "default": "us-east-1", + "description": "region where the bucket will be created or the source region; defaults to us-east-1" + } + } + } + } +} diff --git a/tf-build-tools/pom.xml b/tf-build-tools/pom.xml index 1ead82d1..82b60716 100644 --- a/tf-build-tools/pom.xml +++ b/tf-build-tools/pom.xml @@ -6,12 +6,13 @@ com.deliveredtechnologies tf-build-tools pom - 0.10.1 + 0.11-SNAPSHOT Terraform Build Tools: The parent POM project for Java and Terraform Tools tf-cmd-api tf-maven-plugin tf-s3-archetype + tf-test 1.8 diff --git a/tf-build-tools/tf-cmd-api/pom.xml b/tf-build-tools/tf-cmd-api/pom.xml index 04e84134..803b87d7 100644 --- a/tf-build-tools/tf-cmd-api/pom.xml +++ b/tf-build-tools/tf-cmd-api/pom.xml @@ -5,7 +5,7 @@ tf-build-tools com.deliveredtechnologies - 0.10.1 + 0.11-SNAPSHOT 4.0.0 tf-cmd-api @@ -43,7 +43,7 @@ org.jacoco jacoco-maven-plugin - 0.7.4.201502262128 + 0.8.5 **/*Exception* diff --git a/tf-build-tools/tf-cmd-api/src/main/java/com/deliveredtechnologies/terraform/TerraformUtils.java b/tf-build-tools/tf-cmd-api/src/main/java/com/deliveredtechnologies/terraform/TerraformUtils.java index 43f0e5d2..05682956 100644 --- a/tf-build-tools/tf-cmd-api/src/main/java/com/deliveredtechnologies/terraform/TerraformUtils.java +++ b/tf-build-tools/tf-cmd-api/src/main/java/com/deliveredtechnologies/terraform/TerraformUtils.java @@ -8,7 +8,6 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.util.Arrays; /** * Static utilities for Terraform related default Paths and stuff. @@ -55,8 +54,8 @@ public static Path getTerraformRootModuleDir(String tfmodule) throws IOException } else { path = Paths.get("src", "main", "tf", tfmodule); } - if (!path.toFile().exists() || !Arrays.stream(path.toFile().listFiles()).anyMatch(p -> p.isFile() && p.getName().endsWith(".tf"))) { - throw new TerraformException(String.format("%1$s does not contain any Terraform (*.terraform) files!", tfmodule)); + if (!path.toFile().exists()) { + throw new TerraformException(String.format("%1$s does not exist", tfmodule)); } return path; diff --git a/tf-build-tools/tf-cmd-api/src/main/java/com/deliveredtechnologies/terraform/api/TerraformShow.java b/tf-build-tools/tf-cmd-api/src/main/java/com/deliveredtechnologies/terraform/api/TerraformShow.java index fd6bd04a..04b92703 100644 --- a/tf-build-tools/tf-cmd-api/src/main/java/com/deliveredtechnologies/terraform/api/TerraformShow.java +++ b/tf-build-tools/tf-cmd-api/src/main/java/com/deliveredtechnologies/terraform/api/TerraformShow.java @@ -1,12 +1,9 @@ package com.deliveredtechnologies.terraform.api; -import com.deliveredtechnologies.io.CommandLine; import com.deliveredtechnologies.io.Executable; import com.deliveredtechnologies.terraform.TerraformCommand; import com.deliveredtechnologies.terraform.TerraformCommandLineDecorator; import com.deliveredtechnologies.terraform.TerraformException; -import com.deliveredtechnologies.terraform.TerraformUtils; -import org.slf4j.LoggerFactory; import java.io.IOException; @@ -42,19 +39,16 @@ public String getFormat() { return this.format; } - } TerraformShow(Executable terraform) { super(terraform); } - public TerraformShow(String tfRootDir) throws IOException, TerraformException { - this(new TerraformCommandLineDecorator(TerraformCommand.SHOW, new CommandLine(tfRootDir == null || tfRootDir.isEmpty() ? TerraformUtils.getDefaultTerraformRootModuleDir() : TerraformUtils.getTerraformRootModuleDir(tfRootDir), false, LoggerFactory.getLogger(CommandLine.class)))); + this(new TerraformCommandLineDecorator(TerraformCommand.SHOW, tfRootDir)); } - @Override protected TerraformOption[] getTerraformParams() { return TerraformShow.Option.values(); diff --git a/tf-build-tools/tf-cmd-api/src/test/java/com/deliveredtechnologies/terraform/api/TerraformCleanTest.java b/tf-build-tools/tf-cmd-api/src/test/java/com/deliveredtechnologies/terraform/api/TerraformCleanTest.java index e8864b96..5cb91f27 100644 --- a/tf-build-tools/tf-cmd-api/src/test/java/com/deliveredtechnologies/terraform/api/TerraformCleanTest.java +++ b/tf-build-tools/tf-cmd-api/src/test/java/com/deliveredtechnologies/terraform/api/TerraformCleanTest.java @@ -71,7 +71,7 @@ public void terraformCleanCleansUpTerraformStateFilesAndTerraformWorkingDirector public void terraformCleanThrowsTerraformExceptionOnInvalidPath() throws IOException, TerraformException { TerraformClean terraformClean = new TerraformClean( this.tfModulesWorkingDir.resolveSibling("invalid").toString(), - this.tfInitWorkingDir.toString()); + "invalid"); terraformClean.execute(new Properties()); } diff --git a/tf-build-tools/tf-maven-plugin/pom.xml b/tf-build-tools/tf-maven-plugin/pom.xml index dcd5e4b9..b96215e1 100644 --- a/tf-build-tools/tf-maven-plugin/pom.xml +++ b/tf-build-tools/tf-maven-plugin/pom.xml @@ -4,7 +4,7 @@ com.deliveredtechnologies tf-build-tools - 0.10.1 + 0.11-SNAPSHOT tf-maven-plugin maven-plugin @@ -57,7 +57,7 @@ org.jacoco jacoco-maven-plugin - 0.7.4.201502262128 + 0.8.5 **/terraform/mojo/* diff --git a/tf-build-tools/tf-s3-archetype/pom.xml b/tf-build-tools/tf-s3-archetype/pom.xml index 5c16792b..fb1014c3 100644 --- a/tf-build-tools/tf-s3-archetype/pom.xml +++ b/tf-build-tools/tf-s3-archetype/pom.xml @@ -5,7 +5,7 @@ 4.0.0 com.deliveredtechnologies - 0.10.1 + 0.11-SNAPSHOT tf-build-tools tf-s3-archetype diff --git a/tf-build-tools/tf-test/pom.xml b/tf-build-tools/tf-test/pom.xml new file mode 100644 index 00000000..673c57d7 --- /dev/null +++ b/tf-build-tools/tf-test/pom.xml @@ -0,0 +1,156 @@ + + + + tf-build-tools + com.deliveredtechnologies + 0.11-SNAPSHOT + + 4.0.0 + + tf-test + tf-test + + false + false + false + false + + + + + org.codehaus.groovy + groovy + 3.0.4 + + + com.deliveredtechnologies + tf-cmd-api + ${project.parent.version} + + + + org.slf4j + slf4j-simple + 1.7.30 + test + + + + org.spockframework + spock-core + 2.0-M2-groovy-3.0 + test + + + + org.codehaus.groovy + groovy-json + 3.0.5 + + + + + + + + org.apache.maven.plugins + maven-checkstyle-plugin + 3.0.0 + + + validate-style + validate + + check + + + true + ../checkstyle.xml + UTF-8 + true + true + + + + + + org.jacoco + jacoco-maven-plugin + 0.8.5 + + + **/*Exception* + + + + + jacoco-prepare + + prepare-agent + + + + jacoco-report + test + + report + + + + jacoco-check + test + + check + + + + + BUNDLE + + + LINE + COVEREDRATIO + 0 + + + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + + + org.codehaus.gmavenplus + gmavenplus-plugin + 1.9.0 + + + + addTestSources + compileTests + addSources + compile + + + + + + org.apache.maven.plugins + maven-surefire-plugin + 3.0.0-M4 + + + **/*Spec.java + + + + + + + diff --git a/tf-build-tools/tf-test/src/main/groovy/com/deliveredtechnologies/terraform/fluent/api/Terraform.groovy b/tf-build-tools/tf-test/src/main/groovy/com/deliveredtechnologies/terraform/fluent/api/Terraform.groovy new file mode 100644 index 00000000..981b3ead --- /dev/null +++ b/tf-build-tools/tf-test/src/main/groovy/com/deliveredtechnologies/terraform/fluent/api/Terraform.groovy @@ -0,0 +1,67 @@ +package com.deliveredtechnologies.terraform.fluent.api + +import com.deliveredtechnologies.terraform.api.TerraformApply +import com.deliveredtechnologies.terraform.api.TerraformDestroy +import com.deliveredtechnologies.terraform.api.TerraformInit +import com.deliveredtechnologies.terraform.api.TerraformOutput +import com.deliveredtechnologies.terraform.api.TerraformPlan +import com.deliveredtechnologies.terraform.api.TerraformShow + +class Terraform { + + String rootDir + TerraformInit init + TerraformPlan plan + TerraformApply apply + TerraformOutput output + TerraformShow show + TerraformDestroy destroy + Map properties = new HashMap() + TfPlan tfplan + TfState tfState + String defaultPlanOutputPath + + Terraform withRootDir(String rootDir) { + this.rootDir = rootDir + this.defaultPlanOutputPath = "terraform.tfplan" + this.init = new TerraformInit(rootDir) + this.plan = new TerraformPlan(rootDir) + this.apply = new TerraformApply(rootDir) + this.output = new TerraformOutput(rootDir) + this.show = new TerraformShow(rootDir) + this.destroy = new TerraformDestroy(rootDir) + return this + + } + + Terraform withProperties(Map tfProperties) { + if(!tfProperties.containsKey(TerraformPlan.Option.planOutputFile.getPropertyName())) { + properties.put(TerraformPlan.Option.planOutputFile.getPropertyName(), defaultPlanOutputPath) + + } + properties.putAll(tfProperties) + return this + } + + String init() { + return init.execute(properties) + } + + TfPlan initAndPlan() { + properties.put(TerraformShow.Option.path.getPropertyName(), defaultPlanOutputPath) + init.execute(properties) + plan.execute(properties) + tfplan = new TfPlan(show.execute(properties)) + return tfplan + } + + TfState initAndApply() { + initAndPlan() + properties.put(TerraformApply.Option.plan.getPropertyName(), defaultPlanOutputPath) + apply.execute(properties) + properties.put(TerraformShow.Option.path.getPropertyName(), "terraform.tfstate") + tfState = new TfState(show.execute(properties)) + return tfState + } + +} diff --git a/tf-build-tools/tf-test/src/main/groovy/com/deliveredtechnologies/terraform/fluent/api/TfPlan.groovy b/tf-build-tools/tf-test/src/main/groovy/com/deliveredtechnologies/terraform/fluent/api/TfPlan.groovy new file mode 100644 index 00000000..fe6b27a6 --- /dev/null +++ b/tf-build-tools/tf-test/src/main/groovy/com/deliveredtechnologies/terraform/fluent/api/TfPlan.groovy @@ -0,0 +1,27 @@ +package com.deliveredtechnologies.terraform.fluent.api + +import groovy.json.JsonSlurper + +class TfPlan { + + Map rawPlan + + JsonSlurper slurper = new JsonSlurper() + + TfPlan(String showJsonOutput) { + rawPlan = (Map) slurper.parseText(showJsonOutput) + } + + List getResourcesByType(String type) { + rawPlan.resource_changes.findAll({it.type == type}) + } + + List getResourcesBy(Closure predicate) { + rawPlan.resource_changes.findAll(predicate) + } + + Map getOutputs() { + rawPlan.planned_values.outputs + } + +} diff --git a/tf-build-tools/tf-test/src/main/groovy/com/deliveredtechnologies/terraform/fluent/api/TfState.groovy b/tf-build-tools/tf-test/src/main/groovy/com/deliveredtechnologies/terraform/fluent/api/TfState.groovy new file mode 100644 index 00000000..b616ebdd --- /dev/null +++ b/tf-build-tools/tf-test/src/main/groovy/com/deliveredtechnologies/terraform/fluent/api/TfState.groovy @@ -0,0 +1,14 @@ +package com.deliveredtechnologies.terraform.fluent.api + +import groovy.json.JsonSlurper + +class TfState { + + Map rawState + + JsonSlurper slurper = new JsonSlurper() + + TfState (String showJsonOutput) { + rawState = (Map) slurper.parseText(showJsonOutput) + } +} diff --git a/tf-build-tools/tf-test/src/test/groovy/com/deliveredtechnologies/terraform/fluent/api/TerraformSpec.groovy b/tf-build-tools/tf-test/src/test/groovy/com/deliveredtechnologies/terraform/fluent/api/TerraformSpec.groovy new file mode 100644 index 00000000..89d244f4 --- /dev/null +++ b/tf-build-tools/tf-test/src/test/groovy/com/deliveredtechnologies/terraform/fluent/api/TerraformSpec.groovy @@ -0,0 +1,44 @@ +package com.deliveredtechnologies.terraform.fluent.api + +import spock.lang.Specification + +class TerraformSpec extends Specification { + + + def "init"() { + + Terraform terraform = new Terraform().withRootDir(new File("src/test/resources/tf/").getAbsolutePath()) + .withProperties([noColor: true]) + String result = terraform.init() + println result + + expect: + + result.contains("Terraform has been successfully initialized!") + } + + def "initAndPlan"() { + Terraform terraform = new Terraform().withRootDir(new File("src/test/resources/tf/").getAbsolutePath()) + .withProperties([noColor: true]) + + TfPlan tfPlan = terraform.initAndPlan() + Map rawPlan = tfPlan.rawPlan + + expect: + + rawPlan.output_changes.hello.after == "world" + } + + def "initAndApply"() { + Terraform terraform = new Terraform().withRootDir(new File("src/test/resources/tf/").getAbsolutePath()) + .withProperties([noColor: true]) + + TfState tfState = terraform.initAndApply() + Map rawState = tfState.rawState + + expect: + + rawState.values.outputs.hello.value == "world" + } + +} diff --git a/tf-build-tools/tf-test/src/test/groovy/com/deliveredtechnologies/terraform/fluent/api/TfPlanTest.groovy b/tf-build-tools/tf-test/src/test/groovy/com/deliveredtechnologies/terraform/fluent/api/TfPlanTest.groovy new file mode 100644 index 00000000..c075f423 --- /dev/null +++ b/tf-build-tools/tf-test/src/test/groovy/com/deliveredtechnologies/terraform/fluent/api/TfPlanTest.groovy @@ -0,0 +1,42 @@ +package com.deliveredtechnologies.terraform.fluent.api + + +import spock.lang.Shared +import spock.lang.Specification + +class TfPlanTest extends Specification { + + @Shared + TfPlan tfPlan + + def setupSpec() { + tfPlan = new TfPlan(new File("./src/test/resources/tf_show_example.json").text) + } + + def "GetResourcesByType"() { + given: + List resources = tfPlan.getResourcesByType("aws_s3_bucket") + + expect: + resources.size() == 1 + resources[0].name == "bucket" + + } + + def "GetResourcesBy"() { + given: + List resources = tfPlan.getResourcesBy({it.type == "aws_s3_bucket"}) + + expect: + resources.size() == 1 + resources[0].name == "bucket" + } + + def "GetOutputs"() { + given: + Map outputs = tfPlan.getOutputs() + + expect: + outputs.bucket.value.bucket == "bucket-bb8937d0c3d09cab" + } +} diff --git a/tf-build-tools/tf-test/src/test/groovy/com/deliveredtechnologies/terraform/fluent/api/TfStateTest.groovy b/tf-build-tools/tf-test/src/test/groovy/com/deliveredtechnologies/terraform/fluent/api/TfStateTest.groovy new file mode 100644 index 00000000..8ef81b88 --- /dev/null +++ b/tf-build-tools/tf-test/src/test/groovy/com/deliveredtechnologies/terraform/fluent/api/TfStateTest.groovy @@ -0,0 +1,16 @@ +package com.deliveredtechnologies.terraform.fluent.api + + +import spock.lang.Shared +import spock.lang.Specification + +class TfStateTest extends Specification { + + + @Shared + TfState tfState + + def setupSpec() { + tfState = new TfState(new File("./src/test/resources/tf_show_example.json").text) + } +} diff --git a/tf-build-tools/tf-test/src/test/resources/tf/main.tf b/tf-build-tools/tf-test/src/test/resources/tf/main.tf new file mode 100644 index 00000000..891dadc0 --- /dev/null +++ b/tf-build-tools/tf-test/src/test/resources/tf/main.tf @@ -0,0 +1,3 @@ +output "hello" { + value = "world" +} diff --git a/tf-build-tools/tf-test/src/test/resources/tf_show_example.json b/tf-build-tools/tf-test/src/test/resources/tf_show_example.json new file mode 100644 index 00000000..df4c43eb --- /dev/null +++ b/tf-build-tools/tf-test/src/test/resources/tf_show_example.json @@ -0,0 +1,945 @@ +{ + "format_version": "0.1", + "terraform_version": "0.12.25", + "variables": { + "bucket_name": { + "value": "" + }, + "environment": { + "value": "dev" + }, + "is_versioned": { + "value": "false" + }, + "kms_key_arn": { + "value": "" + }, + "region": { + "value": "us-east-1" + } + }, + "planned_values": { + "outputs": { + "bucket": { + "sensitive": false, + "value": { + "acceleration_status": "", + "acl": "private", + "arn": "arn:aws:s3:::bucket-bb8937d0c3d09cab", + "bucket": "bucket-bb8937d0c3d09cab", + "bucket_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "bucket_prefix": null, + "bucket_regional_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "cors_rule": [], + "force_destroy": true, + "grant": [], + "hosted_zone_id": "Z3AQBSTGFYJSTF", + "id": "bucket-bb8937d0c3d09cab", + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "policy": null, + "region": "us-east-1", + "replication_configuration": [], + "request_payer": "BucketOwner", + "server_side_encryption_configuration": [], + "tags": { + "environment": "dev" + }, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [], + "website_domain": null, + "website_endpoint": null + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_s3_bucket.bucket", + "mode": "managed", + "type": "aws_s3_bucket", + "name": "bucket", + "provider_name": "aws", + "schema_version": 0, + "values": { + "acceleration_status": "", + "acl": "private", + "arn": "arn:aws:s3:::bucket-bb8937d0c3d09cab", + "bucket": "bucket-bb8937d0c3d09cab", + "bucket_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "bucket_prefix": null, + "bucket_regional_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "cors_rule": [], + "force_destroy": true, + "grant": [], + "hosted_zone_id": "Z3AQBSTGFYJSTF", + "id": "bucket-bb8937d0c3d09cab", + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "policy": null, + "region": "us-east-1", + "replication_configuration": [], + "request_payer": "BucketOwner", + "server_side_encryption_configuration": [], + "tags": { + "environment": "dev" + }, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [], + "website_domain": null, + "website_endpoint": null + } + }, + { + "address": "random_id.bucket_name", + "mode": "managed", + "type": "random_id", + "name": "bucket_name", + "provider_name": "random", + "schema_version": 0, + "values": { + "b64": "bucket-u4k30MPQnKs", + "b64_std": "bucket-u4k30MPQnKs=", + "b64_url": "bucket-u4k30MPQnKs", + "byte_length": 8, + "dec": "bucket-13513393526679837867", + "hex": "bucket-bb8937d0c3d09cab", + "id": "u4k30MPQnKs", + "keepers": null, + "prefix": "bucket-" + } + } + ], + "child_modules": [ + { + "resources": [ + { + "address": "module.pet.random_pet.pet", + "mode": "managed", + "type": "random_pet", + "name": "pet", + "provider_name": "random", + "schema_version": 0, + "values": { + "id": "proud-caribou", + "keepers": null, + "length": 2, + "prefix": null, + "separator": "-" + } + } + ], + "address": "module.pet", + "child_modules": [ + { + "resources": [ + { + "address": "module.pet.module.bar.random_integer.random", + "mode": "managed", + "type": "random_integer", + "name": "random", + "provider_name": "random", + "schema_version": 0, + "values": { + "id": "6", + "keepers": null, + "max": 10, + "min": 0, + "result": 6, + "seed": null + } + } + ], + "address": "module.pet.module.bar" + } + ] + }, + { + "resources": [ + { + "address": "module.pet2.random_pet.pet", + "mode": "managed", + "type": "random_pet", + "name": "pet", + "provider_name": "random", + "schema_version": 0, + "values": { + "id": "touched-monster", + "keepers": null, + "length": 2, + "prefix": null, + "separator": "-" + } + } + ], + "address": "module.pet2", + "child_modules": [ + { + "resources": [ + { + "address": "module.pet2.module.bar.random_integer.random", + "mode": "managed", + "type": "random_integer", + "name": "random", + "provider_name": "random", + "schema_version": 0, + "values": { + "id": "9", + "keepers": null, + "max": 10, + "min": 0, + "result": 9, + "seed": null + } + } + ], + "address": "module.pet2.module.bar" + } + ] + } + ] + } + }, + "resource_changes": [ + { + "address": "aws_s3_bucket.bucket", + "mode": "managed", + "type": "aws_s3_bucket", + "name": "bucket", + "provider_name": "aws", + "change": { + "actions": [ + "no-op" + ], + "before": { + "acceleration_status": "", + "acl": "private", + "arn": "arn:aws:s3:::bucket-bb8937d0c3d09cab", + "bucket": "bucket-bb8937d0c3d09cab", + "bucket_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "bucket_prefix": null, + "bucket_regional_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "cors_rule": [], + "force_destroy": true, + "grant": [], + "hosted_zone_id": "Z3AQBSTGFYJSTF", + "id": "bucket-bb8937d0c3d09cab", + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "policy": null, + "region": "us-east-1", + "replication_configuration": [], + "request_payer": "BucketOwner", + "server_side_encryption_configuration": [], + "tags": { + "environment": "dev" + }, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [], + "website_domain": null, + "website_endpoint": null + }, + "after": { + "acceleration_status": "", + "acl": "private", + "arn": "arn:aws:s3:::bucket-bb8937d0c3d09cab", + "bucket": "bucket-bb8937d0c3d09cab", + "bucket_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "bucket_prefix": null, + "bucket_regional_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "cors_rule": [], + "force_destroy": true, + "grant": [], + "hosted_zone_id": "Z3AQBSTGFYJSTF", + "id": "bucket-bb8937d0c3d09cab", + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "policy": null, + "region": "us-east-1", + "replication_configuration": [], + "request_payer": "BucketOwner", + "server_side_encryption_configuration": [], + "tags": { + "environment": "dev" + }, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [], + "website_domain": null, + "website_endpoint": null + }, + "after_unknown": {} + } + }, + { + "address": "module.pet.module.bar.random_integer.random", + "module_address": "module.pet.module.bar", + "mode": "managed", + "type": "random_integer", + "name": "random", + "provider_name": "random", + "change": { + "actions": [ + "no-op" + ], + "before": { + "id": "6", + "keepers": null, + "max": 10, + "min": 0, + "result": 6, + "seed": null + }, + "after": { + "id": "6", + "keepers": null, + "max": 10, + "min": 0, + "result": 6, + "seed": null + }, + "after_unknown": {} + } + }, + { + "address": "module.pet.random_pet.pet", + "module_address": "module.pet", + "mode": "managed", + "type": "random_pet", + "name": "pet", + "provider_name": "random", + "change": { + "actions": [ + "no-op" + ], + "before": { + "id": "proud-caribou", + "keepers": null, + "length": 2, + "prefix": null, + "separator": "-" + }, + "after": { + "id": "proud-caribou", + "keepers": null, + "length": 2, + "prefix": null, + "separator": "-" + }, + "after_unknown": {} + } + }, + { + "address": "module.pet2.module.bar.random_integer.random", + "module_address": "module.pet2.module.bar", + "mode": "managed", + "type": "random_integer", + "name": "random", + "provider_name": "random", + "change": { + "actions": [ + "no-op" + ], + "before": { + "id": "9", + "keepers": null, + "max": 10, + "min": 0, + "result": 9, + "seed": null + }, + "after": { + "id": "9", + "keepers": null, + "max": 10, + "min": 0, + "result": 9, + "seed": null + }, + "after_unknown": {} + } + }, + { + "address": "module.pet2.random_pet.pet", + "module_address": "module.pet2", + "mode": "managed", + "type": "random_pet", + "name": "pet", + "provider_name": "random", + "change": { + "actions": [ + "no-op" + ], + "before": { + "id": "touched-monster", + "keepers": null, + "length": 2, + "prefix": null, + "separator": "-" + }, + "after": { + "id": "touched-monster", + "keepers": null, + "length": 2, + "prefix": null, + "separator": "-" + }, + "after_unknown": {} + } + }, + { + "address": "random_id.bucket_name", + "mode": "managed", + "type": "random_id", + "name": "bucket_name", + "provider_name": "random", + "change": { + "actions": [ + "no-op" + ], + "before": { + "b64": "bucket-u4k30MPQnKs", + "b64_std": "bucket-u4k30MPQnKs=", + "b64_url": "bucket-u4k30MPQnKs", + "byte_length": 8, + "dec": "bucket-13513393526679837867", + "hex": "bucket-bb8937d0c3d09cab", + "id": "u4k30MPQnKs", + "keepers": null, + "prefix": "bucket-" + }, + "after": { + "b64": "bucket-u4k30MPQnKs", + "b64_std": "bucket-u4k30MPQnKs=", + "b64_url": "bucket-u4k30MPQnKs", + "byte_length": 8, + "dec": "bucket-13513393526679837867", + "hex": "bucket-bb8937d0c3d09cab", + "id": "u4k30MPQnKs", + "keepers": null, + "prefix": "bucket-" + }, + "after_unknown": {} + } + } + ], + "output_changes": { + "bucket": { + "actions": [ + "create" + ], + "before": null, + "after": { + "acceleration_status": "", + "acl": "private", + "arn": "arn:aws:s3:::bucket-bb8937d0c3d09cab", + "bucket": "bucket-bb8937d0c3d09cab", + "bucket_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "bucket_prefix": null, + "bucket_regional_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "cors_rule": [], + "force_destroy": true, + "grant": [], + "hosted_zone_id": "Z3AQBSTGFYJSTF", + "id": "bucket-bb8937d0c3d09cab", + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "policy": null, + "region": "us-east-1", + "replication_configuration": [], + "request_payer": "BucketOwner", + "server_side_encryption_configuration": [], + "tags": { + "environment": "dev" + }, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [], + "website_domain": null, + "website_endpoint": null + }, + "after_unknown": false + } + }, + "prior_state": { + "format_version": "0.1", + "terraform_version": "0.12.25", + "values": { + "outputs": { + "bucket": { + "sensitive": false, + "value": { + "acceleration_status": "", + "acl": "private", + "arn": "arn:aws:s3:::bucket-bb8937d0c3d09cab", + "bucket": "bucket-bb8937d0c3d09cab", + "bucket_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "bucket_prefix": null, + "bucket_regional_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "cors_rule": [], + "force_destroy": true, + "grant": [], + "hosted_zone_id": "Z3AQBSTGFYJSTF", + "id": "bucket-bb8937d0c3d09cab", + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "policy": null, + "region": "us-east-1", + "replication_configuration": [], + "request_payer": "BucketOwner", + "server_side_encryption_configuration": [], + "tags": { + "environment": "dev" + }, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [], + "website_domain": null, + "website_endpoint": null + } + } + }, + "root_module": { + "resources": [ + { + "address": "aws_s3_bucket.bucket", + "mode": "managed", + "type": "aws_s3_bucket", + "name": "bucket", + "provider_name": "aws", + "schema_version": 0, + "values": { + "acceleration_status": "", + "acl": "private", + "arn": "arn:aws:s3:::bucket-bb8937d0c3d09cab", + "bucket": "bucket-bb8937d0c3d09cab", + "bucket_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "bucket_prefix": null, + "bucket_regional_domain_name": "bucket-bb8937d0c3d09cab.s3.amazonaws.com", + "cors_rule": [], + "force_destroy": true, + "grant": [], + "hosted_zone_id": "Z3AQBSTGFYJSTF", + "id": "bucket-bb8937d0c3d09cab", + "lifecycle_rule": [], + "logging": [], + "object_lock_configuration": [], + "policy": null, + "region": "us-east-1", + "replication_configuration": [], + "request_payer": "BucketOwner", + "server_side_encryption_configuration": [], + "tags": { + "environment": "dev" + }, + "versioning": [ + { + "enabled": false, + "mfa_delete": false + } + ], + "website": [], + "website_domain": null, + "website_endpoint": null + }, + "depends_on": [ + "random_id.bucket_name" + ] + }, + { + "address": "random_id.bucket_name", + "mode": "managed", + "type": "random_id", + "name": "bucket_name", + "provider_name": "random", + "schema_version": 0, + "values": { + "b64": "bucket-u4k30MPQnKs", + "b64_std": "bucket-u4k30MPQnKs=", + "b64_url": "bucket-u4k30MPQnKs", + "byte_length": 8, + "dec": "bucket-13513393526679837867", + "hex": "bucket-bb8937d0c3d09cab", + "id": "u4k30MPQnKs", + "keepers": null, + "prefix": "bucket-" + } + } + ], + "child_modules": [ + { + "resources": [ + { + "address": "random_pet.pet", + "mode": "managed", + "type": "random_pet", + "name": "pet", + "provider_name": "random", + "schema_version": 0, + "values": { + "id": "touched-monster", + "keepers": null, + "length": 2, + "prefix": null, + "separator": "-" + } + } + ], + "address": "module.pet2", + "child_modules": [ + { + "resources": [ + { + "address": "random_integer.random", + "mode": "managed", + "type": "random_integer", + "name": "random", + "provider_name": "random", + "schema_version": 0, + "values": { + "id": "9", + "keepers": null, + "max": 10, + "min": 0, + "result": 9, + "seed": null + } + } + ], + "address": "module.pet2.module.bar" + } + ] + }, + { + "resources": [ + { + "address": "random_pet.pet", + "mode": "managed", + "type": "random_pet", + "name": "pet", + "provider_name": "random", + "schema_version": 0, + "values": { + "id": "proud-caribou", + "keepers": null, + "length": 2, + "prefix": null, + "separator": "-" + } + } + ], + "address": "module.pet", + "child_modules": [ + { + "resources": [ + { + "address": "random_integer.random", + "mode": "managed", + "type": "random_integer", + "name": "random", + "provider_name": "random", + "schema_version": 0, + "values": { + "id": "6", + "keepers": null, + "max": 10, + "min": 0, + "result": 6, + "seed": null + } + } + ], + "address": "module.pet.module.bar" + } + ] + } + ] + } + } + }, + "configuration": { + "provider_config": { + "aws": { + "name": "aws", + "version_constraint": "~\u003e 2.49", + "expressions": { + "region": { + "references": [ + "var.region" + ] + } + } + } + }, + "root_module": { + "outputs": { + "bucket": { + "expression": { + "references": [ + "aws_s3_bucket.bucket" + ] + }, + "description": "bucket object" + } + }, + "resources": [ + { + "address": "aws_s3_bucket.bucket", + "mode": "managed", + "type": "aws_s3_bucket", + "name": "bucket", + "provider_config_key": "aws", + "expressions": { + "acl": { + "constant_value": "private" + }, + "bucket": { + "references": [ + "local.bucket_name" + ] + }, + "force_destroy": { + "constant_value": "true" + }, + "tags": { + "references": [ + "var.environment" + ] + }, + "versioning": [ + { + "enabled": { + "references": [ + "var.is_versioned" + ] + } + } + ] + }, + "schema_version": 0 + }, + { + "address": "random_id.bucket_name", + "mode": "managed", + "type": "random_id", + "name": "bucket_name", + "provider_config_key": "random", + "expressions": { + "byte_length": { + "constant_value": 8 + }, + "prefix": { + "constant_value": "bucket-" + } + }, + "schema_version": 0 + } + ], + "module_calls": { + "pet": { + "source": "../foo", + "expressions": { + "input": { + "constant_value": "foo" + } + }, + "module": { + "outputs": { + "output": { + "expression": { + "references": [ + "random_pet.pet" + ] + } + } + }, + "resources": [ + { + "address": "random_pet.pet", + "mode": "managed", + "type": "random_pet", + "name": "pet", + "provider_config_key": "pet:random", + "schema_version": 0 + } + ], + "module_calls": { + "bar": { + "source": "../bar", + "expressions": { + "input": { + "constant_value": "test" + } + }, + "module": { + "outputs": { + "output": { + "expression": { + "references": [ + "random_integer.random" + ] + } + } + }, + "resources": [ + { + "address": "random_integer.random", + "mode": "managed", + "type": "random_integer", + "name": "random", + "provider_config_key": "bar:random", + "expressions": { + "max": { + "constant_value": 10 + }, + "min": { + "constant_value": 0 + } + }, + "schema_version": 0 + } + ], + "variables": { + "input": {} + } + } + } + }, + "variables": { + "input": {} + } + } + }, + "pet2": { + "source": "../foo", + "expressions": { + "input": { + "constant_value": "bar" + } + }, + "module": { + "outputs": { + "output": { + "expression": { + "references": [ + "random_pet.pet" + ] + } + } + }, + "resources": [ + { + "address": "random_pet.pet", + "mode": "managed", + "type": "random_pet", + "name": "pet", + "provider_config_key": "pet2:random", + "schema_version": 0 + } + ], + "module_calls": { + "bar": { + "source": "../bar", + "expressions": { + "input": { + "constant_value": "test" + } + }, + "module": { + "outputs": { + "output": { + "expression": { + "references": [ + "random_integer.random" + ] + } + } + }, + "resources": [ + { + "address": "random_integer.random", + "mode": "managed", + "type": "random_integer", + "name": "random", + "provider_config_key": "bar:random", + "expressions": { + "max": { + "constant_value": 10 + }, + "min": { + "constant_value": 0 + } + }, + "schema_version": 0 + } + ], + "variables": { + "input": {} + } + } + } + }, + "variables": { + "input": {} + } + } + } + }, + "variables": { + "bucket_name": { + "default": "", + "description": "name of the bucket; defaults to a 'bucket-{random id}'" + }, + "environment": { + "default": "dev", + "description": "value of the 'Environment' tag" + }, + "is_versioned": { + "default": "false", + "description": "true if versioning is to be enabled, otherwise false; defaults to false" + }, + "kms_key_arn": { + "default": "", + "description": "if set, kms bucket encryption is used with the key arn supplied" + }, + "region": { + "default": "us-east-1", + "description": "region where the bucket will be created or the source region; defaults to us-east-1" + } + } + } + } +}