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