// generate ResourceAttrDiffs for nested data structures in tests func testFlatAttrDiffs(k string, i interface{}) map[string]*ResourceAttrDiff { diffs := make(map[string]*ResourceAttrDiff) // check for strings and empty containers first switch t := i.(type) { case string: diffs[k] = &ResourceAttrDiff{New: t} return diffs case map[string]interface{}: if len(t) == 0 { diffs[k] = &ResourceAttrDiff{New: ""} return diffs } case []interface{}: if len(t) == 0 { diffs[k] = &ResourceAttrDiff{New: ""} return diffs } } flat := flatmap.Flatten(map[string]interface{}{k: i}) for k, v := range flat { attrDiff := &ResourceAttrDiff{ Old: "", New: v, } diffs[k] = attrDiff } return diffs }
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 resource_aws_db_instance_update_state( s *terraform.ResourceState, v *rds.DBInstance) (*terraform.ResourceState, error) { s.Attributes["address"] = v.Address s.Attributes["allocated_storage"] = strconv.Itoa(v.AllocatedStorage) s.Attributes["availability_zone"] = v.AvailabilityZone s.Attributes["backup_retention_period"] = strconv.Itoa(v.BackupRetentionPeriod) s.Attributes["backup_window"] = v.PreferredBackupWindow s.Attributes["endpoint"] = fmt.Sprintf("%s:%s", s.Attributes["address"], s.Attributes["port"]) s.Attributes["engine"] = v.Engine s.Attributes["engine_version"] = v.EngineVersion s.Attributes["instance_class"] = v.DBInstanceClass s.Attributes["maintenance_window"] = v.PreferredMaintenanceWindow s.Attributes["multi_az"] = strconv.FormatBool(v.MultiAZ) s.Attributes["name"] = v.DBName s.Attributes["port"] = strconv.Itoa(v.Port) s.Attributes["status"] = v.DBInstanceStatus s.Attributes["username"] = v.MasterUsername // Flatten our group values toFlatten := make(map[string]interface{}) if len(v.DBSecurityGroupNames) > 0 && v.DBSecurityGroupNames[0] != "" { toFlatten["security_group_names"] = v.DBSecurityGroupNames } if len(v.VpcSecurityGroupIds) > 0 && v.VpcSecurityGroupIds[0] != "" { toFlatten["vpc_security_group_ids"] = v.VpcSecurityGroupIds } for k, v := range flatmap.Flatten(toFlatten) { s.Attributes[k] = v } return s, nil }
func resource_aws_autoscaling_group_update_state( s *terraform.ResourceState, g *autoscaling.AutoScalingGroup) (*terraform.ResourceState, error) { s.Attributes["min_size"] = strconv.Itoa(g.MinSize) s.Attributes["max_size"] = strconv.Itoa(g.MaxSize) s.Attributes["default_cooldown"] = strconv.Itoa(g.DefaultCooldown) s.Attributes["name"] = g.Name s.Attributes["desired_capacity"] = strconv.Itoa(g.DesiredCapacity) s.Attributes["health_check_grace_period"] = strconv.Itoa(g.HealthCheckGracePeriod) s.Attributes["health_check_type"] = g.HealthCheckType s.Attributes["launch_configuration"] = g.LaunchConfigurationName s.Attributes["vpc_zone_identifier"] = g.VPCZoneIdentifier // Flatten our group values toFlatten := make(map[string]interface{}) // Special case the return of amazons load balancers names in the XML having // a blank entry if len(g.LoadBalancerNames) > 0 && g.LoadBalancerNames[0].LoadBalancerName != "" { toFlatten["load_balancers"] = flattenLoadBalancers(g.LoadBalancerNames) } toFlatten["availability_zones"] = flattenAvailabilityZones(g.AvailabilityZones) for k, v := range flatmap.Flatten(toFlatten) { s.Attributes[k] = v } return s, nil }
func resource_aws_elb_update_state( s *terraform.ResourceState, balancer *elb.LoadBalancer) (*terraform.ResourceState, error) { s.Attributes["name"] = balancer.LoadBalancerName s.Attributes["dns_name"] = balancer.DNSName // Flatten our group values toFlatten := make(map[string]interface{}) if len(balancer.Instances) > 0 && balancer.Instances[0].InstanceId != "" { toFlatten["instances"] = flattenInstances(balancer.Instances) } // There's only one health check, so save that to state as we // currently can if balancer.HealthCheck.Target != "" { toFlatten["health_check"] = flattenHealthCheck(balancer.HealthCheck) } for k, v := range flatmap.Flatten(toFlatten) { s.Attributes[k] = v } return s, nil }
func resource_heroku_app_update_state( s *terraform.ResourceState, app *application) (*terraform.ResourceState, error) { s.Attributes["name"] = app.App.Name s.Attributes["stack"] = app.App.Stack.Name s.Attributes["region"] = app.App.Region.Name s.Attributes["git_url"] = app.App.GitURL s.Attributes["web_url"] = app.App.WebURL // We know that the hostname on heroku will be the name+herokuapp.com // You need this to do things like create DNS CNAME records s.Attributes["heroku_hostname"] = fmt.Sprintf("%s.herokuapp.com", app.App.Name) toFlatten := make(map[string]interface{}) if len(app.Vars) > 0 { toFlatten["config_vars"] = []map[string]string{app.Vars} } for k, v := range flatmap.Flatten(toFlatten) { s.Attributes[k] = v } return s, nil }
func resource_aws_security_group_update_state( s *terraform.ResourceState, sg *ec2.SecurityGroupInfo) (*terraform.ResourceState, error) { s.Attributes["description"] = sg.Description s.Attributes["name"] = sg.Name s.Attributes["vpc_id"] = sg.VpcId s.Attributes["owner_id"] = sg.OwnerId // Flatten our ingress values toFlatten := make(map[string]interface{}) toFlatten["ingress"] = flattenIPPerms(sg.IPPerms) for k, v := range flatmap.Flatten(toFlatten) { s.Attributes[k] = v } s.Dependencies = nil if s.Attributes["vpc_id"] != "" { s.Dependencies = append(s.Dependencies, terraform.ResourceDependency{ID: s.Attributes["vpc_id"]}, ) } return s, nil }
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_aws_security_group_update_state( s *terraform.ResourceState, sg *ec2.SecurityGroupInfo) (*terraform.ResourceState, error) { s.Attributes["description"] = sg.Description s.Attributes["name"] = sg.Name s.Attributes["vpc_id"] = sg.VpcId s.Attributes["owner_id"] = sg.OwnerId // Flatten our ingress values toFlatten := make(map[string]interface{}) ingressRules := make([]map[string]interface{}, 0, len(sg.IPPerms)) for _, perm := range sg.IPPerms { n := make(map[string]interface{}) n["from_port"] = perm.FromPort n["protocol"] = perm.Protocol n["to_port"] = perm.ToPort if len(perm.SourceIPs) > 0 { n["cidr_blocks"] = perm.SourceIPs } if len(perm.SourceGroups) > 0 { // We depend on other security groups for _, v := range perm.SourceGroups { s.Dependencies = append(s.Dependencies, terraform.ResourceDependency{ID: v.Id}, ) } n["security_groups"] = flattenSecurityGroups(perm.SourceGroups) } // Reverse the order, as Amazon sorts it the reverse of how we created // it. ingressRules = append([]map[string]interface{}{n}, ingressRules...) } toFlatten["ingress"] = ingressRules for k, v := range flatmap.Flatten(toFlatten) { s.Attributes[k] = v } if s.Attributes["vpc_id"] != "" { s.Dependencies = append(s.Dependencies, terraform.ResourceDependency{ID: s.Attributes["vpc_id"]}, ) } return s, nil }
func resource_aws_r53_record_update_state( s *terraform.ResourceState, rec *route53.ResourceRecordSet) { flatRec := flatmap.Flatten(map[string]interface{}{ "records": rec.Records, }) for k, v := range flatRec { s.Attributes[k] = v } s.Attributes["ttl"] = strconv.FormatInt(int64(rec.TTL), 10) }
// Convert *cloudfront.ActiveTrustedSigners to a flatmap.Map type, which ensures // it can probably be inserted into the schema.TypeMap type used by the // active_trusted_signers attribute. func flattenActiveTrustedSigners(ats *cloudfront.ActiveTrustedSigners) flatmap.Map { m := make(map[string]interface{}) s := []interface{}{} m["enabled"] = *ats.Enabled for _, v := range ats.Items { signer := make(map[string]interface{}) signer["aws_account_number"] = *v.AwsAccountNumber signer["key_pair_ids"] = aws.StringValueSlice(v.KeyPairIds.Items) s = append(s, signer) } m["items"] = s return flatmap.Flatten(m) }
func (v *Validator) Validate( c *terraform.ResourceConfig) (ws []string, es []error) { // Flatten the configuration so it is easier to reason about flat := flatmap.Flatten(c.Raw) keySet := make(map[string]validatorKey) for i, vs := range [][]string{v.Required, v.Optional} { req := i == 0 for _, k := range vs { vk, err := newValidatorKey(k, req) if err != nil { es = append(es, err) continue } keySet[k] = vk } } purged := make([]string, 0) for _, kv := range keySet { p, w, e := kv.Validate(flat) if len(w) > 0 { ws = append(ws, w...) } if len(e) > 0 { es = append(es, e...) } purged = append(purged, p...) } // Delete all the keys we processed in order to find // the unknown keys. for _, p := range purged { delete(flat, p) } // The rest are unknown for k, _ := range flat { es = append(es, fmt.Errorf("Unknown configuration: %s", k)) } return }
func resource_aws_elb_update_state( s *terraform.ResourceState, balancer *elb.LoadBalancer) (*terraform.ResourceState, error) { s.Attributes["name"] = balancer.LoadBalancerName s.Attributes["dns_name"] = balancer.DNSName // Flatten our group values toFlatten := make(map[string]interface{}) if len(balancer.Instances) > 0 && balancer.Instances[0].InstanceId != "" { toFlatten["instances"] = flattenInstances(balancer.Instances) for k, v := range flatmap.Flatten(toFlatten) { s.Attributes[k] = v } } return s, nil }
// DefaultsMap returns a map of default values for this variable. func (v *Variable) DefaultsMap() map[string]string { if v.Default == nil { return nil } n := fmt.Sprintf("var.%s", v.Name) switch v.Type() { case VariableTypeString: return map[string]string{n: v.Default.(string)} case VariableTypeMap: result := flatmap.Flatten(map[string]interface{}{ n: v.Default.(map[string]string), }) result[n] = v.Name return result default: return nil } }
func resource_aws_launch_configuration_update_state( s *terraform.ResourceState, lc *autoscaling.LaunchConfiguration) (*terraform.ResourceState, error) { s.Attributes["image_id"] = lc.ImageId s.Attributes["instance_type"] = lc.InstanceType s.Attributes["key_name"] = lc.KeyName s.Attributes["name"] = lc.Name // Flatten our group values toFlatten := make(map[string]interface{}) if len(lc.SecurityGroups) > 0 && lc.SecurityGroups[0].SecurityGroup != "" { toFlatten["security_groups"] = flattenAutoscalingSecurityGroups(lc.SecurityGroups) } for k, v := range flatmap.Flatten(toFlatten) { s.Attributes[k] = v } return s, nil }
func resource_aws_db_security_group_update_state( s *terraform.ResourceState, v *rds.DBSecurityGroup) (*terraform.ResourceState, error) { s.Attributes["name"] = v.Name s.Attributes["description"] = v.Description // Flatten our group values toFlatten := make(map[string]interface{}) if len(v.EC2SecurityGroupOwnerIds) > 0 && v.EC2SecurityGroupOwnerIds[0] != "" { toFlatten["ingress_security_groups"] = v.EC2SecurityGroupOwnerIds } if len(v.CidrIps) > 0 && v.CidrIps[0] != "" { toFlatten["ingress_cidr"] = v.CidrIps } for k, v := range flatmap.Flatten(toFlatten) { s.Attributes[k] = v } return s, nil }
func resource_heroku_addon_update_state( s *terraform.ResourceState, addon *heroku.Addon) (*terraform.ResourceState, error) { s.Attributes["name"] = addon.Name s.Attributes["plan"] = addon.Plan.Name s.Attributes["provider_id"] = addon.ProviderId toFlatten := make(map[string]interface{}) if len(addon.ConfigVars) > 0 { toFlatten["config_vars"] = addon.ConfigVars } for k, v := range flatmap.Flatten(toFlatten) { s.Attributes[k] = v } s.Dependencies = []terraform.ResourceDependency{ terraform.ResourceDependency{ID: s.Attributes["app"]}, } return s, nil }
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 }
// Diff returns the ResourceDiff for a resource given its state and // configuration. func (b *ResourceBuilder) Diff( s *terraform.InstanceState, c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { attrs := make(map[string]*terraform.ResourceAttrDiff) // We require a new resource if the ID is empty. Or, later, we set // this to true if any configuration changed that triggers a new resource. requiresNew := s.ID == "" // Flatten the raw and processed configuration flatRaw := flatmap.Flatten(c.Raw) flatConfig := flatmap.Flatten(c.Config) for ak, at := range b.Attrs { // Keep track of all the keys we saw in the raw structure // so that we can prune our attributes later. seenKeys := make([]string, 0) // Go through and find the added/changed keys in flatRaw for k, v := range flatRaw { // Find only the attributes that match our prefix if !strings.HasPrefix(k, ak) { continue } // Track that we saw this key seenKeys = append(seenKeys, k) // We keep track of this in case we have a pre-processor // so that we can store the original value still. originalV := v // If this key is in the cleaned config, then use that value // because it'll have its variables properly interpolated if cleanV, ok := flatConfig[k]; ok && cleanV != config.UnknownVariableValue { v = cleanV originalV = v // If we have a pre-processor for this, run it. if pp, ok := b.PreProcess[k]; ok { v = pp(v) } } oldV, ok := s.Attributes[k] // If there is an old value and they're the same, no change if ok && oldV == v { continue } // Record the change attrs[k] = &terraform.ResourceAttrDiff{ Old: oldV, New: v, NewExtra: originalV, Type: terraform.DiffAttrInput, } // If this requires a new resource, record that and flag our // boolean. if at == AttrTypeCreate { attrs[k].RequiresNew = true requiresNew = true } } // Find all the keys that are in our attributes right now that // we also care about. matchingKeys := make(map[string]struct{}) for k, _ := range s.Attributes { // Find only the attributes that match our prefix if !strings.HasPrefix(k, ak) { continue } // If this key is computed, then we don't ever delete it comp := false for _, ck := range b.ComputedAttrs { if ck == k { comp = true break } // If the key is prefixed with the computed key, don't // mark it for delete, ever. if strings.HasPrefix(k, ck+".") { comp = true break } } if comp { continue } matchingKeys[k] = struct{}{} } // Delete the keys we saw in the configuration from the keys // that are currently set. for _, k := range seenKeys { delete(matchingKeys, k) } for k, _ := range matchingKeys { attrs[k] = &terraform.ResourceAttrDiff{ Old: s.Attributes[k], NewRemoved: true, Type: terraform.DiffAttrInput, } } } // If we require a new resource, then process all the attributes // that will be changing due to the creation of the resource. if requiresNew { for _, k := range b.ComputedAttrs { if _, ok := attrs[k]; ok { continue } old := s.Attributes[k] attrs[k] = &terraform.ResourceAttrDiff{ Old: old, NewComputed: true, Type: terraform.DiffAttrOutput, } } } // If we're changing anything, then mark the updated // attributes. if len(attrs) > 0 { for _, k := range b.ComputedAttrsUpdate { if _, ok := attrs[k]; ok { continue } old := s.Attributes[k] attrs[k] = &terraform.ResourceAttrDiff{ Old: old, NewComputed: true, Type: terraform.DiffAttrOutput, } } } // Build our resulting diff if we had attributes change var result *terraform.InstanceDiff if len(attrs) > 0 { result = &terraform.InstanceDiff{ Attributes: attrs, } } return result, nil }