Example #1
0
// 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)
}
Example #12
0
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
}
Example #14
0
// 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
}
Example #19
0
// 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
}