github.com/rmenn/terraform@v0.3.8-0.20150225065417-fc84b3a78802/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  		if err != nil {
   101  			errs = append(errs, err)
   102  		}
   103  	}
   104  
   105  	if len(errs) > 0 {
   106  		return &multierror.Error{Errors: errs}
   107  	}
   108  
   109  	log.Println(
   110  		"[INFO] Waiting for Ingress Authorizations to be authorized")
   111  
   112  	stateConf := &resource.StateChangeConf{
   113  		Pending: []string{"authorizing"},
   114  		Target:  "authorized",
   115  		Refresh: resourceAwsDbSecurityGroupStateRefreshFunc(d, meta),
   116  		Timeout: 10 * time.Minute,
   117  	}
   118  
   119  	// Wait, catching any errors
   120  	_, err = stateConf.WaitForState()
   121  	if err != nil {
   122  		return err
   123  	}
   124  
   125  	return resourceAwsDbSecurityGroupRead(d, meta)
   126  }
   127  
   128  func resourceAwsDbSecurityGroupRead(d *schema.ResourceData, meta interface{}) error {
   129  	sg, err := resourceAwsDbSecurityGroupRetrieve(d, meta)
   130  	if err != nil {
   131  		return err
   132  	}
   133  
   134  	d.Set("name", sg.Name)
   135  	d.Set("description", sg.Description)
   136  
   137  	// Create an empty schema.Set to hold all ingress rules
   138  	rules := &schema.Set{
   139  		F: resourceAwsDbSecurityGroupIngressHash,
   140  	}
   141  
   142  	for _, v := range sg.CidrIps {
   143  		rule := map[string]interface{}{"cidr": v}
   144  		rules.Add(rule)
   145  	}
   146  
   147  	for i, _ := range sg.EC2SecurityGroupOwnerIds {
   148  		rule := map[string]interface{}{
   149  			"security_group_name":     sg.EC2SecurityGroupNames[i],
   150  			"security_group_id":       sg.EC2SecurityGroupIds[i],
   151  			"security_group_owner_id": sg.EC2SecurityGroupOwnerIds[i],
   152  		}
   153  		rules.Add(rule)
   154  	}
   155  
   156  	d.Set("ingress", rules)
   157  
   158  	return nil
   159  }
   160  
   161  func resourceAwsDbSecurityGroupDelete(d *schema.ResourceData, meta interface{}) error {
   162  	conn := meta.(*AWSClient).rdsconn
   163  
   164  	log.Printf("[DEBUG] DB Security Group destroy: %v", d.Id())
   165  
   166  	opts := rds.DeleteDBSecurityGroup{DBSecurityGroupName: d.Id()}
   167  
   168  	log.Printf("[DEBUG] DB Security Group destroy configuration: %v", opts)
   169  	_, err := conn.DeleteDBSecurityGroup(&opts)
   170  
   171  	if err != nil {
   172  		newerr, ok := err.(*rds.Error)
   173  		if ok && newerr.Code == "InvalidDBSecurityGroup.NotFound" {
   174  			return nil
   175  		}
   176  		return err
   177  	}
   178  
   179  	return nil
   180  }
   181  
   182  func resourceAwsDbSecurityGroupRetrieve(d *schema.ResourceData, meta interface{}) (*rds.DBSecurityGroup, error) {
   183  	conn := meta.(*AWSClient).rdsconn
   184  
   185  	opts := rds.DescribeDBSecurityGroups{
   186  		DBSecurityGroupName: d.Id(),
   187  	}
   188  
   189  	log.Printf("[DEBUG] DB Security Group describe configuration: %#v", opts)
   190  
   191  	resp, err := conn.DescribeDBSecurityGroups(&opts)
   192  
   193  	if err != nil {
   194  		return nil, fmt.Errorf("Error retrieving DB Security Groups: %s", err)
   195  	}
   196  
   197  	if len(resp.DBSecurityGroups) != 1 ||
   198  		resp.DBSecurityGroups[0].Name != d.Id() {
   199  		if err != nil {
   200  			return nil, fmt.Errorf("Unable to find DB Security Group: %#v", resp.DBSecurityGroups)
   201  		}
   202  	}
   203  
   204  	v := resp.DBSecurityGroups[0]
   205  
   206  	return &v, nil
   207  }
   208  
   209  // Authorizes the ingress rule on the db security group
   210  func resourceAwsDbSecurityGroupAuthorizeRule(ingress interface{}, dbSecurityGroupName string, conn *rds.Rds) error {
   211  	ing := ingress.(map[string]interface{})
   212  
   213  	opts := rds.AuthorizeDBSecurityGroupIngress{
   214  		DBSecurityGroupName: dbSecurityGroupName,
   215  	}
   216  
   217  	if attr, ok := ing["cidr"]; ok && attr != "" {
   218  		opts.Cidr = attr.(string)
   219  	}
   220  
   221  	if attr, ok := ing["security_group_name"]; ok && attr != "" {
   222  		opts.EC2SecurityGroupName = attr.(string)
   223  	}
   224  
   225  	if attr, ok := ing["security_group_id"]; ok && attr != "" {
   226  		opts.EC2SecurityGroupId = attr.(string)
   227  	}
   228  
   229  	if attr, ok := ing["security_group_owner_id"]; ok && attr != "" {
   230  		opts.EC2SecurityGroupOwnerId = attr.(string)
   231  	}
   232  
   233  	log.Printf("[DEBUG] Authorize ingress rule configuration: %#v", opts)
   234  
   235  	_, err := conn.AuthorizeDBSecurityGroupIngress(&opts)
   236  
   237  	if err != nil {
   238  		return fmt.Errorf("Error authorizing security group ingress: %s", err)
   239  	}
   240  
   241  	return nil
   242  }
   243  
   244  func resourceAwsDbSecurityGroupIngressHash(v interface{}) int {
   245  	var buf bytes.Buffer
   246  	m := v.(map[string]interface{})
   247  
   248  	if v, ok := m["cidr"]; ok {
   249  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   250  	}
   251  
   252  	if v, ok := m["security_group_name"]; ok {
   253  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   254  	}
   255  
   256  	if v, ok := m["security_group_id"]; ok {
   257  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   258  	}
   259  
   260  	if v, ok := m["security_group_owner_id"]; ok {
   261  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   262  	}
   263  
   264  	return hashcode.String(buf.String())
   265  }
   266  
   267  func resourceAwsDbSecurityGroupStateRefreshFunc(
   268  	d *schema.ResourceData, meta interface{}) resource.StateRefreshFunc {
   269  	return func() (interface{}, string, error) {
   270  		v, err := resourceAwsDbSecurityGroupRetrieve(d, meta)
   271  
   272  		if err != nil {
   273  			log.Printf("Error on retrieving DB Security Group when waiting: %s", err)
   274  			return nil, "", err
   275  		}
   276  
   277  		statuses := append(v.EC2SecurityGroupStatuses, v.CidrStatuses...)
   278  
   279  		for _, stat := range statuses {
   280  			// Not done
   281  			if stat != "authorized" {
   282  				return nil, "authorizing", nil
   283  			}
   284  		}
   285  
   286  		return v, "authorized", nil
   287  	}
   288  }