From c8c526d25411a4b41e5dff60b5722d8fa4ba5ec9 Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Thu, 24 Jul 2014 15:44:28 -0700 Subject: [PATCH 1/2] website: config syntax --- .../source/docs/configuration/syntax.html.md | 122 ++++++++++++++++++ 1 file changed, 122 insertions(+) create mode 100644 website/source/docs/configuration/syntax.html.md diff --git a/website/source/docs/configuration/syntax.html.md b/website/source/docs/configuration/syntax.html.md new file mode 100644 index 000000000..6d930de32 --- /dev/null +++ b/website/source/docs/configuration/syntax.html.md @@ -0,0 +1,122 @@ +--- +layout: "docs" +page_title: "Configuration Syntax" +sidebar_current: "docs-config-syntax" +--- + +# Configuration Syntax + +The syntax of Terraform configurations is custom. It is meant to +strike a balance between human readable and editable as well as being +machine-friendly. For machine-friendliness, Terraform can also +read JSON configurations. For general Terraform configurations, +however, we recommend using the Terraform syntax. + +## Terraform Syntax + +Here is an example of Terraform syntax: + +``` +# An AMI +variable "ami" { + description = "the AMI to use" +} + +/* A multi + line comment. */ +resource "aws_instance" "web" { + ami = "${var.ami}" + count = 2 + source_dest_check = false + + connection { + user = "root" + } +} +``` + +Basic bullet point reference: + + * Single line comments start with `#` + + * Multi-line comments are wrapped with `/*` and `*/` + + * Values are assigned with the syntax of `key = value` (whitespace + doesn't matter). The value can be any primitive: a string, + number, or boolean. + + * Strings are in double-quotes. + + * Numbers are assumed to be base 10. If you prefix a number with + `0x`, it is treated as a hexadecimal number. + + * Numbers can be suffxed with `kKmMgG` for some multiple of 10. + For example: `1k` is equal to `1000`. + + * Numbers can be suffxed with `[kKmMgG]b` for power of 2 multiples, + example: `1kb` is equal to `1024`. + + * Boolean values: `true`, `false`, `on`, `off`, `yes`, `no`. + + * Arrays of primitive types can be made by wrapping it in `[]`. + Example: `["foo", "bar", 42]`. + + * Maps can be made with the `{}` syntax: + `{ "foo": "bar", "bar": "baz" }`. + +In addition to the basics, the syntax supports hierarchies of sections, +such as the "resource" and "variable" in the example above. These +sections are similar to maps, but visually look better. For example, +these are nearly equivalent: + +``` +variable "ami" { + description = "the AMI to use" +} + +# is equal to: + +variable = [{ + "ami": { + "description": "the AMI to use", + } +}] +``` + +Notice that the top visually looks a lot better? By repeating multiple +`variable` sections, it adds the `variable` array. When possible, use +sections since they're visually clearer and more reasily readable. + +## JSON Syntax + +Terraform also supports reading JSON formatted configuration files. +The above example converted to JSON: + +```json +{ + "variable": { + "ami": { + "description": "the AMI to use" + } + }, + + "resource": { + "aws_instance": { + "web": { + "ami": "${var.ami}", + "count": 2, + "source_dest_check": false, + + "connection": { + "user": "root" + } + } + } + } +} +``` + +The conversion should be pretty straightforward and self-documented. + +The downsides of JSON are less human readability and the lack of +comments. Otherwise, the two are completely interoperable. From 298483131b7b5e8f70013c9d72e1c9706f18e478 Mon Sep 17 00:00:00 2001 From: Jack Pearkes Date: Thu, 24 Jul 2014 18:50:18 -0400 Subject: [PATCH 2/2] providers/aws: fixed tons of aws stuff --- builtin/providers/aws/resource_aws_elb.go | 7 +++-- .../aws/resource_aws_security_group.go | 5 +++- builtin/providers/aws/structure.go | 30 ++++++++++++++----- builtin/providers/aws/structure_test.go | 12 ++++++-- .../dnsimple/resource_dnsimple_record.go | 6 ++++ 5 files changed, 47 insertions(+), 13 deletions(-) diff --git a/builtin/providers/aws/resource_aws_elb.go b/builtin/providers/aws/resource_aws_elb.go index d62f69552..345001199 100644 --- a/builtin/providers/aws/resource_aws_elb.go +++ b/builtin/providers/aws/resource_aws_elb.go @@ -29,7 +29,10 @@ func resource_aws_elb_create( // Expand the "listener" array to goamz compat []elb.Listener v := flatmap.Expand(rs.Attributes, "listener").([]interface{}) - listeners := expandListeners(v) + listeners, err := expandListeners(v) + if err != nil { + return nil, err + } v = flatmap.Expand(rs.Attributes, "availability_zones").([]interface{}) zones := expandStringList(v) @@ -43,7 +46,7 @@ func resource_aws_elb_create( log.Printf("[DEBUG] ELB create configuration: %#v", elbOpts) - _, err := elbconn.CreateLoadBalancer(elbOpts) + _, err = elbconn.CreateLoadBalancer(elbOpts) if err != nil { return nil, fmt.Errorf("Error creating ELB: %s", err) } diff --git a/builtin/providers/aws/resource_aws_security_group.go b/builtin/providers/aws/resource_aws_security_group.go index 14d57d620..f14321f24 100644 --- a/builtin/providers/aws/resource_aws_security_group.go +++ b/builtin/providers/aws/resource_aws_security_group.go @@ -67,7 +67,10 @@ func resource_aws_security_group_create( ingressRules := []ec2.IPPerm{} v, ok := flatmap.Expand(rs.Attributes, "ingress").([]interface{}) if ok { - ingressRules = expandIPPerms(v) + ingressRules, err = expandIPPerms(v) + if err != nil { + return rs, err + } } if len(ingressRules) > 0 { diff --git a/builtin/providers/aws/structure.go b/builtin/providers/aws/structure.go index b8669d97f..aac6d50d8 100644 --- a/builtin/providers/aws/structure.go +++ b/builtin/providers/aws/structure.go @@ -1,6 +1,7 @@ package aws import ( + "strconv" "strings" "github.com/mitchellh/goamz/autoscaling" @@ -10,7 +11,7 @@ import ( // Takes the result of flatmap.Expand for an array of listeners and // returns ELB API compatible objects -func expandListeners(configured []interface{}) []elb.Listener { +func expandListeners(configured []interface{}) ([]elb.Listener, error) { listeners := make([]elb.Listener, 0, len(configured)) // Loop over our configured listeners and create @@ -18,22 +19,29 @@ func expandListeners(configured []interface{}) []elb.Listener { for _, listener := range configured { newL := listener.(map[string]interface{}) + instancePort, err := strconv.ParseInt(newL["instance_port"].(string), 0, 0) + lbPort, err := strconv.ParseInt(newL["lb_port"].(string), 0, 0) + + if err != nil { + return nil, err + } + l := elb.Listener{ - InstancePort: int64(newL["instance_port"].(int)), + InstancePort: instancePort, InstanceProtocol: newL["instance_protocol"].(string), - LoadBalancerPort: int64(newL["lb_port"].(int)), + LoadBalancerPort: lbPort, Protocol: newL["lb_protocol"].(string), } listeners = append(listeners, l) } - return listeners + return listeners, nil } // Takes the result of flatmap.Expand for an array of ingress/egress // security group rules and returns EC2 API compatible objects -func expandIPPerms(configured []interface{}) []ec2.IPPerm { +func expandIPPerms(configured []interface{}) ([]ec2.IPPerm, error) { perms := make([]ec2.IPPerm, 0, len(configured)) // Loop over our configured permissions and create @@ -54,11 +62,17 @@ func expandIPPerms(configured []interface{}) []ec2.IPPerm { } } + fromPort, err := strconv.Atoi(newP["from_port"].(string)) + toPort, err := strconv.Atoi(newP["to_port"].(string)) + if err != nil { + return nil, err + } + // Create the permission objet p := ec2.IPPerm{ Protocol: newP["protocol"].(string), - FromPort: newP["from_port"].(int), - ToPort: newP["to_port"].(int), + FromPort: fromPort, + ToPort: toPort, SourceIPs: expandStringList(newP["cidr_blocks"].([]interface{})), SourceGroups: expandedGroups, } @@ -66,7 +80,7 @@ func expandIPPerms(configured []interface{}) []ec2.IPPerm { perms = append(perms, p) } - return perms + return perms, nil } // Flattens an array of ipPerms into a list of primitives that diff --git a/builtin/providers/aws/structure_test.go b/builtin/providers/aws/structure_test.go index 803e4f376..31d8662db 100644 --- a/builtin/providers/aws/structure_test.go +++ b/builtin/providers/aws/structure_test.go @@ -33,7 +33,11 @@ func testConf() map[string]string { func Test_expandIPPerms(t *testing.T) { expanded := flatmap.Expand(testConf(), "ingress").([]interface{}) - perms := expandIPPerms(expanded) + perms, err := expandIPPerms(expanded) + + if err != nil { + t.Fatalf("bad: %#v", err) + } expected := ec2.IPPerm{ Protocol: "icmp", FromPort: 1, @@ -118,7 +122,11 @@ func Test_flattenIPPerms(t *testing.T) { func Test_expandListeners(t *testing.T) { expanded := flatmap.Expand(testConf(), "listener").([]interface{}) - listeners := expandListeners(expanded) + listeners, err := expandListeners(expanded) + if err != nil { + t.Fatalf("bad: %#v", err) + } + expected := elb.Listener{ InstancePort: 8000, LoadBalancerPort: 80, diff --git a/builtin/providers/dnsimple/resource_dnsimple_record.go b/builtin/providers/dnsimple/resource_dnsimple_record.go index 611cc3606..b3d2da13f 100644 --- a/builtin/providers/dnsimple/resource_dnsimple_record.go +++ b/builtin/providers/dnsimple/resource_dnsimple_record.go @@ -159,6 +159,12 @@ func resource_dnsimple_record_update_state( s.Attributes["priority"] = rec.StringPrio() s.Attributes["domain_id"] = rec.StringDomainId() + if rec.Name == "" { + s.Attributes["hostname"] = s.Attributes["domain"] + } else { + s.Attributes["hostname"] = fmt.Sprintf("%s.%s", rec.Name, s.Attributes["domain"]) + } + return s, nil }