func Test_expandIPPerms_NoCidr(t *testing.T) { conf := testConf() delete(conf, "ingress.0.cidr_blocks.#") delete(conf, "ingress.0.cidr_blocks.0") expanded := flatmap.Expand(conf, "ingress").([]interface{}) perms, err := expandIPPerms(expanded) if err != nil { t.Fatalf("bad: %#v", err) } expected := ec2.IPPerm{ Protocol: "icmp", FromPort: 1, ToPort: -1, SourceGroups: []ec2.UserSecurityGroup{ ec2.UserSecurityGroup{ Id: "sg-11111", }, }, } if !reflect.DeepEqual(perms[0], expected) { t.Fatalf( "Got:\n\n%#v\n\nExpected:\n\n%#v\n", perms[0], expected) } }
func resource_consul_keys_destroy( s *terraform.ResourceState, meta interface{}) error { p := meta.(*ResourceProvider) client := p.client kv := client.KV() // Get the keys keys, ok := flatmap.Expand(s.Attributes, "key").([]interface{}) if !ok { return fmt.Errorf("Failed to unroll keys") } dc := s.Attributes["datacenter"] wOpts := consulapi.WriteOptions{Datacenter: dc} for _, raw := range keys { _, path, sub, err := parse_key(raw) if err != nil { return err } // Ignore if the key is non-managed shouldDelete, ok := sub["delete"].(bool) if !ok || !shouldDelete { continue } log.Printf("[DEBUG] Deleting key '%s' in %s", path, dc) if _, err := kv.Delete(path, &wOpts); err != nil { return fmt.Errorf("Failed to delete Consul key '%s': %v", path, err) } } return nil }
func resource_consul_keys_diff( s *terraform.ResourceState, c *terraform.ResourceConfig, meta interface{}) (*terraform.ResourceDiff, error) { // Determine the list of computed variables var computed []string keys, ok := flatmap.Expand(flatmap.Flatten(c.Config), "key").([]interface{}) if !ok { goto AFTER } for _, sub := range keys { key, _, _, err := parse_key(sub) if err != nil { continue } computed = append(computed, "var."+key) } AFTER: b := &diff.ResourceBuilder{ Attrs: map[string]diff.AttrType{ "datacenter": diff.AttrTypeCreate, "key": diff.AttrTypeUpdate, }, ComputedAttrsUpdate: computed, } return b.Diff(s, c) }
func Test_expandIPPerms(t *testing.T) { expanded := flatmap.Expand(testConf(), "ingress").([]interface{}) perms, err := expandIPPerms(expanded) if err != nil { t.Fatalf("bad: %#v", err) } expected := ec2.IPPerm{ Protocol: "icmp", FromPort: 1, ToPort: -1, SourceIPs: []string{"0.0.0.0/0"}, SourceGroups: []ec2.UserSecurityGroup{ ec2.UserSecurityGroup{ Id: "sg-11111", }, }, } if !reflect.DeepEqual(perms[0], expected) { t.Fatalf( "Got:\n\n%#v\n\nExpected:\n\n%#v\n", perms[0], expected) } }
func resource_aws_launch_configuration_create( s *terraform.ResourceState, d *terraform.ResourceDiff, meta interface{}) (*terraform.ResourceState, error) { p := meta.(*ResourceProvider) autoscalingconn := p.autoscalingconn // Merge the diff into the state so that we have all the attributes // properly. rs := s.MergeDiff(d) var err error createLaunchConfigurationOpts := autoscaling.CreateLaunchConfiguration{} if rs.Attributes["image_id"] != "" { createLaunchConfigurationOpts.ImageId = rs.Attributes["image_id"] } if rs.Attributes["instance_type"] != "" { createLaunchConfigurationOpts.InstanceType = rs.Attributes["instance_type"] } if rs.Attributes["instance_id"] != "" { createLaunchConfigurationOpts.InstanceId = rs.Attributes["instance_id"] } if rs.Attributes["key_name"] != "" { createLaunchConfigurationOpts.KeyName = rs.Attributes["key_name"] } if err != nil { return nil, fmt.Errorf("Error parsing configuration: %s", err) } if _, ok := rs.Attributes["security_groups.#"]; ok { createLaunchConfigurationOpts.SecurityGroups = expandStringList(flatmap.Expand( rs.Attributes, "security_groups").([]interface{})) } createLaunchConfigurationOpts.Name = rs.Attributes["name"] log.Printf("[DEBUG] autoscaling create launch configuration: %#v", createLaunchConfigurationOpts) _, err = autoscalingconn.CreateLaunchConfiguration(&createLaunchConfigurationOpts) if err != nil { return nil, fmt.Errorf("Error creating launch configuration: %s", err) } rs.ID = rs.Attributes["name"] log.Printf("[INFO] launch configuration ID: %s", rs.ID) g, err := resource_aws_launch_configuration_retrieve(rs.ID, autoscalingconn) if err != nil { return rs, err } return resource_aws_launch_configuration_update_state(rs, g) }
func (i *Interpolater) interpolateComplexTypeAttribute( resourceID string, attributes map[string]string) (ast.Variable, error) { // We can now distinguish between lists and maps in state by the count field: // - lists (and by extension, sets) use the traditional .# notation // - maps use the newer .% notation // Consequently here we can decide how to deal with the keys appropriately // based on whether the type is a map of list. if lengthAttr, isList := attributes[resourceID+".#"]; isList { log.Printf("[DEBUG] Interpolating computed list element attribute %s (%s)", resourceID, lengthAttr) // In Terraform's internal dotted representation of list-like attributes, the // ".#" count field is marked as unknown to indicate "this whole list is // unknown". We must honor that meaning here so computed references can be // treated properly during the plan phase. if lengthAttr == config.UnknownVariableValue { return unknownVariable(), nil } expanded := flatmap.Expand(attributes, resourceID) return hil.InterfaceToVariable(expanded) } if lengthAttr, isMap := attributes[resourceID+".%"]; isMap { log.Printf("[DEBUG] Interpolating computed map element attribute %s (%s)", resourceID, lengthAttr) // In Terraform's internal dotted representation of map attributes, the // ".%" count field is marked as unknown to indicate "this whole list is // unknown". We must honor that meaning here so computed references can be // treated properly during the plan phase. if lengthAttr == config.UnknownVariableValue { return unknownVariable(), nil } expanded := flatmap.Expand(attributes, resourceID) return hil.InterfaceToVariable(expanded) } return ast.Variable{}, fmt.Errorf("No complex type %s found", resourceID) }
func resource_aws_instance_update_state( s *terraform.ResourceState, instance *ec2.Instance) (*terraform.ResourceState, error) { s.Attributes["availability_zone"] = instance.AvailZone s.Attributes["key_name"] = instance.KeyName s.Attributes["public_dns"] = instance.DNSName s.Attributes["public_ip"] = instance.PublicIpAddress s.Attributes["private_dns"] = instance.PrivateDNSName s.Attributes["private_ip"] = instance.PrivateIpAddress s.Attributes["subnet_id"] = instance.SubnetId s.Dependencies = nil // Extract the existing security groups useID := false if raw := flatmap.Expand(s.Attributes, "security_groups"); raw != nil { if sgs, ok := raw.([]interface{}); ok { for _, sg := range sgs { str, ok := sg.(string) if !ok { continue } if strings.HasPrefix(str, "sg-") { useID = true break } } } } // Build up the security groups sgs := make([]string, len(instance.SecurityGroups)) for i, sg := range instance.SecurityGroups { if instance.SubnetId != "" && useID { sgs[i] = sg.Id } else { sgs[i] = sg.Name } s.Dependencies = append(s.Dependencies, terraform.ResourceDependency{ID: sg.Id}, ) } flatmap.Map(s.Attributes).Merge(flatmap.Flatten(map[string]interface{}{ "security_groups": sgs, })) if instance.SubnetId != "" { s.Dependencies = append(s.Dependencies, terraform.ResourceDependency{ID: instance.SubnetId}, ) } return s, nil }
func resource_heroku_app_create( s *terraform.ResourceState, d *terraform.ResourceDiff, meta interface{}) (*terraform.ResourceState, error) { p := meta.(*ResourceProvider) client := p.client // Merge the diff into the state so that we have all the attributes // properly. rs := s.MergeDiff(d) // Build up our creation options opts := heroku.AppCreateOpts{} if attr := rs.Attributes["name"]; attr != "" { opts.Name = &attr } if attr := rs.Attributes["region"]; attr != "" { opts.Region = &attr } if attr := rs.Attributes["stack"]; attr != "" { opts.Stack = &attr } log.Printf("[DEBUG] App create configuration: %#v", opts) a, err := client.AppCreate(&opts) if err != nil { return s, err } rs.ID = a.Name log.Printf("[INFO] App ID: %s", rs.ID) if attr, ok := rs.Attributes["config_vars.#"]; ok && attr == "1" { vs := flatmap.Expand( rs.Attributes, "config_vars").([]interface{}) err = update_config_vars(rs.ID, vs, client) if err != nil { return rs, err } } app, err := resource_heroku_app_retrieve(rs.ID, client) if err != nil { return rs, err } return resource_heroku_app_update_state(rs, app) }
func Test_expandIPPerms_bad(t *testing.T) { badConf := map[string]string{ "ingress.#": "1", "ingress.0.from_port": "not number", } expanded := flatmap.Expand(badConf, "ingress").([]interface{}) perms, err := expandIPPerms(expanded) if err == nil { t.Fatalf("should have err: %#v", perms) } }
func resource_heroku_app_update( s *terraform.ResourceState, d *terraform.ResourceDiff, meta interface{}) (*terraform.ResourceState, error) { p := meta.(*ResourceProvider) client := p.client rs := s.MergeDiff(d) if attr, ok := d.Attributes["name"]; ok { opts := heroku.AppUpdateOpts{ Name: &attr.New, } renamedApp, err := client.AppUpdate(rs.ID, &opts) if err != nil { return s, err } // Store the new ID rs.ID = renamedApp.Name } attr, ok := s.Attributes["config_vars.#"] // If the config var block was removed, nuke all config vars if ok && attr == "1" { vs := flatmap.Expand( rs.Attributes, "config_vars").([]interface{}) err := update_config_vars(rs.ID, vs, client) if err != nil { return rs, err } } else if ok && attr == "0" { log.Println("[INFO] Config vars removed, removing all vars") err := update_config_vars(rs.ID, make([]interface{}, 0), client) if err != nil { return rs, err } } app, err := resource_heroku_app_retrieve(rs.ID, client) if err != nil { return rs, err } return resource_heroku_app_update_state(rs, app) }
func TestExpandStringList(t *testing.T) { expanded := flatmap.Expand(testConf(), "availability_zones").([]interface{}) stringList := expandStringList(expanded) expected := []*string{ aws.String("us-east-1a"), aws.String("us-east-1b"), } if !reflect.DeepEqual(stringList, expected) { t.Fatalf( "Got:\n\n%#v\n\nExpected:\n\n%#v\n", stringList, expected) } }
func resource_heroku_addon_create( s *terraform.ResourceState, d *terraform.ResourceDiff, meta interface{}) (*terraform.ResourceState, error) { addonLock.Lock() defer addonLock.Unlock() p := meta.(*ResourceProvider) client := p.client // Merge the diff into the state so that we have all the attributes // properly. rs := s.MergeDiff(d) app := rs.Attributes["app"] plan := rs.Attributes["plan"] opts := heroku.AddonCreateOpts{} if attr, ok := rs.Attributes["config.#"]; ok && attr == "1" { vs := flatmap.Expand( rs.Attributes, "config").([]interface{}) config := make(map[string]string) for k, v := range vs[0].(map[string]interface{}) { config[k] = v.(string) } opts.Config = &config } log.Printf("[DEBUG] Addon create configuration: %#v, %#v, %#v", app, plan, opts) a, err := client.AddonCreate(app, plan, &opts) if err != nil { return s, err } rs.ID = a.Id log.Printf("[INFO] Addon ID: %s", rs.ID) addon, err := resource_heroku_addon_retrieve(app, rs.ID, client) if err != nil { return rs, err } return resource_heroku_addon_update_state(rs, addon) }
func resource_aws_r53_build_record_set(s *terraform.ResourceState) (*route53.ResourceRecordSet, error) { // Parse the TTL ttl, err := strconv.ParseInt(s.Attributes["ttl"], 10, 32) if err != nil { return nil, err } // Expand the records recRaw := flatmap.Expand(s.Attributes, "records") var records []string for _, raw := range recRaw.([]interface{}) { records = append(records, raw.(string)) } rec := &route53.ResourceRecordSet{ Name: s.Attributes["name"], Type: s.Attributes["type"], TTL: int(ttl), Records: records, } return rec, nil }
func Test_expandListeners(t *testing.T) { expanded := flatmap.Expand(testConf(), "listener").([]interface{}) listeners, err := expandListeners(expanded) if err != nil { t.Fatalf("bad: %#v", err) } expected := elb.Listener{ InstancePort: 8000, LoadBalancerPort: 80, InstanceProtocol: "http", Protocol: "http", } if !reflect.DeepEqual(listeners[0], expected) { t.Fatalf( "Got:\n\n%#v\n\nExpected:\n\n%#v\n", listeners[0], expected) } }
func resource_consul_keys_refresh( s *terraform.ResourceState, meta interface{}) (*terraform.ResourceState, error) { p := meta.(*ResourceProvider) client := p.client kv := client.KV() // Get the list of keys keys, ok := flatmap.Expand(s.Attributes, "key").([]interface{}) if !ok { return s, fmt.Errorf("Failed to unroll keys") } // Update each key dc := s.Attributes["datacenter"] opts := consulapi.QueryOptions{Datacenter: dc} for idx, raw := range keys { key, path, sub, err := parse_key(raw) if err != nil { return s, err } log.Printf("[DEBUG] Refreshing value of key '%s' in %s", path, dc) pair, _, err := kv.Get(path, &opts) if err != nil { return s, fmt.Errorf("Failed to get value for path '%s' from Consul: %v", path, err) } setVal := attribute_value(sub, key, pair) s.Attributes[fmt.Sprintf("var.%s", key)] = setVal if _, ok := sub["value"]; ok { s.Attributes[fmt.Sprintf("key.%d.value", idx)] = setVal } } return s, nil }
func resource_aws_security_group_create( s *terraform.ResourceState, d *terraform.ResourceDiff, meta interface{}) (*terraform.ResourceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn // Merge the diff into the state so that we have all the attributes // properly. rs := s.MergeDiff(d) securityGroupOpts := ec2.SecurityGroup{ Name: rs.Attributes["name"], } if rs.Attributes["vpc_id"] != "" { securityGroupOpts.VpcId = rs.Attributes["vpc_id"] } if rs.Attributes["description"] != "" { securityGroupOpts.Description = rs.Attributes["description"] } log.Printf("[DEBUG] Security Group create configuration: %#v", securityGroupOpts) createResp, err := ec2conn.CreateSecurityGroup(securityGroupOpts) if err != nil { return nil, fmt.Errorf("Error creating Security Group: %s", err) } rs.ID = createResp.Id group := createResp.SecurityGroup log.Printf("[INFO] Security Group ID: %s", rs.ID) // Wait for the security group to truly exist log.Printf( "[DEBUG] Waiting for SG (%s) to exist", s.ID) stateConf := &resource.StateChangeConf{ Pending: []string{""}, Target: "exists", Refresh: SGStateRefreshFunc(ec2conn, rs.ID), Timeout: 1 * time.Minute, } if _, err := stateConf.WaitForState(); err != nil { return s, fmt.Errorf( "Error waiting for SG (%s) to become available: %s", rs.ID, err) } // Expand the "ingress" array to goamz compat []ec2.IPPerm ingressRules := []ec2.IPPerm{} v, ok := flatmap.Expand(rs.Attributes, "ingress").([]interface{}) if ok { ingressRules, err = expandIPPerms(v) if err != nil { return rs, err } } if len(ingressRules) > 0 { _, err = ec2conn.AuthorizeSecurityGroup(group, ingressRules) if err != nil { return rs, fmt.Errorf("Error authorizing security group ingress rules: %s", err) } } return resource_aws_security_group_refresh(rs, meta) }
func resource_aws_elb_create( s *terraform.ResourceState, d *terraform.ResourceDiff, meta interface{}) (*terraform.ResourceState, error) { p := meta.(*ResourceProvider) elbconn := p.elbconn // Merge the diff into the state so that we have all the attributes // properly. rs := s.MergeDiff(d) // The name specified for the ELB. This is also our unique ID // we save to state if the creation is successful (amazon verifies // it is unique) elbName := rs.Attributes["name"] // Expand the "listener" array to goamz compat []elb.Listener v := flatmap.Expand(rs.Attributes, "listener").([]interface{}) listeners, err := expandListeners(v) if err != nil { return nil, err } // Provision the elb elbOpts := &elb.CreateLoadBalancer{ LoadBalancerName: elbName, Listeners: listeners, } if _, ok := rs.Attributes["availability_zones.#"]; ok { v = flatmap.Expand(rs.Attributes, "availability_zones").([]interface{}) zones := expandStringList(v) elbOpts.AvailZone = zones } log.Printf("[DEBUG] ELB create configuration: %#v", elbOpts) _, err = elbconn.CreateLoadBalancer(elbOpts) if err != nil { return nil, fmt.Errorf("Error creating ELB: %s", err) } // Assign the elb's unique identifier for use later rs.ID = elbName log.Printf("[INFO] ELB ID: %s", elbName) if _, ok := rs.Attributes["instances.#"]; ok { // If we have any instances, we need to register them v = flatmap.Expand(rs.Attributes, "instances").([]interface{}) instances := expandStringList(v) if len(instances) > 0 { registerInstancesOpts := elb.RegisterInstancesWithLoadBalancer{ LoadBalancerName: elbName, Instances: instances, } _, err := elbconn.RegisterInstancesWithLoadBalancer(®isterInstancesOpts) if err != nil { return rs, fmt.Errorf("Failure registering instances: %s", err) } } } if _, ok := rs.Attributes["health_check.#"]; ok { v := flatmap.Expand(rs.Attributes, "health_check").([]interface{}) health_check := v[0].(map[string]interface{}) healthyThreshold, err := strconv.ParseInt(health_check["healthy_threshold"].(string), 0, 0) unhealthyThreshold, err := strconv.ParseInt(health_check["unhealthy_threshold"].(string), 0, 0) interval, err := strconv.ParseInt(health_check["interval"].(string), 0, 0) timeout, err := strconv.ParseInt(health_check["timeout"].(string), 0, 0) if err != nil { return nil, err } configureHealthCheckOpts := elb.ConfigureHealthCheck{ LoadBalancerName: elbName, Check: elb.HealthCheck{ HealthyThreshold: healthyThreshold, UnhealthyThreshold: unhealthyThreshold, Interval: interval, Target: health_check["target"].(string), Timeout: timeout, }, } _, err = elbconn.ConfigureHealthCheck(&configureHealthCheckOpts) if err != nil { return rs, fmt.Errorf("Failure configuring health check: %s", err) } } loadBalancer, err := resource_aws_elb_retrieve_balancer(rs.ID, elbconn) if err != nil { return rs, err } return resource_aws_elb_update_state(rs, loadBalancer) }
func resource_aws_elb_update( s *terraform.ResourceState, d *terraform.ResourceDiff, meta interface{}) (*terraform.ResourceState, error) { p := meta.(*ResourceProvider) elbconn := p.elbconn rs := s.MergeDiff(d) // If we currently have instances, or did have instances, // we want to figure out what to add and remove from the load // balancer if attr, ok := d.Attributes["instances.#"]; ok && attr.Old != "" { // The new state of instances merged with the diff mergedInstances := expandStringList(flatmap.Expand( rs.Attributes, "instances").([]interface{})) // The state before the diff merge previousInstances := expandStringList(flatmap.Expand( s.Attributes, "instances").([]interface{})) // keep track of what instances we are removing, and which // we are adding var toRemove []string var toAdd []string for _, instanceId := range mergedInstances { for _, prevId := range previousInstances { // If the merged instance ID existed // previously, we don't have to do anything if instanceId == prevId { continue // Otherwise, we need to add it to the load balancer } else { toAdd = append(toAdd, instanceId) } } } for i, instanceId := range toAdd { for _, prevId := range previousInstances { // If the instance ID we are adding existed // previously, we want to not add it, but rather remove // it if instanceId == prevId { toRemove = append(toRemove, instanceId) toAdd = append(toAdd[:i], toAdd[i+1:]...) // Otherwise, we continue adding it to the ELB } else { continue } } } if len(toAdd) > 0 { registerInstancesOpts := elb.RegisterInstancesWithLoadBalancer{ LoadBalancerName: rs.ID, Instances: toAdd, } _, err := elbconn.RegisterInstancesWithLoadBalancer(®isterInstancesOpts) if err != nil { return s, fmt.Errorf("Failure registering instances: %s", err) } } if len(toRemove) > 0 { deRegisterInstancesOpts := elb.DeregisterInstancesFromLoadBalancer{ LoadBalancerName: rs.ID, Instances: toRemove, } _, err := elbconn.DeregisterInstancesFromLoadBalancer(&deRegisterInstancesOpts) if err != nil { return s, fmt.Errorf("Failure deregistering instances: %s", err) } } } loadBalancer, err := resource_aws_elb_retrieve_balancer(rs.ID, elbconn) if err != nil { return s, err } return resource_aws_elb_update_state(rs, loadBalancer) }
func resource_aws_autoscaling_group_create( s *terraform.ResourceState, d *terraform.ResourceDiff, meta interface{}) (*terraform.ResourceState, error) { p := meta.(*ResourceProvider) autoscalingconn := p.autoscalingconn // Merge the diff into the state so that we have all the attributes // properly. rs := s.MergeDiff(d) var err error autoScalingGroupOpts := autoscaling.CreateAutoScalingGroup{} if rs.Attributes["min_size"] != "" { autoScalingGroupOpts.MinSize, err = strconv.Atoi(rs.Attributes["min_size"]) autoScalingGroupOpts.SetMinSize = true } if rs.Attributes["max_size"] != "" { autoScalingGroupOpts.MaxSize, err = strconv.Atoi(rs.Attributes["max_size"]) autoScalingGroupOpts.SetMaxSize = true } if rs.Attributes["default_cooldown"] != "" { autoScalingGroupOpts.DefaultCooldown, err = strconv.Atoi(rs.Attributes["default_cooldown"]) autoScalingGroupOpts.SetDefaultCooldown = true } if rs.Attributes["desired_capacity"] != "" { autoScalingGroupOpts.DesiredCapacity, err = strconv.Atoi(rs.Attributes["desired_capacity"]) autoScalingGroupOpts.SetDesiredCapacity = true } if rs.Attributes["health_check_grace_period"] != "" { autoScalingGroupOpts.HealthCheckGracePeriod, err = strconv.Atoi(rs.Attributes["health_check_grace_period"]) autoScalingGroupOpts.SetHealthCheckGracePeriod = true } if err != nil { return nil, fmt.Errorf("Error parsing configuration: %s", err) } if _, ok := rs.Attributes["availability_zones.#"]; ok { autoScalingGroupOpts.AvailZone = expandStringList(flatmap.Expand( rs.Attributes, "availability_zones").([]interface{})) } if _, ok := rs.Attributes["load_balancers.#"]; ok { autoScalingGroupOpts.LoadBalancerNames = expandStringList(flatmap.Expand( rs.Attributes, "load_balancers").([]interface{})) } if _, ok := rs.Attributes["vpc_identifier.#"]; ok { autoScalingGroupOpts.VPCZoneIdentifier = expandStringList(flatmap.Expand( rs.Attributes, "vpc_identifier").([]interface{})) } autoScalingGroupOpts.Name = rs.Attributes["name"] autoScalingGroupOpts.HealthCheckType = rs.Attributes["health_check_type"] autoScalingGroupOpts.LaunchConfigurationName = rs.Attributes["launch_configuration"] log.Printf("[DEBUG] AutoScaling Group create configuration: %#v", autoScalingGroupOpts) _, err = autoscalingconn.CreateAutoScalingGroup(&autoScalingGroupOpts) if err != nil { return nil, fmt.Errorf("Error creating AutoScaling Group: %s", err) } rs.ID = rs.Attributes["name"] rs.Dependencies = []terraform.ResourceDependency{ terraform.ResourceDependency{ID: rs.Attributes["launch_configuration"]}, } log.Printf("[INFO] AutoScaling Group ID: %s", rs.ID) g, err := resource_aws_autoscaling_group_retrieve(rs.ID, autoscalingconn) if err != nil { return rs, err } return resource_aws_autoscaling_group_update_state(rs, g) }
func resource_digitalocean_droplet_create( s *terraform.ResourceState, d *terraform.ResourceDiff, meta interface{}) (*terraform.ResourceState, error) { p := meta.(*ResourceProvider) client := p.client // Merge the diff into the state so that we have all the attributes // properly. rs := s.MergeDiff(d) // Build up our creation options opts := digitalocean.CreateDroplet{ Backups: rs.Attributes["backups"], Image: rs.Attributes["image"], IPV6: rs.Attributes["ipv6"], Name: rs.Attributes["name"], PrivateNetworking: rs.Attributes["private_networking"], Region: rs.Attributes["region"], Size: rs.Attributes["size"], } // Only expand ssh_keys if we have them if _, ok := rs.Attributes["ssh_keys.#"]; ok { v := flatmap.Expand(rs.Attributes, "ssh_keys").([]interface{}) if len(v) > 0 { vs := make([]string, 0, len(v)) // here we special case the * expanded lists. For example: // // ssh_keys = ["${digitalocean_key.foo.*.id}"] // if len(v) == 1 && strings.Contains(v[0].(string), ",") { vs = strings.Split(v[0].(string), ",") } for _, v := range v { vs = append(vs, v.(string)) } opts.SSHKeys = vs } } log.Printf("[DEBUG] Droplet create configuration: %#v", opts) id, err := client.CreateDroplet(&opts) if err != nil { return nil, fmt.Errorf("Error creating Droplet: %s", err) } // Assign the droplets id rs.ID = id log.Printf("[INFO] Droplet ID: %s", id) dropletRaw, err := WaitForDropletAttribute(id, "active", []string{"new"}, "status", client) if err != nil { return rs, fmt.Errorf( "Error waiting for droplet (%s) to become ready: %s", id, err) } droplet := dropletRaw.(*digitalocean.Droplet) // Initialize the connection info rs.ConnInfo["type"] = "ssh" rs.ConnInfo["host"] = droplet.IPV4Address("public") return resource_digitalocean_droplet_update_state(rs, droplet) }
func resource_aws_route_table_update( s *terraform.ResourceState, d *terraform.ResourceDiff, meta interface{}) (*terraform.ResourceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn // Our resulting state rs := s.MergeDiff(d) // Get our routes out of the merge oldroutes := flatmap.Expand(s.Attributes, "route") routes := flatmap.Expand(s.MergeDiff(d).Attributes, "route") // Determine the route operations we need to perform ops := routeTableOps(oldroutes, routes) if len(ops) == 0 { return s, nil } // Go through each operation, performing each one at a time. // We store the updated state on each operation so that if any // individual operation fails, we can return a valid partial state. var err error resultRoutes := make([]map[string]string, 0, len(ops)) for _, op := range ops { switch op.Op { case routeTableOpCreate: opts := ec2.CreateRoute{ RouteTableId: s.ID, DestinationCidrBlock: op.Route.DestinationCidrBlock, GatewayId: op.Route.GatewayId, InstanceId: op.Route.InstanceId, } _, err = ec2conn.CreateRoute(&opts) case routeTableOpReplace: opts := ec2.ReplaceRoute{ RouteTableId: s.ID, DestinationCidrBlock: op.Route.DestinationCidrBlock, GatewayId: op.Route.GatewayId, InstanceId: op.Route.InstanceId, } _, err = ec2conn.ReplaceRoute(&opts) case routeTableOpDelete: _, err = ec2conn.DeleteRoute( s.ID, op.Route.DestinationCidrBlock) } if err != nil { // Exit early so we can return what we've done so far break } // If we didn't delete the route, append it to the list of routes // we have. if op.Op != routeTableOpDelete { resultMap := map[string]string{"cidr_block": op.Route.DestinationCidrBlock} if op.Route.GatewayId != "" { resultMap["gateway_id"] = op.Route.GatewayId } else if op.Route.InstanceId != "" { resultMap["instance_id"] = op.Route.InstanceId } resultRoutes = append(resultRoutes, resultMap) } } // Update our state with the settings flatmap.Map(rs.Attributes).Merge(flatmap.Flatten(map[string]interface{}{ "route": resultRoutes, })) return rs, err }
func resource_aws_db_security_group_create( s *terraform.ResourceState, d *terraform.ResourceDiff, meta interface{}) (*terraform.ResourceState, error) { p := meta.(*ResourceProvider) conn := p.rdsconn // Merge the diff into the state so that we have all the attributes // properly. rs := s.MergeDiff(d) var err error var errs []error opts := rds.CreateDBSecurityGroup{ DBSecurityGroupName: rs.Attributes["name"], DBSecurityGroupDescription: rs.Attributes["description"], } log.Printf("[DEBUG] DB Security Group create configuration: %#v", opts) _, err = conn.CreateDBSecurityGroup(&opts) if err != nil { return nil, fmt.Errorf("Error creating DB Security Group: %s", err) } rs.ID = rs.Attributes["name"] log.Printf("[INFO] DB Security Group ID: %s", rs.ID) v, err := resource_aws_db_security_group_retrieve(rs.ID, conn) if err != nil { return rs, err } if _, ok := rs.Attributes["ingress.#"]; ok { ingresses := flatmap.Expand( rs.Attributes, "ingress").([]interface{}) for _, ing := range ingresses { err = authorize_ingress_rule(ing, v.Name, conn) if err != nil { errs = append(errs, err) } } if len(errs) > 0 { return rs, &multierror.Error{Errors: errs} } } log.Println( "[INFO] Waiting for Ingress Authorizations to be authorized") stateConf := &resource.StateChangeConf{ Pending: []string{"authorizing"}, Target: "authorized", Refresh: DBSecurityGroupStateRefreshFunc(rs.ID, conn), Timeout: 10 * time.Minute, } // Wait, catching any errors _, err = stateConf.WaitForState() if err != nil { return rs, err } return resource_aws_db_security_group_update_state(rs, v) }
func resource_aws_instance_create( s *terraform.ResourceState, d *terraform.ResourceDiff, meta interface{}) (*terraform.ResourceState, error) { p := meta.(*ResourceProvider) ec2conn := p.ec2conn // Merge the diff into the state so that we have all the attributes // properly. rs := s.MergeDiff(d) delete(rs.Attributes, "source_dest_check") // Figure out user data userData := "" if attr, ok := d.Attributes["user_data"]; ok { userData = attr.NewExtra.(string) } associatePublicIPAddress := false if rs.Attributes["associate_public_ip_address"] == "true" { associatePublicIPAddress = true } // Build the creation struct runOpts := &ec2.RunInstances{ ImageId: rs.Attributes["ami"], InstanceType: rs.Attributes["instance_type"], KeyName: rs.Attributes["key_name"], SubnetId: rs.Attributes["subnet_id"], AssociatePublicIpAddress: associatePublicIPAddress, UserData: []byte(userData), } if raw := flatmap.Expand(rs.Attributes, "security_groups"); raw != nil { if sgs, ok := raw.([]interface{}); ok { for _, sg := range sgs { str, ok := sg.(string) if !ok { continue } var g ec2.SecurityGroup if runOpts.SubnetId != "" { g.Id = str } else { g.Name = str } runOpts.SecurityGroups = append(runOpts.SecurityGroups, g) } } } // Create the instance log.Printf("[DEBUG] Run configuration: %#v", runOpts) runResp, err := ec2conn.RunInstances(runOpts) if err != nil { return nil, fmt.Errorf("Error launching source instance: %s", err) } instance := &runResp.Instances[0] log.Printf("[INFO] Instance ID: %s", instance.InstanceId) // Store the resulting ID so we can look this up later rs.ID = instance.InstanceId // Wait for the instance to become running so we can get some attributes // that aren't available until later. log.Printf( "[DEBUG] Waiting for instance (%s) to become running", instance.InstanceId) stateConf := &resource.StateChangeConf{ Pending: []string{"pending"}, Target: "running", Refresh: InstanceStateRefreshFunc(ec2conn, instance.InstanceId), Timeout: 10 * time.Minute, Delay: 10 * time.Second, MinTimeout: 3 * time.Second, } instanceRaw, err := stateConf.WaitForState() if err != nil { return rs, fmt.Errorf( "Error waiting for instance (%s) to become ready: %s", instance.InstanceId, err) } instance = instanceRaw.(*ec2.Instance) // Initialize the connection info rs.ConnInfo["type"] = "ssh" rs.ConnInfo["host"] = instance.PublicIpAddress // Set our attributes rs, err = resource_aws_instance_update_state(rs, instance) if err != nil { return rs, err } // Update if we need to return resource_aws_instance_update(rs, d, meta) }
func (i *Interpolater) interpolateComplexTypeAttribute( resourceID string, attributes map[string]string) (ast.Variable, error) { // We can now distinguish between lists and maps in state by the count field: // - lists (and by extension, sets) use the traditional .# notation // - maps use the newer .% notation // Consequently here we can decide how to deal with the keys appropriately // based on whether the type is a map of list. if lengthAttr, isList := attributes[resourceID+".#"]; isList { log.Printf("[DEBUG] Interpolating computed list element attribute %s (%s)", resourceID, lengthAttr) // In Terraform's internal dotted representation of list-like attributes, the // ".#" count field is marked as unknown to indicate "this whole list is // unknown". We must honor that meaning here so computed references can be // treated properly during the plan phase. if lengthAttr == config.UnknownVariableValue { return unknownVariable(), nil } keys := make([]string, 0) listElementKey := regexp.MustCompile("^" + resourceID + "\\.[0-9]+$") for id, _ := range attributes { if listElementKey.MatchString(id) { keys = append(keys, id) } } sort.Strings(keys) var members []string for _, key := range keys { members = append(members, attributes[key]) } return hil.InterfaceToVariable(members) } if lengthAttr, isMap := attributes[resourceID+".%"]; isMap { log.Printf("[DEBUG] Interpolating computed map element attribute %s (%s)", resourceID, lengthAttr) // In Terraform's internal dotted representation of map attributes, the // ".%" count field is marked as unknown to indicate "this whole list is // unknown". We must honor that meaning here so computed references can be // treated properly during the plan phase. if lengthAttr == config.UnknownVariableValue { return unknownVariable(), nil } resourceFlatMap := make(map[string]string) mapElementKey := regexp.MustCompile("^" + resourceID + "\\.([^%]+)$") for id, val := range attributes { if mapElementKey.MatchString(id) { resourceFlatMap[id] = val } } expanded := flatmap.Expand(resourceFlatMap, resourceID) return hil.InterfaceToVariable(expanded) } return ast.Variable{}, fmt.Errorf("No complex type %s found", resourceID) }
func resource_consul_keys_create( s *terraform.ResourceState, d *terraform.ResourceDiff, meta interface{}) (*terraform.ResourceState, error) { p := meta.(*ResourceProvider) // Merge the diff into the state so that we have all the attributes // properly. rs := s.MergeDiff(d) rs.ID = "consul" // Check if the datacenter should be computed dc := rs.Attributes["datacenter"] if aDiff, ok := d.Attributes["datacenter"]; ok && aDiff.NewComputed { var err error dc, err = get_dc(p.client) if err != nil { return rs, fmt.Errorf("Failed to get agent datacenter: %v", err) } rs.Attributes["datacenter"] = dc } // Get the keys keys, ok := flatmap.Expand(rs.Attributes, "key").([]interface{}) if !ok { return rs, fmt.Errorf("Failed to unroll keys") } kv := p.client.KV() qOpts := consulapi.QueryOptions{Datacenter: dc} wOpts := consulapi.WriteOptions{Datacenter: dc} for idx, raw := range keys { key, path, sub, err := parse_key(raw) if err != nil { return rs, err } if valueRaw, ok := sub["value"]; ok { value, ok := valueRaw.(string) if !ok { return rs, fmt.Errorf("Failed to get value for key '%s'", key) } log.Printf("[DEBUG] Setting key '%s' to '%v' in %s", path, value, dc) pair := consulapi.KVPair{Key: path, Value: []byte(value)} if _, err := kv.Put(&pair, &wOpts); err != nil { return rs, fmt.Errorf("Failed to set Consul key '%s': %v", path, err) } rs.Attributes[fmt.Sprintf("var.%s", key)] = value rs.Attributes[fmt.Sprintf("key.%d.value", idx)] = value } else { log.Printf("[DEBUG] Getting key '%s' in %s", path, dc) pair, _, err := kv.Get(path, &qOpts) if err != nil { return rs, fmt.Errorf("Failed to get Consul key '%s': %v", path, err) } rs.Attributes[fmt.Sprintf("var.%s", key)] = attribute_value(sub, key, pair) } } return rs, nil }
func resource_aws_db_instance_create( s *terraform.ResourceState, d *terraform.ResourceDiff, meta interface{}) (*terraform.ResourceState, error) { p := meta.(*ResourceProvider) conn := p.rdsconn // Merge the diff into the state so that we have all the attributes // properly. rs := s.MergeDiff(d) var err error var attr string opts := rds.CreateDBInstance{} if attr = rs.Attributes["allocated_storage"]; attr != "" { opts.AllocatedStorage, err = strconv.Atoi(attr) opts.SetAllocatedStorage = true } if attr = rs.Attributes["backup_retention_period"]; attr != "" { opts.BackupRetentionPeriod, err = strconv.Atoi(attr) opts.SetBackupRetentionPeriod = true } if attr = rs.Attributes["iops"]; attr != "" { opts.Iops, err = strconv.Atoi(attr) opts.SetIops = true } if attr = rs.Attributes["port"]; attr != "" { opts.Port, err = strconv.Atoi(attr) opts.SetPort = true } if attr = rs.Attributes["availability_zone"]; attr != "" { opts.AvailabilityZone = attr } if attr = rs.Attributes["instance_class"]; attr != "" { opts.DBInstanceClass = attr } if attr = rs.Attributes["maintenance_window"]; attr != "" { opts.PreferredMaintenanceWindow = attr } if attr = rs.Attributes["backup_window"]; attr != "" { opts.PreferredBackupWindow = attr } if attr = rs.Attributes["multi_az"]; attr == "true" { opts.MultiAZ = true } if attr = rs.Attributes["publicly_accessible"]; attr == "true" { opts.PubliclyAccessible = true } if attr = rs.Attributes["subnet_group_name"]; attr != "" { opts.DBSubnetGroupName = attr } if err != nil { return nil, fmt.Errorf("Error parsing configuration: %s", err) } if _, ok := rs.Attributes["vpc_security_group_ids.#"]; ok { opts.VpcSecurityGroupIds = expandStringList(flatmap.Expand( rs.Attributes, "vpc_security_group_ids").([]interface{})) } if _, ok := rs.Attributes["security_group_names.#"]; ok { opts.DBSecurityGroupNames = expandStringList(flatmap.Expand( rs.Attributes, "security_group_names").([]interface{})) } opts.DBInstanceIdentifier = rs.Attributes["identifier"] opts.DBName = rs.Attributes["name"] opts.MasterUsername = rs.Attributes["username"] opts.MasterUserPassword = rs.Attributes["password"] opts.EngineVersion = rs.Attributes["engine_version"] opts.Engine = rs.Attributes["engine"] // Don't keep the password around in the state delete(rs.Attributes, "password") log.Printf("[DEBUG] DB Instance create configuration: %#v", opts) _, err = conn.CreateDBInstance(&opts) if err != nil { return nil, fmt.Errorf("Error creating DB Instance: %s", err) } rs.ID = rs.Attributes["identifier"] log.Printf("[INFO] DB Instance ID: %s", rs.ID) log.Println( "[INFO] Waiting for DB Instance to be available") stateConf := &resource.StateChangeConf{ Pending: []string{"creating", "backing-up", "modifying"}, Target: "available", Refresh: DBInstanceStateRefreshFunc(rs.ID, conn), Timeout: 10 * time.Minute, MinTimeout: 10 * time.Second, Delay: 30 * time.Second, // Wait 30 secs before starting } // Wait, catching any errors _, err = stateConf.WaitForState() if err != nil { return rs, err } v, err := resource_aws_db_instance_retrieve(rs.ID, conn) if err != nil { return rs, err } return resource_aws_db_instance_update_state(rs, v) }
func resource_openstack_compute_create( s *terraform.ResourceState, d *terraform.ResourceDiff, meta interface{}) (*terraform.ResourceState, error) { p := meta.(*ResourceProvider) client := p.client // Merge the diff into the state so that we have all the attributes // properly. rs := s.MergeDiff(d) serversApi, err := gophercloud.ServersApi(client.AccessProvider, gophercloud.ApiCriteria{ Name: "nova", UrlChoice: gophercloud.PublicURL, }) if err != nil { return nil, err } name := rs.Attributes["name"] if len(name) == 0 { name = randomString(16) } var osNetworks []gophercloud.NetworkConfig if raw := flatmap.Expand(rs.Attributes, "networks"); raw != nil { if entries, ok := raw.([]interface{}); ok { for _, entry := range entries { value, ok := entry.(string) if !ok { continue } osNetwork := gophercloud.NetworkConfig{value} osNetworks = append(osNetworks, osNetwork) } } } var securityGroup []map[string]interface{} if raw := flatmap.Expand(rs.Attributes, "security_groups"); raw != nil { if entries, ok := raw.([]interface{}); ok { for _, entry := range entries { value, ok := entry.(string) if !ok { continue } securityGroup = append(securityGroup, map[string]interface{}{"name": value}) } } } newServer, err := serversApi.CreateServer(gophercloud.NewServer{ Name: name, ImageRef: rs.Attributes["image_ref"], FlavorRef: rs.Attributes["flavor_ref"], Networks: osNetworks, SecurityGroup: securityGroup, }) if err != nil { return nil, err } rs.ID = newServer.Id rs.Attributes["id"] = newServer.Id rs.Attributes["name"] = name return rs, nil }