github.com/ndarilek/terraform@v0.3.8-0.20150320140257-d3135c1b2bac/builtin/providers/aws/resource_aws_db_security_group.go (about)

     1  package aws
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"log"
     7  	"time"
     8  
     9  	"github.com/hashicorp/aws-sdk-go/aws"
    10  	"github.com/hashicorp/aws-sdk-go/gen/rds"
    11  	"github.com/hashicorp/terraform/helper/hashcode"
    12  	"github.com/hashicorp/terraform/helper/multierror"
    13  	"github.com/hashicorp/terraform/helper/resource"
    14  	"github.com/hashicorp/terraform/helper/schema"
    15  )
    16  
    17  func resourceAwsDbSecurityGroup() *schema.Resource {
    18  	return &schema.Resource{
    19  		Create: resourceAwsDbSecurityGroupCreate,
    20  		Read:   resourceAwsDbSecurityGroupRead,
    21  		Delete: resourceAwsDbSecurityGroupDelete,
    22  
    23  		Schema: map[string]*schema.Schema{
    24  			"name": &schema.Schema{
    25  				Type:     schema.TypeString,
    26  				Required: true,
    27  				ForceNew: true,
    28  			},
    29  
    30  			"description": &schema.Schema{
    31  				Type:     schema.TypeString,
    32  				Required: true,
    33  				ForceNew: true,
    34  			},
    35  
    36  			"ingress": &schema.Schema{
    37  				Type:     schema.TypeSet,
    38  				Required: true,
    39  				ForceNew: true,
    40  				Elem: &schema.Resource{
    41  					Schema: map[string]*schema.Schema{
    42  						"cidr": &schema.Schema{
    43  							Type:     schema.TypeString,
    44  							Optional: true,
    45  						},
    46  
    47  						"security_group_name": &schema.Schema{
    48  							Type:     schema.TypeString,
    49  							Optional: true,
    50  							Computed: true,
    51  						},
    52  
    53  						"security_group_id": &schema.Schema{
    54  							Type:     schema.TypeString,
    55  							Optional: true,
    56  							Computed: true,
    57  						},
    58  
    59  						"security_group_owner_id": &schema.Schema{
    60  							Type:     schema.TypeString,
    61  							Optional: true,
    62  							Computed: true,
    63  						},
    64  					},
    65  				},
    66  				Set: resourceAwsDbSecurityGroupIngressHash,
    67  			},
    68  		},
    69  	}
    70  }
    71  
    72  func resourceAwsDbSecurityGroupCreate(d *schema.ResourceData, meta interface{}) error {
    73  	conn := meta.(*AWSClient).rdsconn
    74  
    75  	var err error
    76  	var errs []error
    77  
    78  	opts := rds.CreateDBSecurityGroupMessage{
    79  		DBSecurityGroupName:        aws.String(d.Get("name").(string)),
    80  		DBSecurityGroupDescription: aws.String(d.Get("description").(string)),
    81  	}
    82  
    83  	log.Printf("[DEBUG] DB Security Group create configuration: %#v", opts)
    84  	_, err = conn.CreateDBSecurityGroup(&opts)
    85  	if err != nil {
    86  		return fmt.Errorf("Error creating DB Security Group: %s", err)
    87  	}
    88  
    89  	d.SetId(d.Get("name").(string))
    90  
    91  	log.Printf("[INFO] DB Security Group ID: %s", d.Id())
    92  
    93  	sg, err := resourceAwsDbSecurityGroupRetrieve(d, meta)
    94  	if err != nil {
    95  		return err
    96  	}
    97  
    98  	ingresses := d.Get("ingress").(*schema.Set)
    99  	for _, ing := range ingresses.List() {
   100  		err := resourceAwsDbSecurityGroupAuthorizeRule(ing, *sg.DBSecurityGroupName, conn)
   101  		if err != nil {
   102  			errs = append(errs, err)
   103  		}
   104  	}
   105  
   106  	if len(errs) > 0 {
   107  		return &multierror.Error{Errors: errs}
   108  	}
   109  
   110  	log.Println(
   111  		"[INFO] Waiting for Ingress Authorizations to be authorized")
   112  
   113  	stateConf := &resource.StateChangeConf{
   114  		Pending: []string{"authorizing"},
   115  		Target:  "authorized",
   116  		Refresh: resourceAwsDbSecurityGroupStateRefreshFunc(d, meta),
   117  		Timeout: 10 * time.Minute,
   118  	}
   119  
   120  	// Wait, catching any errors
   121  	_, err = stateConf.WaitForState()
   122  	if err != nil {
   123  		return err
   124  	}
   125  
   126  	return resourceAwsDbSecurityGroupRead(d, meta)
   127  }
   128  
   129  func resourceAwsDbSecurityGroupRead(d *schema.ResourceData, meta interface{}) error {
   130  	sg, err := resourceAwsDbSecurityGroupRetrieve(d, meta)
   131  	if err != nil {
   132  		return err
   133  	}
   134  
   135  	d.Set("name", *sg.DBSecurityGroupName)
   136  	d.Set("description", *sg.DBSecurityGroupDescription)
   137  
   138  	// Create an empty schema.Set to hold all ingress rules
   139  	rules := &schema.Set{
   140  		F: resourceAwsDbSecurityGroupIngressHash,
   141  	}
   142  
   143  	for _, v := range sg.IPRanges {
   144  		rule := map[string]interface{}{"cidr": *v.CIDRIP}
   145  		rules.Add(rule)
   146  	}
   147  
   148  	for _, g := range sg.EC2SecurityGroups {
   149  		rule := map[string]interface{}{
   150  			"security_group_name":     *g.EC2SecurityGroupName,
   151  			"security_group_id":       *g.EC2SecurityGroupID,
   152  			"security_group_owner_id": *g.EC2SecurityGroupOwnerID,
   153  		}
   154  		rules.Add(rule)
   155  	}
   156  
   157  	d.Set("ingress", rules)
   158  
   159  	return nil
   160  }
   161  
   162  func resourceAwsDbSecurityGroupDelete(d *schema.ResourceData, meta interface{}) error {
   163  	conn := meta.(*AWSClient).rdsconn
   164  
   165  	log.Printf("[DEBUG] DB Security Group destroy: %v", d.Id())
   166  
   167  	opts := rds.DeleteDBSecurityGroupMessage{DBSecurityGroupName: aws.String(d.Id())}
   168  
   169  	log.Printf("[DEBUG] DB Security Group destroy configuration: %v", opts)
   170  	err := conn.DeleteDBSecurityGroup(&opts)
   171  
   172  	if err != nil {
   173  		newerr, ok := err.(aws.APIError)
   174  		if ok && newerr.Code == "InvalidDBSecurityGroup.NotFound" {
   175  			return nil
   176  		}
   177  		return err
   178  	}
   179  
   180  	return nil
   181  }
   182  
   183  func resourceAwsDbSecurityGroupRetrieve(d *schema.ResourceData, meta interface{}) (*rds.DBSecurityGroup, error) {
   184  	conn := meta.(*AWSClient).rdsconn
   185  
   186  	opts := rds.DescribeDBSecurityGroupsMessage{
   187  		DBSecurityGroupName: aws.String(d.Id()),
   188  	}
   189  
   190  	log.Printf("[DEBUG] DB Security Group describe configuration: %#v", opts)
   191  
   192  	resp, err := conn.DescribeDBSecurityGroups(&opts)
   193  
   194  	if err != nil {
   195  		return nil, fmt.Errorf("Error retrieving DB Security Groups: %s", err)
   196  	}
   197  
   198  	if len(resp.DBSecurityGroups) != 1 ||
   199  		*resp.DBSecurityGroups[0].DBSecurityGroupName != d.Id() {
   200  		return nil, fmt.Errorf("Unable to find DB Security Group: %#v", resp.DBSecurityGroups)
   201  	}
   202  
   203  	v := resp.DBSecurityGroups[0]
   204  
   205  	return &v, nil
   206  }
   207  
   208  // Authorizes the ingress rule on the db security group
   209  func resourceAwsDbSecurityGroupAuthorizeRule(ingress interface{}, dbSecurityGroupName string, conn *rds.RDS) error {
   210  	ing := ingress.(map[string]interface{})
   211  
   212  	opts := rds.AuthorizeDBSecurityGroupIngressMessage{
   213  		DBSecurityGroupName: aws.String(dbSecurityGroupName),
   214  	}
   215  
   216  	if attr, ok := ing["cidr"]; ok && attr != "" {
   217  		opts.CIDRIP = aws.String(attr.(string))
   218  	}
   219  
   220  	if attr, ok := ing["security_group_name"]; ok && attr != "" {
   221  		opts.EC2SecurityGroupName = aws.String(attr.(string))
   222  	}
   223  
   224  	if attr, ok := ing["security_group_id"]; ok && attr != "" {
   225  		opts.EC2SecurityGroupID = aws.String(attr.(string))
   226  	}
   227  
   228  	if attr, ok := ing["security_group_owner_id"]; ok && attr != "" {
   229  		opts.EC2SecurityGroupOwnerID = aws.String(attr.(string))
   230  	}
   231  
   232  	log.Printf("[DEBUG] Authorize ingress rule configuration: %#v", opts)
   233  
   234  	_, err := conn.AuthorizeDBSecurityGroupIngress(&opts)
   235  
   236  	if err != nil {
   237  		return fmt.Errorf("Error authorizing security group ingress: %s", err)
   238  	}
   239  
   240  	return nil
   241  }
   242  
   243  func resourceAwsDbSecurityGroupIngressHash(v interface{}) int {
   244  	var buf bytes.Buffer
   245  	m := v.(map[string]interface{})
   246  
   247  	if v, ok := m["cidr"]; ok {
   248  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   249  	}
   250  
   251  	if v, ok := m["security_group_name"]; ok {
   252  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   253  	}
   254  
   255  	if v, ok := m["security_group_id"]; ok {
   256  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   257  	}
   258  
   259  	if v, ok := m["security_group_owner_id"]; ok {
   260  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   261  	}
   262  
   263  	return hashcode.String(buf.String())
   264  }
   265  
   266  func resourceAwsDbSecurityGroupStateRefreshFunc(
   267  	d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc {
   268  	return func() (interface{}, string, error) {
   269  		v, err := resourceAwsDbSecurityGroupRetrieve(d, meta)
   270  
   271  		if err != nil {
   272  			log.Printf("Error on retrieving DB Security Group when waiting: %s", err)
   273  			return nil, "", err
   274  		}
   275  
   276  		statuses := make([]string, 0, len(v.EC2SecurityGroups)+len(v.IPRanges))
   277  		for _, ec2g := range v.EC2SecurityGroups {
   278  			statuses = append(statuses, *ec2g.Status)
   279  		}
   280  		for _, ips := range v.IPRanges {
   281  			statuses = append(statuses, *ips.Status)
   282  		}
   283  
   284  		for _, stat := range statuses {
   285  			// Not done
   286  			if stat != "authorized" {
   287  				return nil, "authorizing", nil
   288  			}
   289  		}
   290  
   291  		return v, "authorized", nil
   292  	}
   293  }