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)
}
Beispiel #6
0
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)
}
Beispiel #11
0
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(&registerInstancesOpts)

			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(&registerInstancesOpts)

			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)
}
Beispiel #24
0
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
}