Skip to content

Commit

Permalink
Merge pull request #773 from ceh/issue-691
Browse files Browse the repository at this point in the history
helper/schema: fix panic when validating composite schema type
  • Loading branch information
mitchellh committed Jan 14, 2015
2 parents 5b08cd6 + 4893eb8 commit 152e72f
Show file tree
Hide file tree
Showing 26 changed files with 131 additions and 50 deletions.
2 changes: 1 addition & 1 deletion examples/aws-count/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
The count parameter on resources can simplify configurations
and let you scale resources by simply incrementing a number.

Additionally, variables can be used to expand a list of resources
Additionally, variables can be used to expand an array of resources
for use elsewhere.

As with all examples, just copy and paste the example and run
Expand Down
32 changes: 21 additions & 11 deletions helper/schema/schema.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ type Schema struct {
// element type is a complex structure, potentially with its own lifecycle.
Elem interface{}

// The follow fields are only valid for a TypeSet type.
// The following fields are only valid for a TypeSet type.
//
// Set defines a function to determine the unique ID of an item so that
// a proper set can be built.
Expand Down Expand Up @@ -902,7 +902,7 @@ func (m schemaMap) validate(
"%s: this field cannot be set", k)}
}

return m.validatePrimitive(k, raw, schema, c)
return m.validateType(k, raw, schema, c)
}

func (m schemaMap) validateList(
Expand All @@ -915,7 +915,7 @@ func (m schemaMap) validateList(
rawV := reflect.ValueOf(raw)
if rawV.Kind() != reflect.Slice {
return nil, []error{fmt.Errorf(
"%s: should be a list", k)}
"%s: should be an array", k)}
}

// Now build the []interface{}
Expand All @@ -936,8 +936,7 @@ func (m schemaMap) validateList(
// This is a sub-resource
ws2, es2 = m.validateObject(key, t.Schema, c)
case *Schema:
// This is some sort of primitive
ws2, es2 = m.validatePrimitive(key, raw, t, c)
ws2, es2 = m.validateType(key, raw, t, c)
}

