github.com/chalford/terraform@v0.3.7-0.20150113080010-a78c69a8c81f/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/terraform/helper/hashcode"
    10  	"github.com/hashicorp/terraform/helper/multierror"
    11  	"github.com/hashicorp/terraform/helper/resource"
    12  	"github.com/hashicorp/terraform/helper/schema"
    13  	"github.com/mitchellh/goamz/rds"
    14  )
    15  
    16  func resourceAwsDbSecurityGroup() *schema.Resource {
    17  	return &schema.Resource{
    18  		Create: resourceAwsDbSecurityGroupCreate,
    19  		Read:   resourceAwsDbSecurityGroupRead,
    20  		Delete: resourceAwsDbSecurityGroupDelete,
    21  
    22  		Schema: map[string]*schema.Schema{
    23  			"name": &schema.Schema{
    24  				Type:     schema.TypeString,
    25  				Required: true,
    26  				ForceNew: true,
    27  			},
    28  
    29  			"description": &schema.Schema{
    30  				Type:     schema.TypeString,
    31  				Required: true,
    32  				ForceNew: true,
    33  			},
    34  
    35  			"ingress": &schema.Schema{
    36  				Type:     schema.TypeSet,
    37  				Required: true,
    38  				ForceNew: true,
    39  				Elem: &schema.Resource{
    40  					Schema: map[string]*schema.Schema{
    41  						"cidr": &schema.Schema{
    42  							Type:     schema.TypeString,
    43  							Optional: true,
    44  						},
    45  
    46  						"security_group_name": &schema.Schema{
    47  							Type:     schema.TypeString,
    48  							Optional: true,
    49  							Computed: true,
    50  						},
    51  
    52  						"security_group_id": &schema.Schema{
    53  							Type:     schema.TypeString,
    54  							Optional: true,
    55  							Computed: true,
    56  						},
    57  
    58  						"security_group_owner_id": &schema.Schema{
    59  							Type:     schema.TypeString,
    60  							Optional: true,
    61  							Computed: true,
    62  						},
    63  					},
    64  				},
    65  				Set: resourceAwsDbSecurityGroupIngressHash,
    66  			},
    67  		},
    68  	}
    69  }
    70  
    71  func resourceAwsDbSecurityGroupCreate(d *schema.ResourceData, meta interface{}) error {
    72  	conn := meta.(*AWSClient).rdsconn
    73  
    74  	var err error
    75  	var errs []error
    76  
    77  	opts := rds.CreateDBSecurityGroup{
    78  		DBSecurityGroupName:        d.Get("name").(string),
    79  		DBSecurityGroupDescription: d.Get("description").(string),
    80  	}
    81  
    82  	log.Printf("[DEBUG] DB Security Group create configuration: %#v", opts)
    83  	_, err = conn.CreateDBSecurityGroup(&opts)
    84  	if err != nil {
    85  		return fmt.Errorf("Error creating DB Security Group: %s", err)
    86  	}
    87  
    88  	d.SetId(d.Get("name").(string))
    89  
    90  	log.Printf("[INFO] DB Security Group ID: %s", d.Id())
    91  
    92  	sg, err := resourceAwsDbSecurityGroupRetrieve(d, meta)
    93  	if err != nil {
    94  		return err
    95  	}
    96  
    97  	ingresses := d.Get("ingress").(*schema.Set)
    98  	for _, ing := range ingresses.List() {
    99  		err = resourceAwsDbSecurityGroupAuthorizeRule(ing, sg.Name, conn)
   100  
   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.Name)
   136  	d.Set("description", sg.Description)
   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.CidrIps {
   144  		rule := map[string]interface{}{"cidr": v}
   145  		rules.Add(rule)
   146  	}
   147  
   148  	for i, _ := range sg.EC2SecurityGroupOwnerIds {
   149  		rule := map[string]interface{}{
   150  			"security_group_name":     sg.EC2SecurityGroupNames[i],
   151  			"security_group_id":       sg.EC2SecurityGroupIds[i],
   152  			"security_group_owner_id": sg.EC2SecurityGroupOwnerIds[i],
   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.DeleteDBSecurityGroup{DBSecurityGroupName: 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.(*rds.Error)
   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.DescribeDBSecurityGroups{
   187  		DBSecurityGroupName: 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].Name != d.Id() {
   200  		if err != nil {
   201  			return nil, fmt.Errorf("Unable to find DB Security Group: %#v", resp.DBSecurityGroups)
   202  		}
   203  	}
   204  
   205  	v := resp.DBSecurityGroups[0]
   206  
   207  	return &v, nil
   208  }
   209  
   210  // Authorizes the ingress rule on the db security group
   211  func resourceAwsDbSecurityGroupAuthorizeRule(ingress interface{}, dbSecurityGroupName string, conn *rds.Rds) error {
   212  	ing := ingress.(map[string]interface{})
   213  
   214  	opts := rds.AuthorizeDBSecurityGroupIngress{
   215  		DBSecurityGroupName: dbSecurityGroupName,
   216  	}
   217  
   218  	if attr, ok := ing["cidr"]; ok && attr != "" {
   219  		opts.Cidr = attr.(string)
   220  	}
   221  
   222  	if attr, ok := ing["security_group_name"]; ok && attr != "" {
   223  		opts.EC2SecurityGroupName = attr.(string)
   224  	}
   225  
   226  	if attr, ok := ing["security_group_id"]; ok && attr != "" {
   227  		opts.EC2SecurityGroupId = attr.(string)
   228  	}
   229  
   230  	if attr, ok := ing["security_group_owner_id"]; ok && attr != "" {
   231  		opts.EC2SecurityGroupOwnerId = attr.(string)
   232  	}
   233  
   234  	log.Printf("[DEBUG] Authorize ingress rule configuration: %#v", opts)
   235  
   236  	_, err := conn.AuthorizeDBSecurityGroupIngress(&opts)
   237  
   238  	if err != nil {
   239  		return fmt.Errorf("Error authorizing security group ingress: %s", err)
   240  	}
   241  
   242  	return nil
   243  }
   244  
   245  func resourceAwsDbSecurityGroupIngressHash(v interface{}) int {
   246  	var buf bytes.Buffer
   247  	m := v.(map[string]interface{})
   248  
   249  	if v, ok := m["cidr"]; ok {
   250  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   251  	}
   252  
   253  	if v, ok := m["security_group_name"]; ok {
   254  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   255  	}
   256  
   257  	if v, ok := m["security_group_id"]; ok {
   258  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   259  	}
   260  
   261  	if v, ok := m["security_group_owner_id"]; ok {
   262  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   263  	}
   264  
   265  	return hashcode.String(buf.String())
   266  }
   267  
   268  func resourceAwsDbSecurityGroupStateRefreshFunc(
   269  	d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc {
   270  	return func() (interface{}, string, error) {
   271  		v, err := resourceAwsDbSecurityGroupRetrieve(d, meta)
   272  
   273  		if err != nil {
   274  			log.Printf("Error on retrieving DB Security Group when waiting: %s", err)
   275  			return nil, "", err
   276  		}
   277  
   278  		statuses := append(v.EC2SecurityGroupStatuses, v.CidrStatuses...)
   279  
   280  		for _, stat := range statuses {
   281  			// Not done
   282  			if stat != "authorized" {
   283  				return nil, "authorizing", nil
   284  			}
   285  		}
   286  
   287  		return v, "authorized", nil
   288  	}
   289  }