core: refactoring the way sets work internally v2
This is a refactored solution for PR #616. Functionally this is still the same change, but it’s implemented a lot cleaner with less code and less changes to existing parts of TF.
This commit is contained in:
parent
69b2c245dd
commit
83c760fcb3
2
Makefile
2
Makefile
|
@ -16,7 +16,7 @@ testacc: config/y.go
|
|||
echo "ERROR: Set TEST to a specific package"; \
|
||||
exit 1; \
|
||||
fi
|
||||
TF_ACC=1 go test $(TEST) -v $(TESTARGS) -timeout 30m
|
||||
TF_ACC=1 go test $(TEST) -v $(TESTARGS) -timeout 45m
|
||||
|
||||
testrace: config/y.go
|
||||
TF_ACC= go test -race $(TEST) $(TESTARGS)
|
||||
|
|
|
@ -3,6 +3,7 @@ package aws
|
|||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/hashcode"
|
||||
|
@ -195,7 +196,7 @@ func resourceAwsAutoscalingGroupRead(d *schema.ResourceData, meta interface{}) e
|
|||
d.Set("min_size", g.MinSize)
|
||||
d.Set("max_size", g.MaxSize)
|
||||
d.Set("name", g.Name)
|
||||
d.Set("vpc_zone_identifier", g.VPCZoneIdentifier)
|
||||
d.Set("vpc_zone_identifier", strings.Split(g.VPCZoneIdentifier, ","))
|
||||
|
||||
return nil
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ func TestAccAWSAutoScalingGroup_basic(t *testing.T) {
|
|||
testAccCheckAWSAutoScalingGroupExists("aws_autoscaling_group.bar", &group),
|
||||
testAccCheckAWSAutoScalingGroupAttributes(&group),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_autoscaling_group.bar", "availability_zones.0", "us-west-2a"),
|
||||
"aws_autoscaling_group.bar", "availability_zones.2487133097", "us-west-2a"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_autoscaling_group.bar", "name", "foobar3-terraform-test"),
|
||||
resource.TestCheckResourceAttr(
|
||||
|
@ -39,7 +39,7 @@ func TestAccAWSAutoScalingGroup_basic(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"aws_autoscaling_group.bar", "force_delete", "true"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_autoscaling_group.bar", "termination_policies.0", "OldestInstance"),
|
||||
"aws_autoscaling_group.bar", "termination_policies.912102603", "OldestInstance"),
|
||||
),
|
||||
},
|
||||
|
||||
|
|
|
@ -29,17 +29,17 @@ func TestAccAWSDBParameterGroup(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"aws_db_parameter_group.bar", "description", "Test parameter group for terraform"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_db_parameter_group.bar", "parameter.0.name", "character_set_results"),
|
||||
"aws_db_parameter_group.bar", "parameter.1708034931.name", "character_set_results"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_db_parameter_group.bar", "parameter.0.value", "utf8"),
|
||||
"aws_db_parameter_group.bar", "parameter.1708034931.value", "utf8"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_db_parameter_group.bar", "parameter.1.name", "character_set_server"),
|
||||
"aws_db_parameter_group.bar", "parameter.2421266705.name", "character_set_server"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_db_parameter_group.bar", "parameter.1.value", "utf8"),
|
||||
"aws_db_parameter_group.bar", "parameter.2421266705.value", "utf8"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_db_parameter_group.bar", "parameter.2.name", "character_set_client"),
|
||||
"aws_db_parameter_group.bar", "parameter.2478663599.name", "character_set_client"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_db_parameter_group.bar", "parameter.2.value", "utf8"),
|
||||
"aws_db_parameter_group.bar", "parameter.2478663599.value", "utf8"),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
|
@ -54,25 +54,25 @@ func TestAccAWSDBParameterGroup(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"aws_db_parameter_group.bar", "description", "Test parameter group for terraform"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_db_parameter_group.bar", "parameter.0.name", "collation_connection"),
|
||||
"aws_db_parameter_group.bar", "parameter.1706463059.name", "collation_connection"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_db_parameter_group.bar", "parameter.0.value", "utf8_unicode_ci"),
|
||||
"aws_db_parameter_group.bar", "parameter.1706463059.value", "utf8_unicode_ci"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_db_parameter_group.bar", "parameter.1.name", "character_set_results"),
|
||||
"aws_db_parameter_group.bar", "parameter.1708034931.name", "character_set_results"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_db_parameter_group.bar", "parameter.1.value", "utf8"),
|
||||
"aws_db_parameter_group.bar", "parameter.1708034931.value", "utf8"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_db_parameter_group.bar", "parameter.2.name", "character_set_server"),
|
||||
"aws_db_parameter_group.bar", "parameter.2421266705.name", "character_set_server"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_db_parameter_group.bar", "parameter.2.value", "utf8"),
|
||||
"aws_db_parameter_group.bar", "parameter.2421266705.value", "utf8"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_db_parameter_group.bar", "parameter.3.name", "collation_server"),
|
||||
"aws_db_parameter_group.bar", "parameter.2475805061.name", "collation_server"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_db_parameter_group.bar", "parameter.3.value", "utf8_unicode_ci"),
|
||||
"aws_db_parameter_group.bar", "parameter.2475805061.value", "utf8_unicode_ci"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_db_parameter_group.bar", "parameter.4.name", "character_set_client"),
|
||||
"aws_db_parameter_group.bar", "parameter.2478663599.name", "character_set_client"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_db_parameter_group.bar", "parameter.4.value", "utf8"),
|
||||
"aws_db_parameter_group.bar", "parameter.2478663599.value", "utf8"),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
|
|
@ -34,15 +34,15 @@ func TestAccAWSELB_basic(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"aws_elb.bar", "availability_zones.2", "us-west-2c"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_elb.bar", "listener.0.instance_port", "8000"),
|
||||
"aws_elb.bar", "listener.206423021.instance_port", "8000"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_elb.bar", "listener.0.instance_protocol", "http"),
|
||||
"aws_elb.bar", "listener.206423021.instance_protocol", "http"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_elb.bar", "listener.0.ssl_certificate_id", ssl_certificate_id),
|
||||
"aws_elb.bar", "listener.206423021.ssl_certificate_id", ssl_certificate_id),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_elb.bar", "listener.0.lb_port", "80"),
|
||||
"aws_elb.bar", "listener.206423021.lb_port", "80"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_elb.bar", "listener.0.lb_protocol", "http"),
|
||||
"aws_elb.bar", "listener.206423021.lb_protocol", "http"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_elb.bar", "cross_zone_load_balancing", "true"),
|
||||
),
|
||||
|
@ -101,15 +101,15 @@ func TestAccAWSELB_HealthCheck(t *testing.T) {
|
|||
testAccCheckAWSELBExists("aws_elb.bar", &conf),
|
||||
testAccCheckAWSELBAttributesHealthCheck(&conf),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_elb.bar", "health_check.0.healthy_threshold", "5"),
|
||||
"aws_elb.bar", "health_check.3484319807.healthy_threshold", "5"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_elb.bar", "health_check.0.unhealthy_threshold", "5"),
|
||||
"aws_elb.bar", "health_check.3484319807.unhealthy_threshold", "5"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_elb.bar", "health_check.0.target", "HTTP:8000/"),
|
||||
"aws_elb.bar", "health_check.3484319807.target", "HTTP:8000/"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_elb.bar", "health_check.0.timeout", "30"),
|
||||
"aws_elb.bar", "health_check.3484319807.timeout", "30"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_elb.bar", "health_check.0.interval", "60"),
|
||||
"aws_elb.bar", "health_check.3484319807.interval", "60"),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
@ -257,7 +257,6 @@ resource "aws_elb" "bar" {
|
|||
lb_protocol = "http"
|
||||
}
|
||||
|
||||
instances = []
|
||||
cross_zone_load_balancing = true
|
||||
}
|
||||
`
|
||||
|
|
|
@ -24,29 +24,29 @@ func TestAccAWSNetworkAclsWithEgressAndIngressRules(t *testing.T) {
|
|||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckAWSNetworkAclExists("aws_network_acl.bar", &networkAcl),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "ingress.0.protocol", "tcp"),
|
||||
"aws_network_acl.bar", "ingress.580214135.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "ingress.0.rule_no", "1"),
|
||||
"aws_network_acl.bar", "ingress.580214135.rule_no", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "ingress.0.from_port", "80"),
|
||||
"aws_network_acl.bar", "ingress.580214135.from_port", "80"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "ingress.0.to_port", "80"),
|
||||
"aws_network_acl.bar", "ingress.580214135.to_port", "80"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "ingress.0.action", "allow"),
|
||||
"aws_network_acl.bar", "ingress.580214135.action", "allow"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "ingress.0.cidr_block", "10.3.10.3/18"),
|
||||
"aws_network_acl.bar", "ingress.580214135.cidr_block", "10.3.10.3/18"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "egress.0.protocol", "tcp"),
|
||||
"aws_network_acl.bar", "egress.1730430240.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "egress.0.rule_no", "2"),
|
||||
"aws_network_acl.bar", "egress.1730430240.rule_no", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "egress.0.from_port", "443"),
|
||||
"aws_network_acl.bar", "egress.1730430240.from_port", "443"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "egress.0.to_port", "443"),
|
||||
"aws_network_acl.bar", "egress.1730430240.to_port", "443"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "egress.0.cidr_block", "10.3.2.3/18"),
|
||||
"aws_network_acl.bar", "egress.1730430240.cidr_block", "10.3.2.3/18"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.bar", "egress.0.action", "allow"),
|
||||
"aws_network_acl.bar", "egress.1730430240.action", "allow"),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
@ -67,17 +67,17 @@ func TestAccAWSNetworkAclsOnlyIngressRules(t *testing.T) {
|
|||
testAccCheckAWSNetworkAclExists("aws_network_acl.foos", &networkAcl),
|
||||
// testAccCheckSubnetAssociation("aws_network_acl.foos", "aws_subnet.blob"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.0.protocol", "tcp"),
|
||||
"aws_network_acl.foos", "ingress.3697634361.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.0.rule_no", "2"),
|
||||
"aws_network_acl.foos", "ingress.3697634361.rule_no", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.0.from_port", "443"),
|
||||
"aws_network_acl.foos", "ingress.3697634361.from_port", "0"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.0.to_port", "443"),
|
||||
"aws_network_acl.foos", "ingress.3697634361.to_port", "22"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.0.action", "deny"),
|
||||
"aws_network_acl.foos", "ingress.3697634361.action", "deny"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.0.cidr_block", "10.2.2.3/18"),
|
||||
"aws_network_acl.foos", "ingress.3697634361.cidr_block", "10.2.2.3/18"),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
@ -98,23 +98,21 @@ func TestAccAWSNetworkAclsOnlyIngressRulesChange(t *testing.T) {
|
|||
testAccCheckAWSNetworkAclExists("aws_network_acl.foos", &networkAcl),
|
||||
testIngressRuleLength(&networkAcl, 2),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.0.protocol", "tcp"),
|
||||
"aws_network_acl.foos", "ingress.3697634361.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.0.rule_no", "2"),
|
||||
"aws_network_acl.foos", "ingress.3697634361.rule_no", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.0.from_port", "443"),
|
||||
"aws_network_acl.foos", "ingress.3697634361.from_port", "0"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.0.to_port", "443"),
|
||||
"aws_network_acl.foos", "ingress.3697634361.to_port", "22"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.0.action", "deny"),
|
||||
"aws_network_acl.foos", "ingress.3697634361.action", "deny"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.0.cidr_block", "10.2.2.3/18"),
|
||||
"aws_network_acl.foos", "ingress.3697634361.cidr_block", "10.2.2.3/18"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.1.rule_no", "1"),
|
||||
"aws_network_acl.foos", "ingress.2438803013.from_port", "443"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.1.from_port", "0"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.1.to_port", "22"),
|
||||
"aws_network_acl.foos", "ingress.2438803013.rule_no", "2"),
|
||||
),
|
||||
},
|
||||
resource.TestStep{
|
||||
|
@ -123,17 +121,17 @@ func TestAccAWSNetworkAclsOnlyIngressRulesChange(t *testing.T) {
|
|||
testAccCheckAWSNetworkAclExists("aws_network_acl.foos", &networkAcl),
|
||||
testIngressRuleLength(&networkAcl, 1),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.0.protocol", "tcp"),
|
||||
"aws_network_acl.foos", "ingress.3697634361.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.0.rule_no", "1"),
|
||||
"aws_network_acl.foos", "ingress.3697634361.rule_no", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.0.from_port", "443"),
|
||||
"aws_network_acl.foos", "ingress.3697634361.from_port", "0"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.0.to_port", "443"),
|
||||
"aws_network_acl.foos", "ingress.3697634361.to_port", "22"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.0.action", "deny"),
|
||||
"aws_network_acl.foos", "ingress.3697634361.action", "deny"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_network_acl.foos", "ingress.0.cidr_block", "10.2.2.3/18"),
|
||||
"aws_network_acl.foos", "ingress.3697634361.cidr_block", "10.2.2.3/18"),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
@ -349,8 +347,8 @@ resource "aws_network_acl" "foos" {
|
|||
rule_no = 1
|
||||
action = "deny"
|
||||
cidr_block = "10.2.2.3/18"
|
||||
from_port = 443
|
||||
to_port = 443
|
||||
from_port = 0
|
||||
to_port = 22
|
||||
}
|
||||
subnet_id = "${aws_subnet.blob.id}"
|
||||
}
|
||||
|
|
|
@ -28,15 +28,15 @@ func TestAccAWSSecurityGroup_normal(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"aws_security_group.web", "description", "Used in the terraform acceptance tests"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_security_group.web", "ingress.0.protocol", "tcp"),
|
||||
"aws_security_group.web", "ingress.332851786.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_security_group.web", "ingress.0.from_port", "80"),
|
||||
"aws_security_group.web", "ingress.332851786.from_port", "80"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_security_group.web", "ingress.0.to_port", "8000"),
|
||||
"aws_security_group.web", "ingress.332851786.to_port", "8000"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_security_group.web", "ingress.0.cidr_blocks.#", "1"),
|
||||
"aws_security_group.web", "ingress.332851786.cidr_blocks.#", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_security_group.web", "ingress.0.cidr_blocks.0", "10.0.0.0/8"),
|
||||
"aws_security_group.web", "ingress.332851786.cidr_blocks.0", "10.0.0.0/8"),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
@ -74,13 +74,13 @@ func TestAccAWSSecurityGroup_self(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"aws_security_group.web", "description", "Used in the terraform acceptance tests"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_security_group.web", "ingress.0.protocol", "tcp"),
|
||||
"aws_security_group.web", "ingress.3128515109.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_security_group.web", "ingress.0.from_port", "80"),
|
||||
"aws_security_group.web", "ingress.3128515109.from_port", "80"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_security_group.web", "ingress.0.to_port", "8000"),
|
||||
"aws_security_group.web", "ingress.3128515109.to_port", "8000"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_security_group.web", "ingress.0.self", "true"),
|
||||
"aws_security_group.web", "ingress.3128515109.self", "true"),
|
||||
checkSelf,
|
||||
),
|
||||
},
|
||||
|
@ -114,15 +114,15 @@ func TestAccAWSSecurityGroup_vpc(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"aws_security_group.web", "description", "Used in the terraform acceptance tests"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_security_group.web", "ingress.0.protocol", "tcp"),
|
||||
"aws_security_group.web", "ingress.332851786.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_security_group.web", "ingress.0.from_port", "80"),
|
||||
"aws_security_group.web", "ingress.332851786.from_port", "80"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_security_group.web", "ingress.0.to_port", "8000"),
|
||||
"aws_security_group.web", "ingress.332851786.to_port", "8000"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_security_group.web", "ingress.0.cidr_blocks.#", "1"),
|
||||
"aws_security_group.web", "ingress.332851786.cidr_blocks.#", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"aws_security_group.web", "ingress.0.cidr_blocks.0", "10.0.0.0/8"),
|
||||
"aws_security_group.web", "ingress.332851786.cidr_blocks.0", "10.0.0.0/8"),
|
||||
testCheck,
|
||||
),
|
||||
},
|
||||
|
@ -383,7 +383,7 @@ resource "aws_security_group" "web" {
|
|||
protocol = "tcp"
|
||||
from_port = 80
|
||||
to_port = 8000
|
||||
cidr_blocks = ["10.0.0.0/8", "0.0.0.0/0"]
|
||||
cidr_blocks = ["0.0.0.0/0", "10.0.0.0/8"]
|
||||
}
|
||||
}
|
||||
`
|
||||
|
@ -463,6 +463,16 @@ resource "aws_security_group" "web" {
|
|||
|
||||
const testAccAWSSecurityGroupConfigTags = `
|
||||
resource "aws_security_group" "foo" {
|
||||
name = "terraform_acceptance_test_example"
|
||||
description = "Used in the terraform acceptance tests"
|
||||
|
||||
ingress {
|
||||
protocol = "tcp"
|
||||
from_port = 80
|
||||
to_port = 8000
|
||||
cidr_blocks = ["10.0.0.0/8"]
|
||||
}
|
||||
|
||||
tags {
|
||||
foo = "bar"
|
||||
}
|
||||
|
@ -471,6 +481,16 @@ resource "aws_security_group" "foo" {
|
|||
|
||||
const testAccAWSSecurityGroupConfigTagsUpdate = `
|
||||
resource "aws_security_group" "foo" {
|
||||
name = "terraform_acceptance_test_example"
|
||||
description = "Used in the terraform acceptance tests"
|
||||
|
||||
ingress {
|
||||
protocol = "tcp"
|
||||
from_port = 80
|
||||
to_port = 8000
|
||||
cidr_blocks = ["10.0.0.0/8"]
|
||||
}
|
||||
|
||||
tags {
|
||||
bar = "baz"
|
||||
}
|
||||
|
|
|
@ -23,22 +23,21 @@ func TestAccCloudStackFirewall_basic(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "ipaddress", CLOUDSTACK_PUBLIC_IPADDRESS),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.0.source_cidr", "10.0.0.0/24"),
|
||||
"cloudstack_firewall.foo", "rule.1702320581.source_cidr", "10.0.0.0/24"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.0.protocol", "tcp"),
|
||||
"cloudstack_firewall.foo", "rule.1702320581.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.0.ports.#", "2"),
|
||||
"cloudstack_firewall.foo", "rule.1702320581.ports.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.0.ports.0", "1000-2000"),
|
||||
"cloudstack_firewall.foo", "rule.1702320581.ports.1209010669", "1000-2000"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.0.ports.1", "80"),
|
||||
"cloudstack_firewall.foo", "rule.1702320581.ports.1889509032", "80"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
func TestAccCloudStackFirewall_update(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
@ -54,15 +53,15 @@ func TestAccCloudStackFirewall_update(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.#", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.0.source_cidr", "10.0.0.0/24"),
|
||||
"cloudstack_firewall.foo", "rule.1702320581.source_cidr", "10.0.0.0/24"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.0.protocol", "tcp"),
|
||||
"cloudstack_firewall.foo", "rule.1702320581.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.0.ports.#", "2"),
|
||||
"cloudstack_firewall.foo", "rule.1702320581.ports.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.0.ports.0", "1000-2000"),
|
||||
"cloudstack_firewall.foo", "rule.1702320581.ports.1209010669", "1000-2000"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.0.ports.1", "80"),
|
||||
"cloudstack_firewall.foo", "rule.1702320581.ports.1889509032", "80"),
|
||||
),
|
||||
},
|
||||
|
||||
|
@ -75,31 +74,30 @@ func TestAccCloudStackFirewall_update(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.0.source_cidr", "10.0.0.0/24"),
|
||||
"cloudstack_firewall.foo", "rule.1702320581.source_cidr", "10.0.0.0/24"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.0.protocol", "tcp"),
|
||||
"cloudstack_firewall.foo", "rule.1702320581.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.0.ports.#", "2"),
|
||||
"cloudstack_firewall.foo", "rule.1702320581.ports.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.0.ports.0", "1000-2000"),
|
||||
"cloudstack_firewall.foo", "rule.1702320581.ports.1209010669", "1000-2000"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.0.ports.1", "80"),
|
||||
"cloudstack_firewall.foo", "rule.1702320581.ports.1889509032", "80"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.1.source_cidr", "172.16.100.0/24"),
|
||||
"cloudstack_firewall.foo", "rule.3779782959.source_cidr", "172.16.100.0/24"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.1.protocol", "tcp"),
|
||||
"cloudstack_firewall.foo", "rule.3779782959.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.1.ports.#", "2"),
|
||||
"cloudstack_firewall.foo", "rule.3779782959.ports.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.1.ports.0", "80"),
|
||||
"cloudstack_firewall.foo", "rule.3779782959.ports.1889509032", "80"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_firewall.foo", "rule.1.ports.1", "443"),
|
||||
"cloudstack_firewall.foo", "rule.3779782959.ports.3638101695", "443"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
func testAccCheckCloudStackFirewallRulesExist(n string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
|
|
|
@ -23,26 +23,25 @@ func TestAccCloudStackNetworkACLRule_basic(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.#", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.action", "allow"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.action", "allow"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.source_cidr", "172.16.100.0/24"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.source_cidr", "172.16.100.0/24"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.protocol", "tcp"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.ports.#", "2"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.ports.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.ports.0", "80"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.ports.1889509032", "80"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.ports.1", "443"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.ports.3638101695", "443"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.traffic_type", "ingress"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.traffic_type", "ingress"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
func TestAccCloudStackNetworkACLRule_update(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
@ -56,19 +55,19 @@ func TestAccCloudStackNetworkACLRule_update(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.#", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.action", "allow"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.action", "allow"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.source_cidr", "172.16.100.0/24"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.source_cidr", "172.16.100.0/24"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.protocol", "tcp"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.ports.#", "2"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.ports.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.ports.0", "80"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.ports.1889509032", "80"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.ports.1", "443"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.ports.3638101695", "443"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.traffic_type", "ingress"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.traffic_type", "ingress"),
|
||||
),
|
||||
},
|
||||
|
||||
|
@ -79,39 +78,38 @@ func TestAccCloudStackNetworkACLRule_update(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.action", "allow"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.action", "allow"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.source_cidr", "172.16.100.0/24"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.source_cidr", "172.16.100.0/24"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.protocol", "tcp"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.ports.#", "2"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.ports.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.ports.0", "80"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.ports.1889509032", "80"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.ports.1", "443"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.ports.3638101695", "443"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.0.traffic_type", "ingress"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.3247834462.traffic_type", "ingress"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.1.action", "deny"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.4267872693.action", "deny"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.1.source_cidr", "10.0.0.0/24"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.4267872693.source_cidr", "10.0.0.0/24"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.1.protocol", "tcp"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.4267872693.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.1.ports.#", "2"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.4267872693.ports.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.1.ports.0", "1000-2000"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.4267872693.ports.1209010669", "1000-2000"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.1.ports.1", "80"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.4267872693.ports.1889509032", "80"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_network_acl_rule.foo", "rule.1.traffic_type", "engress"),
|
||||
"cloudstack_network_acl_rule.foo", "rule.4267872693.traffic_type", "engress"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
func testAccCheckCloudStackNetworkACLRulesExist(n string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
|
|
|
@ -23,20 +23,19 @@ func TestAccCloudStackPortForward_basic(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_port_forward.foo", "ipaddress", CLOUDSTACK_PUBLIC_IPADDRESS),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_port_forward.foo", "forward.0.protocol", "tcp"),
|
||||
"cloudstack_port_forward.foo", "forward.1537694805.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_port_forward.foo", "forward.0.private_port", "443"),
|
||||
"cloudstack_port_forward.foo", "forward.1537694805.private_port", "443"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_port_forward.foo", "forward.0.public_port", "8443"),
|
||||
"cloudstack_port_forward.foo", "forward.1537694805.public_port", "8443"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_port_forward.foo", "forward.0.virtual_machine", "terraform-test"),
|
||||
"cloudstack_port_forward.foo", "forward.1537694805.virtual_machine", "terraform-test"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
/*
|
||||
func TestAccCloudStackPortForward_update(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
|
@ -52,13 +51,13 @@ func TestAccCloudStackPortForward_update(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_port_forward.foo", "forward.#", "1"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_port_forward.foo", "forward.0.protocol", "tcp"),
|
||||
"cloudstack_port_forward.foo", "forward.1537694805.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_port_forward.foo", "forward.0.private_port", "443"),
|
||||
"cloudstack_port_forward.foo", "forward.1537694805.private_port", "443"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_port_forward.foo", "forward.0.public_port", "8443"),
|
||||
"cloudstack_port_forward.foo", "forward.1537694805.public_port", "8443"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_port_forward.foo", "forward.0.virtual_machine", "terraform-test"),
|
||||
"cloudstack_port_forward.foo", "forward.1537694805.virtual_machine", "terraform-test"),
|
||||
),
|
||||
},
|
||||
|
||||
|
@ -71,27 +70,26 @@ func TestAccCloudStackPortForward_update(t *testing.T) {
|
|||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_port_forward.foo", "forward.#", "2"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_port_forward.foo", "forward.0.protocol", "tcp"),
|
||||
"cloudstack_port_forward.foo", "forward.8416686.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_port_forward.foo", "forward.0.private_port", "80"),
|
||||
"cloudstack_port_forward.foo", "forward.8416686.private_port", "80"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_port_forward.foo", "forward.0.public_port", "8080"),
|
||||
"cloudstack_port_forward.foo", "forward.8416686.public_port", "8080"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_port_forward.foo", "forward.0.virtual_machine", "terraform-test"),
|
||||
"cloudstack_port_forward.foo", "forward.8416686.virtual_machine", "terraform-test"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_port_forward.foo", "forward.1.protocol", "tcp"),
|
||||
"cloudstack_port_forward.foo", "forward.1537694805.protocol", "tcp"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_port_forward.foo", "forward.1.private_port", "443"),
|
||||
"cloudstack_port_forward.foo", "forward.1537694805.private_port", "443"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_port_forward.foo", "forward.1.public_port", "8443"),
|
||||
"cloudstack_port_forward.foo", "forward.1537694805.public_port", "8443"),
|
||||
resource.TestCheckResourceAttr(
|
||||
"cloudstack_port_forward.foo", "forward.1.virtual_machine", "terraform-test"),
|
||||
"cloudstack_port_forward.foo", "forward.1537694805.virtual_machine", "terraform-test"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
*/
|
||||
|
||||
func testAccCheckCloudStackPortForwardsExist(n string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
|
@ -157,12 +155,10 @@ func testAccCheckCloudStackPortForwardDestroy(s *terraform.State) error {
|
|||
var testAccCloudStackPortForward_basic = fmt.Sprintf(`
|
||||
resource "cloudstack_instance" "foobar" {
|
||||
name = "terraform-test"
|
||||
display_name = "terraform"
|
||||
service_offering= "%s"
|
||||
network = "%s"
|
||||
template = "%s"
|
||||
zone = "%s"
|
||||
user_data = "foobar\nfoo\nbar"
|
||||
expunge = true
|
||||
}
|
||||
|
||||
|
@ -185,12 +181,10 @@ resource "cloudstack_port_forward" "foo" {
|
|||
var testAccCloudStackPortForward_update = fmt.Sprintf(`
|
||||
resource "cloudstack_instance" "foobar" {
|
||||
name = "terraform-test"
|
||||
display_name = "terraform"
|
||||
service_offering= "%s"
|
||||
network = "%s"
|
||||
template = "%s"
|
||||
zone = "%s"
|
||||
user_data = "foobar\nfoo\nbar"
|
||||
expunge = true
|
||||
}
|
||||
|
||||
|
|
|
@ -113,6 +113,25 @@ func (d *ResourceData) HasChange(key string) bool {
|
|||
return !reflect.DeepEqual(o, n)
|
||||
}
|
||||
|
||||
// hasComputedSubKeys walks true a schema and returns whether or not the
|
||||
// given key contains any subkeys that are computed.
|
||||
func (d *ResourceData) hasComputedSubKeys(key string, schema *Schema) bool {
|
||||
prefix := key + "."
|
||||
|
||||
switch t := schema.Elem.(type) {
|
||||
case *Resource:
|
||||
for k, schema := range t.Schema {
|
||||
if d.config.IsComputed(prefix + k) {
|
||||
return true
|
||||
}
|
||||
if d.hasComputedSubKeys(prefix+k, schema) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// Partial turns partial state mode on/off.
|
||||
//
|
||||
// When partial state mode is enabled, then only key prefixes specified
|
||||
|
@ -285,101 +304,178 @@ func (d *ResourceData) getSet(
|
|||
source getSource) getResult {
|
||||
s := &Set{F: schema.Set}
|
||||
result := getResult{Schema: schema, Value: s}
|
||||
prefix := k + "."
|
||||
|
||||
// Get the list. For sets, the entire source must be exact: the
|
||||
// Get the set. For sets, the entire source must be exact: the
|
||||
// entire set must come from set, diff, state, etc. So we go backwards
|
||||
// and once we get a result, we take it. Or, we never get a result.
|
||||
var raw getResult
|
||||
var indexMap map[int]int
|
||||
codes := make(map[string]int)
|
||||
sourceLevel := source & getSourceLevelMask
|
||||
sourceFlags := source & ^getSourceLevelMask
|
||||
for listSource := sourceLevel; listSource > 0; listSource >>= 1 {
|
||||
sourceDiff := sourceFlags&getSourceDiff != 0
|
||||
for setSource := sourceLevel; setSource > 0; setSource >>= 1 {
|
||||
// If we're already asking for an exact source and it doesn't
|
||||
// match, then leave since the original source was the match.
|
||||
if sourceFlags&getSourceExact != 0 && listSource != sourceLevel {
|
||||
if sourceFlags&getSourceExact != 0 && setSource != sourceLevel {
|
||||
break
|
||||
}
|
||||
|
||||
// The source we get from is the level we're on, plus the flags
|
||||
// we had, plus the exact flag.
|
||||
getSource := listSource
|
||||
getSource |= sourceFlags
|
||||
getSource |= getSourceExact
|
||||
raw = d.getList(k, nil, schema, getSource)
|
||||
if raw.Exists {
|
||||
break
|
||||
}
|
||||
}
|
||||
if !raw.Exists {
|
||||
if len(parts) > 0 {
|
||||
return d.getList(k, parts, schema, source)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
if d.config != nil && setSource == getSourceConfig {
|
||||
raw := d.getList(k, nil, schema, setSource)
|
||||
// If the entire list is computed, then the entire set is
|
||||
// necessarilly computed.
|
||||
if raw.Computed {
|
||||
result.Computed = true
|
||||
if len(parts) > 0 {
|
||||
break
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
if raw.Exists {
|
||||
result.Exists = true
|
||||
|
||||
list := raw.Value.([]interface{})
|
||||
if len(list) == 0 {
|
||||
if len(parts) > 0 {
|
||||
return d.getList(k, parts, schema, source)
|
||||
}
|
||||
|
||||
result.Exists = raw.Exists
|
||||
return result
|
||||
}
|
||||
|
||||
// This is a reverse map of hash code => index in config used to
|
||||
// resolve direct set item lookup for turning into state. Confused?
|
||||
// Read on...
|
||||
//
|
||||
// To create the state (the state* functions), a Get call is done
|
||||
// with a full key such as "ports.0". The index of a set ("0") doesn't
|
||||
// make a lot of sense, but we need to deterministically list out
|
||||
// elements of the set like this. Luckily, same sets have a deterministic
|
||||
// List() output, so we can use that to look things up.
|
||||
//
|
||||
// This mapping makes it so that we can look up the hash code of an
|
||||
// object back to its index in the REAL config.
|
||||
var indexMap map[int]int
|
||||
if len(parts) > 0 {
|
||||
indexMap = make(map[int]int)
|
||||
}
|
||||
indexMap = make(map[int]int, len(list))
|
||||
|
||||
// Build the set from all the items using the given hash code
|
||||
for i, v := range list {
|
||||
code := s.add(v)
|
||||
if indexMap != nil {
|
||||
|
||||
// Check if any of the keys in this item are computed
|
||||
computed := false
|
||||
if len(d.config.ComputedKeys) > 0 {
|
||||
prefix := fmt.Sprintf("%s.%d", k, i)
|
||||
computed = d.hasComputedSubKeys(prefix, schema)
|
||||
}
|
||||
|
||||
// Check if we are computed and if so negatate the hash to
|
||||
// this is a approximate hash
|
||||
if computed {
|
||||
s.m[-code] = s.m[code]
|
||||
delete(s.m, code)
|
||||
code = -code
|
||||
}
|
||||
indexMap[code] = i
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// If we're trying to get a specific element, then rewrite the
|
||||
// index to be just that, then jump direct to getList.
|
||||
if len(parts) > 0 {
|
||||
index := parts[0]
|
||||
indexInt, err := strconv.ParseInt(index, 0, 0)
|
||||
if d.state != nil && setSource == getSourceState {
|
||||
for k, _ := range d.state.Attributes {
|
||||
if !strings.HasPrefix(k, prefix) || strings.HasPrefix(k, prefix+"#") {
|
||||
continue
|
||||
}
|
||||
parts := strings.Split(k[len(prefix):], ".")
|
||||
idx := parts[0]
|
||||
if _, ok := codes[idx]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
code, err := strconv.Atoi(strings.Replace(parts[0], "~", "-", -1))
|
||||
if err != nil {
|
||||
return getResultEmpty
|
||||
panic(fmt.Sprintf("unable to convert %s to int: %v", idx, err))
|
||||
}
|
||||
codes[idx] = code
|
||||
}
|
||||
}
|
||||
|
||||
codes := s.listCode()
|
||||
if int(indexInt) >= len(codes) {
|
||||
return getResultEmpty
|
||||
if d.setMap != nil && setSource == getSourceSet {
|
||||
for k, _ := range d.setMap {
|
||||
if !strings.HasPrefix(k, prefix) || strings.HasPrefix(k, prefix+"#") {
|
||||
continue
|
||||
}
|
||||
code := codes[indexInt]
|
||||
realIndex := indexMap[code]
|
||||
|
||||
parts[0] = strconv.FormatInt(int64(realIndex), 10)
|
||||
return d.getList(k, parts, schema, source)
|
||||
parts := strings.Split(k[len(prefix):], ".")
|
||||
idx := parts[0]
|
||||
if _, ok := codes[idx]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
code, err := strconv.Atoi(strings.Replace(parts[0], "~", "-", -1))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("unable to convert %s to int: %v", idx, err))
|
||||
}
|
||||
codes[idx] = code
|
||||
}
|
||||
}
|
||||
|
||||
if d.diff != nil && sourceDiff {
|
||||
for k, _ := range d.diff.Attributes {
|
||||
if !strings.HasPrefix(k, prefix) || strings.HasPrefix(k, prefix+"#") {
|
||||
continue
|
||||
}
|
||||
parts := strings.Split(k[len(prefix):], ".")
|
||||
idx := parts[0]
|
||||
if _, ok := codes[idx]; ok {
|
||||
continue
|
||||
}
|
||||
|
||||
code, err := strconv.Atoi(strings.Replace(parts[0], "~", "-", -1))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("unable to convert %s to int: %v", idx, err))
|
||||
}
|
||||
codes[idx] = code
|
||||
}
|
||||
}
|
||||
|
||||
if len(codes) > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if indexMap == nil {
|
||||
s.m = make(map[int]interface{})
|
||||
for idx, code := range codes {
|
||||
switch t := schema.Elem.(type) {
|
||||
case *Schema:
|
||||
// Get a single value
|
||||
s.m[code] = d.get(prefix+idx, nil, t, source).Value
|
||||
result.Exists = true
|
||||
case *Resource:
|
||||
// Get the entire object
|
||||
m := make(map[string]interface{})
|
||||
for field, _ := range t.Schema {
|
||||
m[field] = d.getObject(prefix+idx, []string{field}, t.Schema, source).Value
|
||||
}
|
||||
s.m[code] = m
|
||||
result.Exists = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(parts) > 0 {
|
||||
// We still have parts left over meaning we're accessing an
|
||||
// element of this set.
|
||||
idx := parts[0]
|
||||
parts = parts[1:]
|
||||
|
||||
// Special case if we're accessing the count of the set
|
||||
if idx == "#" {
|
||||
schema := &Schema{Type: TypeInt}
|
||||
return d.get(prefix+"#", parts, schema, source)
|
||||
}
|
||||
|
||||
if source&getSourceLevelMask == getSourceConfig {
|
||||
i, err := strconv.Atoi(strings.Replace(idx, "~", "-", -1))
|
||||
if err != nil {
|
||||
panic(fmt.Sprintf("unable to convert %s to int: %v", idx, err))
|
||||
}
|
||||
if i, ok := indexMap[i]; ok {
|
||||
idx = strconv.Itoa(i)
|
||||
}
|
||||
}
|
||||
|
||||
switch t := schema.Elem.(type) {
|
||||
case *Schema:
|
||||
return d.get(prefix+idx, parts, t, source)
|
||||
case *Resource:
|
||||
return d.getObject(prefix+idx, parts, t.Schema, source)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
@ -916,8 +1012,13 @@ func (d *ResourceData) setSet(
|
|||
// If it is a slice, then we have to turn it into a *Set so that
|
||||
// we get the proper order back based on the hash code.
|
||||
if v := reflect.ValueOf(value); v.Kind() == reflect.Slice {
|
||||
// Build a temp *ResourceData to use for the conversion
|
||||
tempD := &ResourceData{
|
||||
setMap: make(map[string]string),
|
||||
}
|
||||
|
||||
// Set the entire list, this lets us get sane values out of it
|
||||
if err := d.setList(k, nil, schema, value); err != nil {
|
||||
if err := tempD.setList(k, nil, schema, value); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
@ -930,7 +1031,7 @@ func (d *ResourceData) setSet(
|
|||
source := getSourceSet | getSourceExact
|
||||
for i := 0; i < v.Len(); i++ {
|
||||
is := strconv.FormatInt(int64(i), 10)
|
||||
result := d.getList(k, []string{is}, schema, source)
|
||||
result := tempD.getList(k, []string{is}, schema, source)
|
||||
if !result.Exists {
|
||||
panic("just set item doesn't exist")
|
||||
}
|
||||
|
@ -941,11 +1042,32 @@ func (d *ResourceData) setSet(
|
|||
value = s
|
||||
}
|
||||
|
||||
if s, ok := value.(*Set); ok {
|
||||
value = s.List()
|
||||
switch t := schema.Elem.(type) {
|
||||
case *Schema:
|
||||
for code, elem := range value.(*Set).m {
|
||||
subK := fmt.Sprintf("%s.%d", k, code)
|
||||
err := d.set(subK, nil, t, elem)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
case *Resource:
|
||||
for code, elem := range value.(*Set).m {
|
||||
for field, _ := range t.Schema {
|
||||
subK := fmt.Sprintf("%s.%d", k, code)
|
||||
err := d.setObject(
|
||||
subK, []string{field}, t.Schema, elem.(map[string]interface{})[field])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("%s: unknown element type (internal)", k)
|
||||
}
|
||||
|
||||
return d.setList(k, nil, schema, value)
|
||||
d.setMap[k+".#"] = strconv.Itoa(value.(*Set).Len())
|
||||
return nil
|
||||
}
|
||||
|
||||
func (d *ResourceData) stateList(
|
||||
|
@ -1071,18 +1193,18 @@ func (d *ResourceData) stateSet(
|
|||
}
|
||||
|
||||
set := raw.Value.(*Set)
|
||||
list := set.List()
|
||||
result := make(map[string]string)
|
||||
result[prefix+".#"] = strconv.FormatInt(int64(len(list)), 10)
|
||||
for i := 0; i < len(list); i++ {
|
||||
key := fmt.Sprintf("%s.%d", prefix, i)
|
||||
result[prefix+".#"] = strconv.Itoa(set.Len())
|
||||
|
||||
for _, idx := range set.listCode() {
|
||||
key := fmt.Sprintf("%s.%d", prefix, idx)
|
||||
|
||||
var m map[string]string
|
||||
switch t := schema.Elem.(type) {
|
||||
case *Resource:
|
||||
m = d.stateObject(key, t.Schema)
|
||||
case *Schema:
|
||||
m = d.stateSingle(key, t)
|
||||
case *Resource:
|
||||
m = d.stateObject(key, t.Schema)
|
||||
}
|
||||
|
||||
for k, v := range m {
|
||||
|
|
|
@ -15,6 +15,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
Key string
|
||||
Value interface{}
|
||||
}{
|
||||
// #0
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -41,6 +42,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
Value: "",
|
||||
},
|
||||
|
||||
// #1
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -68,6 +70,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
Value: "foo",
|
||||
},
|
||||
|
||||
// #2
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -94,6 +97,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
Value: "foo",
|
||||
},
|
||||
|
||||
// #3
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -117,6 +121,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
Value: "bar",
|
||||
},
|
||||
|
||||
// #4
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -147,6 +152,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
Value: "",
|
||||
},
|
||||
|
||||
// #5
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"port": &Schema{
|
||||
|
@ -170,6 +176,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
Value: 80,
|
||||
},
|
||||
|
||||
// #6
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -193,6 +200,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
Value: 2,
|
||||
},
|
||||
|
||||
// #7
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -216,6 +224,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
Value: 3,
|
||||
},
|
||||
|
||||
// #8
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -232,6 +241,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
Value: 0,
|
||||
},
|
||||
|
||||
// #9
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -255,6 +265,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
Value: []interface{}{1, 2, 5},
|
||||
},
|
||||
|
||||
// #10
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ingress": &Schema{
|
||||
|
@ -293,6 +304,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
},
|
||||
},
|
||||
|
||||
// #11
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ingress": &Schema{
|
||||
|
@ -333,7 +345,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
},
|
||||
},
|
||||
|
||||
// Computed get
|
||||
// #12 Computed get
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -353,7 +365,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
Value: "foo",
|
||||
},
|
||||
|
||||
// Full object
|
||||
// #13 Full object
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -383,7 +395,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
},
|
||||
},
|
||||
|
||||
// List of maps
|
||||
// #14 List of maps
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"config_vars": &Schema{
|
||||
|
@ -427,7 +439,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
},
|
||||
},
|
||||
|
||||
// List of maps in state
|
||||
// #15 List of maps in state
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"config_vars": &Schema{
|
||||
|
@ -462,7 +474,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
},
|
||||
},
|
||||
|
||||
// List of maps with removal in diff
|
||||
// #16 List of maps with removal in diff
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"config_vars": &Schema{
|
||||
|
@ -500,7 +512,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
Value: []interface{}{},
|
||||
},
|
||||
|
||||
// Sets
|
||||
// #17 Sets
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -517,7 +529,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
State: &terraform.InstanceState{
|
||||
Attributes: map[string]string{
|
||||
"ports.#": "1",
|
||||
"ports.0": "80",
|
||||
"ports.80": "80",
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -528,6 +540,7 @@ func TestResourceDataGet(t *testing.T) {
|
|||
Value: []interface{}{80},
|
||||
},
|
||||
|
||||
// #18
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"data": &Schema{
|
||||
|
@ -556,14 +569,14 @@ func TestResourceDataGet(t *testing.T) {
|
|||
State: &terraform.InstanceState{
|
||||
Attributes: map[string]string{
|
||||
"data.#": "1",
|
||||
"data.0.index": "10",
|
||||
"data.0.value": "50",
|
||||
"data.10.index": "10",
|
||||
"data.10.value": "50",
|
||||
},
|
||||
},
|
||||
|
||||
Diff: &terraform.InstanceDiff{
|
||||
Attributes: map[string]*terraform.ResourceAttrDiff{
|
||||
"data.0.value": &terraform.ResourceAttrDiff{
|
||||
"data.10.value": &terraform.ResourceAttrDiff{
|
||||
Old: "50",
|
||||
New: "80",
|
||||
},
|
||||
|
@ -1398,9 +1411,9 @@ func TestResourceDataSet(t *testing.T) {
|
|||
State: &terraform.InstanceState{
|
||||
Attributes: map[string]string{
|
||||
"ports.#": "3",
|
||||
"ports.0": "100",
|
||||
"ports.1": "80",
|
||||
"ports.2": "80",
|
||||
"ports.100": "100",
|
||||
"ports.80": "80",
|
||||
"ports.81": "81",
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -1433,12 +1446,12 @@ func TestResourceDataSet(t *testing.T) {
|
|||
State: &terraform.InstanceState{
|
||||
Attributes: map[string]string{
|
||||
"ports.#": "2",
|
||||
"ports.0": "100",
|
||||
"ports.1": "80",
|
||||
"ports.100": "100",
|
||||
"ports.80": "80",
|
||||
},
|
||||
},
|
||||
|
||||
Key: "ports.0",
|
||||
Key: "ports.100",
|
||||
Value: 256,
|
||||
Err: true,
|
||||
|
||||
|
@ -1822,9 +1835,9 @@ func TestResourceDataState(t *testing.T) {
|
|||
State: &terraform.InstanceState{
|
||||
Attributes: map[string]string{
|
||||
"ports.#": "3",
|
||||
"ports.0": "100",
|
||||
"ports.1": "80",
|
||||
"ports.2": "80",
|
||||
"ports.100": "100",
|
||||
"ports.80": "80",
|
||||
"ports.81": "81",
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -1832,9 +1845,10 @@ func TestResourceDataState(t *testing.T) {
|
|||
|
||||
Result: &terraform.InstanceState{
|
||||
Attributes: map[string]string{
|
||||
"ports.#": "2",
|
||||
"ports.0": "80",
|
||||
"ports.1": "100",
|
||||
"ports.#": "3",
|
||||
"ports.80": "80",
|
||||
"ports.81": "81",
|
||||
"ports.100": "100",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1863,8 +1877,8 @@ func TestResourceDataState(t *testing.T) {
|
|||
Result: &terraform.InstanceState{
|
||||
Attributes: map[string]string{
|
||||
"ports.#": "2",
|
||||
"ports.0": "80",
|
||||
"ports.1": "100",
|
||||
"ports.80": "80",
|
||||
"ports.100": "100",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -1902,12 +1916,12 @@ func TestResourceDataState(t *testing.T) {
|
|||
State: &terraform.InstanceState{
|
||||
Attributes: map[string]string{
|
||||
"ports.#": "2",
|
||||
"ports.0.order": "10",
|
||||
"ports.0.a.#": "1",
|
||||
"ports.0.a.0": "80",
|
||||
"ports.1.order": "20",
|
||||
"ports.1.b.#": "1",
|
||||
"ports.1.b.0": "100",
|
||||
"ports.10.order": "10",
|
||||
"ports.10.a.#": "1",
|
||||
"ports.10.a.0": "80",
|
||||
"ports.20.order": "20",
|
||||
"ports.20.b.#": "1",
|
||||
"ports.20.b.0": "100",
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -1927,12 +1941,12 @@ func TestResourceDataState(t *testing.T) {
|
|||
Result: &terraform.InstanceState{
|
||||
Attributes: map[string]string{
|
||||
"ports.#": "2",
|
||||
"ports.0.order": "10",
|
||||
"ports.0.a.#": "1",
|
||||
"ports.0.a.0": "80",
|
||||
"ports.1.order": "20",
|
||||
"ports.1.b.#": "1",
|
||||
"ports.1.b.0": "100",
|
||||
"ports.10.order": "10",
|
||||
"ports.10.a.#": "1",
|
||||
"ports.10.a.0": "80",
|
||||
"ports.20.order": "20",
|
||||
"ports.20.b.#": "1",
|
||||
"ports.20.b.0": "100",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
@ -2161,15 +2175,15 @@ func TestResourceDataState(t *testing.T) {
|
|||
State: &terraform.InstanceState{
|
||||
Attributes: map[string]string{
|
||||
"ports.#": "3",
|
||||
"ports.0": "100",
|
||||
"ports.1": "80",
|
||||
"ports.2": "80",
|
||||
"ports.100": "100",
|
||||
"ports.80": "80",
|
||||
"ports.81": "81",
|
||||
},
|
||||
},
|
||||
|
||||
Diff: &terraform.InstanceDiff{
|
||||
Attributes: map[string]*terraform.ResourceAttrDiff{
|
||||
"ports.1": &terraform.ResourceAttrDiff{
|
||||
"ports.120": &terraform.ResourceAttrDiff{
|
||||
New: "120",
|
||||
},
|
||||
},
|
||||
|
@ -2179,9 +2193,10 @@ func TestResourceDataState(t *testing.T) {
|
|||
|
||||
Result: &terraform.InstanceState{
|
||||
Attributes: map[string]string{
|
||||
"ports.#": "2",
|
||||
"ports.0": "80",
|
||||
"ports.1": "100",
|
||||
"ports.#": "3",
|
||||
"ports.80": "80",
|
||||
"ports.81": "81",
|
||||
"ports.100": "100",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
|
|
@ -618,25 +618,109 @@ func (m schemaMap) diffSet(
|
|||
diff *terraform.InstanceDiff,
|
||||
d *ResourceData,
|
||||
all bool) error {
|
||||
if !all {
|
||||
// This is a bit strange, but we expect the entire set to be in the diff,
|
||||
// so we first diff the set normally but with a new diff. Then, if
|
||||
// there IS any change, we just set the change to the entire list.
|
||||
tempD := new(terraform.InstanceDiff)
|
||||
tempD.Attributes = make(map[string]*terraform.ResourceAttrDiff)
|
||||
if err := m.diffList(k, schema, tempD, d, false); err != nil {
|
||||
return err
|
||||
}
|
||||
o, n, _, computedSet := d.diffChange(k)
|
||||
nSet := n != nil
|
||||
|
||||
// If we had no changes, then we're done
|
||||
if tempD.Empty() {
|
||||
// If we have an old value and no new value is set or will be
|
||||
// computed once all variables can be interpolated and we're
|
||||
// computed, then nothing has changed.
|
||||
if o != nil && n == nil && !computedSet && schema.Computed {
|
||||
return nil
|
||||
}
|
||||
|
||||
if o == nil {
|
||||
o = &Set{F: schema.Set}
|
||||
}
|
||||
if n == nil {
|
||||
n = &Set{F: schema.Set}
|
||||
}
|
||||
os := o.(*Set)
|
||||
ns := n.(*Set)
|
||||
|
||||
// If the new value was set, compare the listCode's to determine if
|
||||
// the two are equal. Comparing listCode's instead of the actuall values
|
||||
// is needed because there could be computed values in the set which
|
||||
// would result in false positives while comparing.
|
||||
if !all && nSet && reflect.DeepEqual(os.listCode(), ns.listCode()) {
|
||||
return nil
|
||||
}
|
||||
|
||||
// We have changes, so re-run the diff, but set a flag to force
|
||||
// getting all diffs, even if there is no change.
|
||||
return m.diffList(k, schema, diff, d, true)
|
||||
// Get the counts
|
||||
oldLen := os.Len()
|
||||
newLen := ns.Len()
|
||||
oldStr := strconv.Itoa(oldLen)
|
||||
newStr := strconv.Itoa(newLen)
|
||||
|
||||
// If the set computed then say that the # is computed
|
||||
if computedSet || (schema.Computed && !nSet) {
|
||||
// If # already exists, equals 0 and no new set is supplied, there
|
||||
// is nothing to record in the diff
|
||||
count, ok := d.GetOk(k + ".#")
|
||||
if ok && count.(int) == 0 && !nSet && !computedSet {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set the count but make sure that if # does not exist, we don't
|
||||
// use the zeroed value
|
||||
countStr := strconv.Itoa(count.(int))
|
||||
if !ok {
|
||||
countStr = ""
|
||||
}
|
||||
|
||||
diff.Attributes[k+".#"] = &terraform.ResourceAttrDiff{
|
||||
Old: countStr,
|
||||
NewComputed: true,
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// If the counts are not the same, then record that diff
|
||||
changed := oldLen != newLen
|
||||
if changed || all {
|
||||
countSchema := &Schema{
|
||||
Type: TypeInt,
|
||||
Computed: schema.Computed,
|
||||
ForceNew: schema.ForceNew,
|
||||
}
|
||||
|
||||
diff.Attributes[k+".#"] = countSchema.finalizeDiff(&terraform.ResourceAttrDiff{
|
||||
Old: oldStr,
|
||||
New: newStr,
|
||||
})
|
||||
}
|
||||
|
||||
for _, code := range ns.listCode() {
|
||||
switch t := schema.Elem.(type) {
|
||||
case *Schema:
|
||||
// Copy the schema so that we can set Computed/ForceNew from
|
||||
// the parent schema (the TypeSet).
|
||||
t2 := *t
|
||||
t2.ForceNew = schema.ForceNew
|
||||
|
||||
// This is just a primitive element, so go through each and
|
||||
// just diff each.
|
||||
subK := fmt.Sprintf("%s.%d", k, code)
|
||||
subK = strings.Replace(subK, "-", "~", -1)
|
||||
err := m.diff(subK, &t2, diff, d, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
case *Resource:
|
||||
// This is a complex resource
|
||||
for k2, schema := range t.Schema {
|
||||
subK := fmt.Sprintf("%s.%d.%s", k, code, k2)
|
||||
subK = strings.Replace(subK, "-", "~", -1)
|
||||
err := m.diff(subK, schema, diff, d, true)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("%s: unknown element type (internal)", k)
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (m schemaMap) diffString(
|
||||
|
|
|
@ -21,6 +21,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
* String decode
|
||||
*/
|
||||
|
||||
// #0
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -50,6 +51,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #1
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -77,6 +79,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #2
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -98,7 +101,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// Computed, but set in config
|
||||
// #3 Computed, but set in config
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -130,7 +133,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// Default
|
||||
// #4 Default
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -156,7 +159,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// DefaultFunc, value
|
||||
// #5 DefaultFunc, value
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -184,7 +187,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// DefaultFunc, configuration set
|
||||
// #6 DefaultFunc, configuration set
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -214,7 +217,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// String with StateFunc
|
||||
// #7 String with StateFunc
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -246,7 +249,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// Variable (just checking)
|
||||
// #8 Variable (just checking)
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -277,7 +280,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// Variable computed
|
||||
// #9 Variable computed
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -312,6 +315,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
* Int decode
|
||||
*/
|
||||
|
||||
// #10
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"port": &Schema{
|
||||
|
@ -345,6 +349,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
* Bool decode
|
||||
*/
|
||||
|
||||
// #11
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"port": &Schema{
|
||||
|
@ -377,6 +382,8 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
/*
|
||||
* Bool
|
||||
*/
|
||||
|
||||
// #12
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"delete": &Schema{
|
||||
|
@ -403,6 +410,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
* List decode
|
||||
*/
|
||||
|
||||
// #13
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -442,6 +450,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #14
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -485,6 +494,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #15
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -518,6 +528,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #16
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -545,6 +556,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #17
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -582,6 +594,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #18
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -626,6 +639,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #19
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -656,6 +670,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
* Set
|
||||
*/
|
||||
|
||||
// #20
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -680,15 +695,15 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Old: "0",
|
||||
New: "3",
|
||||
},
|
||||
"ports.0": &terraform.ResourceAttrDiff{
|
||||
"ports.1": &terraform.ResourceAttrDiff{
|
||||
Old: "",
|
||||
New: "1",
|
||||
},
|
||||
"ports.1": &terraform.ResourceAttrDiff{
|
||||
"ports.2": &terraform.ResourceAttrDiff{
|
||||
Old: "",
|
||||
New: "2",
|
||||
},
|
||||
"ports.2": &terraform.ResourceAttrDiff{
|
||||
"ports.5": &terraform.ResourceAttrDiff{
|
||||
Old: "",
|
||||
New: "5",
|
||||
},
|
||||
|
@ -698,6 +713,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #21
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -724,6 +740,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #22
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -753,6 +770,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #23
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -781,15 +799,15 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Old: "0",
|
||||
New: "3",
|
||||
},
|
||||
"ports.0": &terraform.ResourceAttrDiff{
|
||||
"ports.1": &terraform.ResourceAttrDiff{
|
||||
Old: "",
|
||||
New: "1",
|
||||
},
|
||||
"ports.1": &terraform.ResourceAttrDiff{
|
||||
"ports.2": &terraform.ResourceAttrDiff{
|
||||
Old: "",
|
||||
New: "2",
|
||||
},
|
||||
"ports.2": &terraform.ResourceAttrDiff{
|
||||
"ports.5": &terraform.ResourceAttrDiff{
|
||||
Old: "",
|
||||
New: "5",
|
||||
},
|
||||
|
@ -799,6 +817,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #24
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -825,7 +844,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Diff: &terraform.InstanceDiff{
|
||||
Attributes: map[string]*terraform.ResourceAttrDiff{
|
||||
"ports.#": &terraform.ResourceAttrDiff{
|
||||
Old: "0",
|
||||
Old: "",
|
||||
New: "",
|
||||
NewComputed: true,
|
||||
},
|
||||
|
@ -835,6 +854,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #25
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -850,8 +870,8 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
State: &terraform.InstanceState{
|
||||
Attributes: map[string]string{
|
||||
"ports.#": "2",
|
||||
"ports.0": "2",
|
||||
"ports.1": "1",
|
||||
"ports.2": "2",
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -865,15 +885,15 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Old: "2",
|
||||
New: "3",
|
||||
},
|
||||
"ports.0": &terraform.ResourceAttrDiff{
|
||||
"ports.1": &terraform.ResourceAttrDiff{
|
||||
Old: "1",
|
||||
New: "1",
|
||||
},
|
||||
"ports.1": &terraform.ResourceAttrDiff{
|
||||
"ports.2": &terraform.ResourceAttrDiff{
|
||||
Old: "2",
|
||||
New: "2",
|
||||
},
|
||||
"ports.2": &terraform.ResourceAttrDiff{
|
||||
"ports.5": &terraform.ResourceAttrDiff{
|
||||
Old: "",
|
||||
New: "5",
|
||||
},
|
||||
|
@ -883,6 +903,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #26
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -898,8 +919,8 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
State: &terraform.InstanceState{
|
||||
Attributes: map[string]string{
|
||||
"ports.#": "2",
|
||||
"ports.0": "2",
|
||||
"ports.1": "1",
|
||||
"ports.2": "2",
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -911,20 +932,13 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Old: "2",
|
||||
New: "0",
|
||||
},
|
||||
"ports.0": &terraform.ResourceAttrDiff{
|
||||
Old: "1",
|
||||
NewRemoved: true,
|
||||
},
|
||||
"ports.1": &terraform.ResourceAttrDiff{
|
||||
Old: "2",
|
||||
NewRemoved: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Err: false,
|
||||
},
|
||||
|
||||
// #27
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ports": &Schema{
|
||||
|
@ -932,7 +946,9 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Optional: true,
|
||||
Computed: true,
|
||||
Elem: &Schema{Type: TypeInt},
|
||||
Set: func(v interface{}) int { return v.(int) },
|
||||
Set: func(a interface{}) int {
|
||||
return a.(int)
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -940,7 +956,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Attributes: map[string]string{
|
||||
"availability_zone": "bar",
|
||||
"ports.#": "1",
|
||||
"ports.0": "80",
|
||||
"ports.80": "80",
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -951,6 +967,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #28
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ingress": &Schema{
|
||||
|
@ -980,15 +997,15 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
State: &terraform.InstanceState{
|
||||
Attributes: map[string]string{
|
||||
"ingress.#": "2",
|
||||
"ingress.0.ports.#": "1",
|
||||
"ingress.0.ports.0": "80",
|
||||
"ingress.1.ports.#": "1",
|
||||
"ingress.1.ports.0": "443",
|
||||
"ingress.80.ports.#": "1",
|
||||
"ingress.80.ports.0": "80",
|
||||
"ingress.443.ports.#": "1",
|
||||
"ingress.443.ports.0": "443",
|
||||
},
|
||||
},
|
||||
|
||||
Config: map[string]interface{}{
|
||||
"ingress": []interface{}{
|
||||
"ingress": []map[string]interface{}{
|
||||
map[string]interface{}{
|
||||
"ports": []interface{}{443},
|
||||
},
|
||||
|
@ -1007,6 +1024,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
* List of structure decode
|
||||
*/
|
||||
|
||||
// #29
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"ingress": &Schema{
|
||||
|
@ -1053,6 +1071,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
* ComputedWhen
|
||||
*/
|
||||
|
||||
// #30
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -1083,6 +1102,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #31
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -1165,6 +1185,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
* Maps
|
||||
*/
|
||||
|
||||
// #32
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"config_vars": &Schema{
|
||||
|
@ -1194,6 +1215,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #33
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"config_vars": &Schema{
|
||||
|
@ -1231,6 +1253,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #34
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"vars": &Schema{
|
||||
|
@ -1271,6 +1294,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #35
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"vars": &Schema{
|
||||
|
@ -1292,6 +1316,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #36
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"config_vars": &Schema{
|
||||
|
@ -1331,6 +1356,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #37
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"config_vars": &Schema{
|
||||
|
@ -1373,6 +1399,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
* ForceNews
|
||||
*/
|
||||
|
||||
// #38
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -1418,7 +1445,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// Set
|
||||
// #39 Set
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"availability_zone": &Schema{
|
||||
|
@ -1432,7 +1459,9 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Optional: true,
|
||||
Computed: true,
|
||||
Elem: &Schema{Type: TypeInt},
|
||||
Set: func(v interface{}) int { return v.(int) },
|
||||
Set: func(a interface{}) int {
|
||||
return a.(int)
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -1440,7 +1469,7 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Attributes: map[string]string{
|
||||
"availability_zone": "bar",
|
||||
"ports.#": "1",
|
||||
"ports.0": "80",
|
||||
"ports.80": "80",
|
||||
},
|
||||
},
|
||||
|
||||
|
@ -1467,13 +1496,9 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
Err: false,
|
||||
},
|
||||
|
||||
// #40 Set
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"internal": &Schema{
|
||||
Type: TypeBool,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"instances": &Schema{
|
||||
Type: TypeSet,
|
||||
Elem: &Schema{Type: TypeString},
|
||||
|
@ -1487,13 +1512,11 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
|
||||
State: &terraform.InstanceState{
|
||||
Attributes: map[string]string{
|
||||
"internal": "false",
|
||||
"instances.#": "0",
|
||||
},
|
||||
},
|
||||
|
||||
Config: map[string]interface{}{
|
||||
"internal": true,
|
||||
"instances": []interface{}{"${var.foo}"},
|
||||
},
|
||||
|
||||
|
@ -1503,13 +1526,136 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
|
||||
Diff: &terraform.InstanceDiff{
|
||||
Attributes: map[string]*terraform.ResourceAttrDiff{
|
||||
"internal": &terraform.ResourceAttrDiff{
|
||||
"instances.#": &terraform.ResourceAttrDiff{
|
||||
Old: "0",
|
||||
NewComputed: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Err: false,
|
||||
},
|
||||
|
||||
// #41 Set
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"route": &Schema{
|
||||
Type: TypeSet,
|
||||
Optional: true,
|
||||
Elem: &Resource{
|
||||
Schema: map[string]*Schema{
|
||||
"index": &Schema{
|
||||
Type: TypeInt,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"gateway": &Schema{
|
||||
Type: TypeString,
|
||||
Optional: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
Set: func(v interface{}) int {
|
||||
m := v.(map[string]interface{})
|
||||
return m["index"].(int)
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
State: nil,
|
||||
|
||||
Config: map[string]interface{}{
|
||||
"route": []map[string]interface{}{
|
||||
map[string]interface{}{
|
||||
"index": "1",
|
||||
"gateway": "${var.foo}",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
ConfigVariables: map[string]string{
|
||||
"var.foo": config.UnknownVariableValue,
|
||||
},
|
||||
|
||||
Diff: &terraform.InstanceDiff{
|
||||
Attributes: map[string]*terraform.ResourceAttrDiff{
|
||||
"route.#": &terraform.ResourceAttrDiff{
|
||||
Old: "0",
|
||||
New: "1",
|
||||
},
|
||||
"route.~1.index": &terraform.ResourceAttrDiff{
|
||||
Old: "",
|
||||
New: "1",
|
||||
},
|
||||
"route.~1.gateway": &terraform.ResourceAttrDiff{
|
||||
Old: "",
|
||||
New: "${var.foo}",
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
"instances.#": &terraform.ResourceAttrDiff{
|
||||
Err: false,
|
||||
},
|
||||
|
||||
// #42 Set
|
||||
{
|
||||
Schema: map[string]*Schema{
|
||||
"route": &Schema{
|
||||
Type: TypeSet,
|
||||
Optional: true,
|
||||
Elem: &Resource{
|
||||
Schema: map[string]*Schema{
|
||||
"index": &Schema{
|
||||
Type: TypeInt,
|
||||
Required: true,
|
||||
},
|
||||
|
||||
"gateway": &Schema{
|
||||
Type: TypeSet,
|
||||
Optional: true,
|
||||
Elem: &Schema{Type: TypeInt},
|
||||
Set: func(a interface{}) int {
|
||||
return a.(int)
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
Set: func(v interface{}) int {
|
||||
m := v.(map[string]interface{})
|
||||
return m["index"].(int)
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
State: nil,
|
||||
|
||||
Config: map[string]interface{}{
|
||||
"route": []map[string]interface{}{
|
||||
map[string]interface{}{
|
||||
"index": "1",
|
||||
"gateway": []interface{}{
|
||||
"${var.foo}",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
ConfigVariables: map[string]string{
|
||||
"var.foo": config.UnknownVariableValue,
|
||||
},
|
||||
|
||||
Diff: &terraform.InstanceDiff{
|
||||
Attributes: map[string]*terraform.ResourceAttrDiff{
|
||||
"route.#": &terraform.ResourceAttrDiff{
|
||||
Old: "0",
|
||||
New: "1",
|
||||
},
|
||||
"route.~1.index": &terraform.ResourceAttrDiff{
|
||||
Old: "",
|
||||
New: "1",
|
||||
},
|
||||
"route.~1.gateway.#": &terraform.ResourceAttrDiff{
|
||||
Old: "",
|
||||
NewComputed: true,
|
||||
},
|
||||
},
|
||||
|
@ -1522,12 +1668,12 @@ func TestSchemaMap_Diff(t *testing.T) {
|
|||
for i, tc := range cases {
|
||||
c, err := config.NewRawConfig(tc.Config)
|
||||
if err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
t.Fatalf("#%d err: %s", i, err)
|
||||
}
|
||||
|
||||
if len(tc.ConfigVariables) > 0 {
|
||||
if err := c.Interpolate(tc.ConfigVariables); err != nil {
|
||||
t.Fatalf("err: %s", err)
|
||||
t.Fatalf("#%d err: %s", i, err)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ import (
|
|||
"bytes"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
@ -348,7 +349,7 @@ func (d *InstanceDiff) RequiresNew() bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// Same checks whether or not to InstanceDiff are the "same." When
|
||||
// Same checks whether or not two InstanceDiff's are the "same". When
|
||||
// we say "same", it is not necessarily exactly equal. Instead, it is
|
||||
// just checking that the same attributes are changing, a destroy
|
||||
// isn't suddenly happening, etc.
|
||||
|
@ -376,7 +377,18 @@ func (d *InstanceDiff) Same(d2 *InstanceDiff) bool {
|
|||
for k, _ := range d2.Attributes {
|
||||
checkNew[k] = struct{}{}
|
||||
}
|
||||
for k, diffOld := range d.Attributes {
|
||||
|
||||
// Make an ordered list so we are sure the approximated hashes are left
|
||||
// to process at the end of the loop
|
||||
keys := make([]string, 0, len(d.Attributes))
|
||||
for k, _ := range d.Attributes {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.StringSlice(keys).Sort()
|
||||
|
||||
for _, k := range keys {
|
||||
diffOld := d.Attributes[k]
|
||||
|
||||
if _, ok := checkOld[k]; !ok {
|
||||
// We're not checking this key for whatever reason (see where
|
||||
// check is modified).
|
||||
|
@ -389,14 +401,52 @@ func (d *InstanceDiff) Same(d2 *InstanceDiff) bool {
|
|||
|
||||
_, ok := d2.Attributes[k]
|
||||
if !ok {
|
||||
// The matching attribute was not found, we're different
|
||||
// No exact match, but maybe this is a set containing computed
|
||||
// values. So check if there is an approximate hash in the key
|
||||
// and if so, try to match the key.
|
||||
if strings.Contains(k, "~") {
|
||||
// TODO (SvH): There should be a better way to do this...
|
||||
parts := strings.Split(k, ".")
|
||||
parts2 := strings.Split(k, ".")
|
||||
re := regexp.MustCompile(`^~\d+$`)
|
||||
for i, part := range parts {
|
||||
if re.MatchString(part) {
|
||||
parts2[i] = `\d+`
|
||||
}
|
||||
}
|
||||
re, err := regexp.Compile("^" + strings.Join(parts2, `\.`) + "$")
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
for k2, _ := range checkNew {
|
||||
if re.MatchString(k2) {
|
||||
delete(checkNew, k2)
|
||||
|
||||
if diffOld.NewComputed && strings.HasSuffix(k, ".#") {
|
||||
// This is a computed list or set, so remove any keys with this
|
||||
// prefix from the check list.
|
||||
prefix := k2[:len(k2)-1]
|
||||
for k2, _ := range checkNew {
|
||||
if strings.HasPrefix(k2, prefix) {
|
||||
delete(checkNew, k2)
|
||||
}
|
||||
}
|
||||
}
|
||||
ok = true
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if diffOld.NewComputed && strings.HasSuffix(k, ".#") {
|
||||
// This is a computed list, so remove any keys with this
|
||||
// This is a computed list or set, so remove any keys with this
|
||||
// prefix from the check list.
|
||||
kprefix := k[0:len(k)-2] + "."
|
||||
kprefix := k[:len(k)-1]
|
||||
for k2, _ := range checkOld {
|
||||
if strings.HasPrefix(k2, kprefix) {
|
||||
delete(checkOld, k2)
|
||||
|
|
|
@ -464,6 +464,34 @@ func TestInstanceDiffSame(t *testing.T) {
|
|||
},
|
||||
true,
|
||||
},
|
||||
|
||||
{
|
||||
&InstanceDiff{
|
||||
Attributes: map[string]*ResourceAttrDiff{
|
||||
"foo.#": &ResourceAttrDiff{
|
||||
Old: "0",
|
||||
New: "1",
|
||||
},
|
||||
"foo.~35964334.bar": &ResourceAttrDiff{
|
||||
Old: "",
|
||||
New: "${var.foo}",
|
||||
},
|
||||
},
|
||||
},
|
||||
&InstanceDiff{
|
||||
Attributes: map[string]*ResourceAttrDiff{
|
||||
"foo.#": &ResourceAttrDiff{
|
||||
Old: "0",
|
||||
New: "1",
|
||||
},
|
||||
"foo.87654323.bar": &ResourceAttrDiff{
|
||||
Old: "",
|
||||
New: "12",
|
||||
},
|
||||
},
|
||||
},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
for i, tc := range cases {
|
||||
|
|
|
@ -1,8 +1,6 @@
|
|||
package terraform
|
||||
|
||||
import (
|
||||
"sync"
|
||||
)
|
||||
import "sync"
|
||||
|
||||
// MockResourceProvider implements ResourceProvider but mocks out all the
|
||||
// calls for testing purposes.
|
||||
|
|
Loading…
Reference in New Issue