if len(ws2) > 0 {
Expand Down Expand Up @@ -1041,12 +1040,6 @@ func (m schemaMap) validatePrimitive(
}

switch schema.Type {
case TypeSet:
fallthrough
case TypeList:
return m.validateList(k, raw, schema, c)
case TypeMap:
return m.validateMap(k, raw, schema, c)
case TypeBool:
// Verify that we can parse this as the correct type
var n bool
Expand All @@ -1071,3 +1064,20 @@ func (m schemaMap) validatePrimitive(

return nil, nil
}

func (m schemaMap) validateType(
k string,
raw interface{},
schema *Schema,
c *terraform.ResourceConfig) ([]string, []error) {
switch schema.Type {
case TypeSet:
fallthrough
case TypeList:
return m.validateList(k, raw, schema, c)
case TypeMap:
return m.validateMap(k, raw, schema, c)
default:
return m.validatePrimitive(k, raw, schema, c)
}
}
39 changes: 39 additions & 0 deletions helper/schema/schema_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2503,6 +2503,45 @@ func TestSchemaMap_Validate(t *testing.T) {

Err: true,
},

{
Schema: map[string]*Schema{
"security_groups": &Schema{
Type: TypeSet,
Optional: true,
Computed: true,
ForceNew: true,
Elem: &Schema{Type: TypeString},
Set: func(v interface{}) int {
return len(v.(string))
},
},
},

Config: map[string]interface{}{
"security_groups": []interface{}{"${var.foo}"},
},

Err: false,
},

{
Schema: map[string]*Schema{
"security_groups": &Schema{
Type: TypeSet,
Optional: true,
Computed: true,
ForceNew: true,
Elem: &Schema{Type: TypeString},
},
},

Config: map[string]interface{}{
"security_groups": "${var.foo}",
},

Err: true,
},
}

for i, tc := range cases {
Expand Down
16 changes: 16 additions & 0 deletions terraform/context_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4148,6 +4148,22 @@ func TestContextPlan_varMultiCountOne(t *testing.T) {
}
}

func TestContextPlan_varListErr(t *testing.T) {
m := testModule(t, "plan-var-list-err")
p := testProvider("aws")
ctx := testContext(t, &ContextOpts{
Module: m,
Providers: map[string]ResourceProviderFactory{
"aws": testProviderFuncFixed(p),
},
})

_, err := ctx.Plan(nil)
if err == nil {
t.Fatal("should error")
}
}

func TestContextRefresh(t *testing.T) {
p := testProvider("aws")
m := testModule(t, "refresh-basic")
Expand Down
16 changes: 16 additions & 0 deletions terraform/test-fixtures/plan-var-list-err/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
provider "aws" {
access_key = "a"
secret_key = "b"
region = "us-east-1"
}

resource "aws_instance" "foo" {
ami = "ami-foo"
instance_type = "t2.micro"
security_groups = "${aws_security_group.foo.name}"
}

resource "aws_security_group" "foo" {
name = "foobar"
description = "foobar"
}
8 changes: 4 additions & 4 deletions website/source/docs/configuration/interpolation.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ will interpolate the ID attribute from the "aws\_instance"
resource named "web". If the resource has a `count` attribute set,
you can access individual attributes with a zero-based index, such
as `${aws_instance.web.0.id}`. You can also use the splat syntax
to get a list of all the attributes: `${aws_instance.web.*.id}`.
to get an array of all the attributes: `${aws_instance.web.*.id}`.
This is documented in more detail in the
[resource configuration page](/docs/configuration/resources.html).

Expand Down Expand Up @@ -68,16 +68,16 @@ The supported built-in functions are:
in this file are _not_ interpolated. The contents of the file are
read as-is.

* `join(delim, list)` - Joins the list with the delimiter. A list is
* `join(delim, array)` - Joins the array with the delimiter. An array is
only possible with splat variables from resources with a count
greater than one. Example: `join(",", aws_instance.foo.*.id)`

* `lookup(map, key)` - Performs a dynamic lookup into a mapping
variable.

* `element(list, index)` - Returns a single element from a list
* `element(array, index)` - Returns a single element from an array
at the given index. If the index is greater than the number of
elements, this function will wrap using a standard mod algorithm.
A list is only possible with splat variables from resources with
An array is only possible with splat variables from resources with
a count greater than one.
Example: `element(aws_subnet.foo.*.id, count.index)`
2 changes: 1 addition & 1 deletion website/source/docs/configuration/resources.html.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ There are **meta-parameters** available to all resources:
[interpolation](/docs/configuration/interpolation.html) to reference
the current count index in your resource.

* `depends_on` (list of strings) - Explicit dependencies that this
* `depends_on` (array of strings) - Explicit dependencies that this
resource has. These dependencies will be created before this
resource. The dependencies are in the format of `TYPE.NAME`,
for example `aws_instance.web`.
Expand Down
8 changes: 4 additions & 4 deletions website/source/docs/providers/aws/r/autoscale.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,17 @@ The following arguments are supported:
* `name` - (Required) The name of the auto scale group.
* `max_size` - (Required) The maximum size of the auto scale group.
* `min_size` - (Required) The minimum size of the auto scale group.
* `availability_zones` - (Required) A list of AZs to launch resources in.
* `availability_zones` - (Required) An array of AZs to launch resources in.
* `launch_configuration` - (Required) The ID of the launch configuration to use.
* `health_check_grace_period` - (Optional) Time after instance comes into service before checking health.
* `health_check_type` - (Optional) "EC2" or "ELB". Controls how health checking is done.
* `desired_capacity` - (Optional) The number of Amazon EC2 instances that should be running in the group.
* `force_delete` - (Optional) Allows deleting the autoscaling group without waiting
for all instances in the pool to terminate.
* `load_balancers` (Optional) A list of load balancer names to add to the autoscaling
* `load_balancers` (Optional) An array of load balancer names to add to the autoscaling
group names.
* `vpc_zone_identifier` (Optional) A list of subnet IDs to launch resources in.
* `termination_policies` (Optional) A list of policies to decide how the instances in the auto scale group should be terminated.
* `vpc_zone_identifier` (Optional) An array of subnet IDs to launch resources in.
* `termination_policies` (Optional) An array of policies to decide how the instances in the auto scale group should be terminated.

## Attributes Reference

Expand Down
4 changes: 2 additions & 2 deletions website/source/docs/providers/aws/r/db_instance.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,9 @@ The following arguments are supported:
* `multi_az` - (Optional) Specifies if the RDS instance is multi-AZ
* `port` - (Optional) The port on which the DB accepts connections.
* `publicly_accessible` - (Optional) Bool to control if instance is publicly accessible.
* `vpc_security_group_ids` - (Optional) List of VPC security groups to associate.
* `vpc_security_group_ids` - (Optional) Array of VPC security groups to associate.
* `skip_final_snapshot` - (Optional) Enables skipping the final snapshot on deletion.
* `security_group_names` - (Optional) List of DB Security Groups to associate.
* `security_group_names` - (Optional) Array of DB Security Groups to associate.
* `db_subnet_group_name` - (Optional) Name of DB subnet group
* `parameter_group_name` - (Optional) Name of the DB parameter group to associate.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ The following arguments are supported:
* `name` - (Required) The name of the DB parameter group.
* `family` - (Required) The family of the DB parameter group.
* `description` - (Required) The description of the DB parameter group.
* `parameter` - (Optional) A list of DB parameters to apply.
* `parameter` - (Optional) An array of DB parameters to apply.

Parameter blocks support the following:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ The following arguments are supported:

* `name` - (Required) The name of the DB security group.
* `description` - (Required) The description of the DB security group.
* `ingress` - (Optional) A list of ingress rules.
* `ingress` - (Optional) An array of ingress rules.

Ingress blocks support the following:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ The following arguments are supported:

* `name` - (Required) The name of the DB security group.
* `description` - (Required) The description of the DB security group.
* `subnet_ids` - (Required) A list of ingress rules.
* `subnet_ids` - (Required) An array of ingress rules.

## Attributes Reference

Expand Down
10 changes: 5 additions & 5 deletions website/source/docs/providers/aws/r/elb.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,11 @@ The following arguments are supported:

* `name` - (Required) The name of the ELB
* `availability_zones` - (Optional) The AZ's to serve traffic in.
* `security_groups` - (Optional) A list of security group IDs to assign to the ELB.
* `subnets` - (Optional) A list of subnets to attach to the ELB.
* `instances` - (Optional) A list of instance ids to place in the ELB pool.
* `security_groups` - (Optional) An array of security group IDs to assign to the ELB.
* `subnets` - (Optional) An array of subnets to attach to the ELB.
* `instances` - (Optional) An array of instance ids to place in the ELB pool.
* `internal` - (Optional) If true, ELB will be an internal ELB.
* `listener` - (Required) A list of listener blocks. Listeners documented below.
* `listener` - (Required) An array of listener blocks. Listeners documented below.
* `health_check` - (Optional) A health_check block. Health Check documented below.
* `cross_zone_load_balancing` - (Optional) Enable cross-zone load balancing.

Expand All @@ -83,4 +83,4 @@ The following attributes are exported:
* `id` - The name of the ELB
* `name` - The name of the ELB
* `dns_name` - The DNS name of the ELB
* `instances` - The list of instances in the ELB
* `instances` - The array of instances in the ELB
4 changes: 2 additions & 2 deletions website/source/docs/providers/aws/r/instance.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ The following arguments are supported:
EBS-optimized.
* `instance_type` - (Required) The type of instance to start
* `key_name` - (Optional) The key name to use for the instance.
* `security_groups` - (Optional) A list of security group IDs or names to associate with.
* `security_groups` - (Optional) An array of security group IDs or names to associate with.
If you are within a non-default VPC, you'll need to use the security group ID. Otherwise,
for EC2 and the default VPC, use the security group name.
* `subnet_id` - (Optional) The VPC Subnet ID to launch in.
Expand All @@ -47,7 +47,7 @@ The following arguments are supported:
* `iam_instance_profile` - (Optional) The IAM Instance Profile to
launch the instance with.
* `tags` - (Optional) A mapping of tags to assign to the resource.
* `block_device` - (Optional) A list of block devices to add. Their keys are documented below.
* `block_device` - (Optional) An array of block devices to add. Their keys are documented below.

Each `block_device` supports the following:

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ The following arguments are supported:
* `iam_instance_profile` - (Optional) The IAM instance profile to associate
with launched instances.
* `key_name` - (Optional) The key name that should be used for the instance.
* `security_groups` - (Optional) A list of associated security group IDS.
* `security_groups` - (Optional) An array of associated security group IDS.
* `user_data` - (Optional) The user data to provide when launching the instance.

## Attributes Reference
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ The following arguments are supported:
* `name` - (Required) The name of the record.
* `type` - (Required) The record type.
* `ttl` - (Required) The TTL of the record.
* `records` - (Required) A string list of records.
* `records` - (Required) A string array of records.

## Attributes Reference

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ resource "aws_route_table" "r" {
The following arguments are supported:

* `vpc_id` - (Required) The ID of the routing table.
* `route` - (Optional) A list of route objects. Their keys are documented below.
* `route` - (Optional) An array of route objects. Their keys are documented below.
* `tags` - (Optional) A mapping of tags to assign to the resource.

Each route supports the following:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,10 +61,10 @@ The following arguments are supported:

The `ingress` block supports:

* `cidr_blocks` - (Optional) List of CIDR blocks. Cannot be used with `security_groups`.
* `cidr_blocks` - (Optional) Array of CIDR blocks. Cannot be used with `security_groups`.
* `from_port` - (Required) The start port.
* `protocol` - (Required) The protocol.
* `security_groups` - (Optional) List of security group IDs. Cannot be used with `cidr_blocks`.
* `security_groups` - (Optional) Array of security group IDs. Cannot be used with `cidr_blocks`.
* `self` - (Optional) If true, the security group itself will be added as
a source to this ingress rule.
* `to_port` - (Required) The end range port.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ The `rule` block supports:
* `icmp_code` - (Optional) The ICMP code to allow. This can only be specified if
the protocol is ICMP.

* `ports` - (Optional) List of ports and/or port ranges to allow. This can only
* `ports` - (Optional) Array of ports and/or port ranges to allow. This can only
be specified if the protocol is TCP or UDP.

## Attributes Reference
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ The `rule` block supports:
* `icmp_code` - (Optional) The ICMP code to allow. This can only be specified if
the protocol is ICMP.

* `ports` - (Optional) List of ports and/or port ranges to allow. This can only
* `ports` - (Optional) Array of ports and/or port ranges to allow. This can only
be specified if the protocol is TCP, UDP, ALL or a valid protocol number.

* `traffic_type` - (Optional) The traffic type for the rule. Valid options are:
Expand Down
2 changes: 1 addition & 1 deletion website/source/docs/providers/do/r/droplet.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ The following arguments are supported:
* `backups` - (Optional) Boolean controlling if backups are made.
* `ipv6` - (Optional) Boolean controlling if IPv6 is enabled.
* `private_networking` - (Optional) Boolean controlling if private networks are enabled.
* `ssh_keys` - (Optional) A list of SSH IDs or fingerprints to enable in
* `ssh_keys` - (Optional) An array of SSH IDs or fingerprints to enable in
the format `[12345, 123456]`. To retrieve this info, use a tool such
as `curl` with the [DigitalOcean API](https://developers.digitalocean.com/#keys),
to retrieve them.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -42,18 +42,18 @@ The following arguments are supported:
* `allow` - (Required) Can be specified multiple times for each allow
rule. Each allow block supports fields documented below.

* `source_ranges` - (Optional) A list of source CIDR ranges that this
* `source_ranges` - (Optional) An array of source CIDR ranges that this
firewall applies to.

* `source_tags` - (Optional) A list of source tags that this firewall applies to.
* `source_tags` - (Optional) An array of source tags that this firewall applies to.

* `target_tags` - (Optional) A list of target tags that this firewall applies to.
* `target_tags` - (Optional) An array of target tags that this firewall applies to.

The `allow` block supports:

* `protocol` - (Required) The name of the protocol to allow.

* `ports` - (Optional) List of ports and/or port ranges to allow. This can
* `ports` - (Optional) Array of ports and/or port ranges to allow. This can
only be specified if the protocol is TCP or UDP.

## Attributes Reference
Expand Down
Loading

0 comments on commit 152e72f

Please sign in to comment.