github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/aws/resource_aws_config_config_rule.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/resource"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  
    13  	"github.com/aws/aws-sdk-go/aws"
    14  	"github.com/aws/aws-sdk-go/aws/awserr"
    15  	"github.com/aws/aws-sdk-go/service/configservice"
    16  )
    17  
    18  func resourceAwsConfigConfigRule() *schema.Resource {
    19  	return &schema.Resource{
    20  		Create: resourceAwsConfigConfigRulePut,
    21  		Read:   resourceAwsConfigConfigRuleRead,
    22  		Update: resourceAwsConfigConfigRulePut,
    23  		Delete: resourceAwsConfigConfigRuleDelete,
    24  
    25  		Importer: &schema.ResourceImporter{
    26  			State: schema.ImportStatePassthrough,
    27  		},
    28  
    29  		Schema: map[string]*schema.Schema{
    30  			"name": {
    31  				Type:         schema.TypeString,
    32  				Required:     true,
    33  				ValidateFunc: validateMaxLength(64),
    34  			},
    35  			"rule_id": {
    36  				Type:     schema.TypeString,
    37  				Computed: true,
    38  			},
    39  			"arn": {
    40  				Type:     schema.TypeString,
    41  				Computed: true,
    42  			},
    43  			"description": {
    44  				Type:         schema.TypeString,
    45  				Optional:     true,
    46  				ValidateFunc: validateMaxLength(256),
    47  			},
    48  			"input_parameters": {
    49  				Type:         schema.TypeString,
    50  				Optional:     true,
    51  				ValidateFunc: validateJsonString,
    52  			},
    53  			"maximum_execution_frequency": {
    54  				Type:         schema.TypeString,
    55  				Optional:     true,
    56  				ValidateFunc: validateConfigExecutionFrequency,
    57  			},
    58  			"scope": {
    59  				Type:     schema.TypeList,
    60  				MaxItems: 1,
    61  				Optional: true,
    62  				Elem: &schema.Resource{
    63  					Schema: map[string]*schema.Schema{
    64  						"compliance_resource_id": {
    65  							Type:         schema.TypeString,
    66  							Optional:     true,
    67  							ValidateFunc: validateMaxLength(256),
    68  						},
    69  						"compliance_resource_types": {
    70  							Type:     schema.TypeSet,
    71  							Optional: true,
    72  							MaxItems: 100,
    73  							Elem: &schema.Schema{
    74  								Type:         schema.TypeString,
    75  								ValidateFunc: validateMaxLength(256),
    76  							},
    77  							Set: schema.HashString,
    78  						},
    79  						"tag_key": {
    80  							Type:         schema.TypeString,
    81  							Optional:     true,
    82  							ValidateFunc: validateMaxLength(128),
    83  						},
    84  						"tag_value": {
    85  							Type:         schema.TypeString,
    86  							Optional:     true,
    87  							ValidateFunc: validateMaxLength(256),
    88  						},
    89  					},
    90  				},
    91  			},
    92  			"source": {
    93  				Type:     schema.TypeList,
    94  				MaxItems: 1,
    95  				Required: true,
    96  				Elem: &schema.Resource{
    97  					Schema: map[string]*schema.Schema{
    98  						"owner": {
    99  							Type:         schema.TypeString,
   100  							Required:     true,
   101  							ValidateFunc: validateConfigRuleSourceOwner,
   102  						},
   103  						"source_detail": {
   104  							Type:     schema.TypeSet,
   105  							Set:      configRuleSourceDetailsHash,
   106  							Optional: true,
   107  							MaxItems: 25,
   108  							Elem: &schema.Resource{
   109  								Schema: map[string]*schema.Schema{
   110  									"event_source": {
   111  										Type:     schema.TypeString,
   112  										Optional: true,
   113  									},
   114  									"maximum_execution_frequency": {
   115  										Type:         schema.TypeString,
   116  										Optional:     true,
   117  										ValidateFunc: validateConfigExecutionFrequency,
   118  									},
   119  									"message_type": {
   120  										Type:     schema.TypeString,
   121  										Optional: true,
   122  									},
   123  								},
   124  							},
   125  						},
   126  						"source_identifier": {
   127  							Type:         schema.TypeString,
   128  							Required:     true,
   129  							ValidateFunc: validateMaxLength(256),
   130  						},
   131  					},
   132  				},
   133  			},
   134  		},
   135  	}
   136  }
   137  
   138  func resourceAwsConfigConfigRulePut(d *schema.ResourceData, meta interface{}) error {
   139  	conn := meta.(*AWSClient).configconn
   140  
   141  	name := d.Get("name").(string)
   142  	ruleInput := configservice.ConfigRule{
   143  		ConfigRuleName: aws.String(name),
   144  		Source:         expandConfigRuleSource(d.Get("source").([]interface{})),
   145  	}
   146  
   147  	scopes := d.Get("scope").([]interface{})
   148  	if len(scopes) > 0 {
   149  		ruleInput.Scope = expandConfigRuleScope(scopes[0].(map[string]interface{}))
   150  	}
   151  
   152  	if v, ok := d.GetOk("description"); ok {
   153  		ruleInput.Description = aws.String(v.(string))
   154  	}
   155  	if v, ok := d.GetOk("input_parameters"); ok {
   156  		ruleInput.InputParameters = aws.String(v.(string))
   157  	}
   158  	if v, ok := d.GetOk("maximum_execution_frequency"); ok {
   159  		ruleInput.MaximumExecutionFrequency = aws.String(v.(string))
   160  	}
   161  
   162  	input := configservice.PutConfigRuleInput{
   163  		ConfigRule: &ruleInput,
   164  	}
   165  	log.Printf("[DEBUG] Creating AWSConfig config rule: %s", input)
   166  	err := resource.Retry(2*time.Minute, func() *resource.RetryError {
   167  		_, err := conn.PutConfigRule(&input)
   168  		if err != nil {
   169  			if awsErr, ok := err.(awserr.Error); ok {
   170  				if awsErr.Code() == "InsufficientPermissionsException" {
   171  					// IAM is eventually consistent
   172  					return resource.RetryableError(err)
   173  				}
   174  			}
   175  
   176  			return resource.NonRetryableError(fmt.Errorf("Failed to create AWSConfig rule: %s", err))
   177  		}
   178  
   179  		return nil
   180  	})
   181  	if err != nil {
   182  		return err
   183  	}
   184  
   185  	d.SetId(name)
   186  
   187  	log.Printf("[DEBUG] AWSConfig config rule %q created", name)
   188  
   189  	return resourceAwsConfigConfigRuleRead(d, meta)
   190  }
   191  
   192  func resourceAwsConfigConfigRuleRead(d *schema.ResourceData, meta interface{}) error {
   193  	conn := meta.(*AWSClient).configconn
   194  
   195  	out, err := conn.DescribeConfigRules(&configservice.DescribeConfigRulesInput{
   196  		ConfigRuleNames: []*string{aws.String(d.Id())},
   197  	})
   198  	if err != nil {
   199  		if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoSuchConfigRuleException" {
   200  			log.Printf("[WARN] Config Rule %q is gone (NoSuchConfigRuleException)", d.Id())
   201  			d.SetId("")
   202  			return nil
   203  		}
   204  		return err
   205  	}
   206  
   207  	numberOfRules := len(out.ConfigRules)
   208  	if numberOfRules < 1 {
   209  		log.Printf("[WARN] Config Rule %q is gone (no rules found)", d.Id())
   210  		d.SetId("")
   211  		return nil
   212  	}
   213  
   214  	if numberOfRules > 1 {
   215  		return fmt.Errorf("Expected exactly 1 Config Rule, received %d: %#v",
   216  			numberOfRules, out.ConfigRules)
   217  	}
   218  
   219  	log.Printf("[DEBUG] AWS Config config rule received: %s", out)
   220  
   221  	rule := out.ConfigRules[0]
   222  	d.Set("arn", rule.ConfigRuleArn)
   223  	d.Set("rule_id", rule.ConfigRuleId)
   224  	d.Set("name", rule.ConfigRuleName)
   225  	d.Set("description", rule.Description)
   226  	d.Set("input_parameters", rule.InputParameters)
   227  	d.Set("maximum_execution_frequency", rule.MaximumExecutionFrequency)
   228  
   229  	if rule.Scope != nil {
   230  		d.Set("scope", flattenConfigRuleScope(rule.Scope))
   231  	}
   232  
   233  	d.Set("source", flattenConfigRuleSource(rule.Source))
   234  
   235  	return nil
   236  }
   237  
   238  func resourceAwsConfigConfigRuleDelete(d *schema.ResourceData, meta interface{}) error {
   239  	conn := meta.(*AWSClient).configconn
   240  
   241  	name := d.Get("name").(string)
   242  
   243  	log.Printf("[DEBUG] Deleting AWS Config config rule %q", name)
   244  	_, err := conn.DeleteConfigRule(&configservice.DeleteConfigRuleInput{
   245  		ConfigRuleName: aws.String(name),
   246  	})
   247  	if err != nil {
   248  		return fmt.Errorf("Deleting Config Rule failed: %s", err)
   249  	}
   250  
   251  	conf := resource.StateChangeConf{
   252  		Pending: []string{
   253  			configservice.ConfigRuleStateActive,
   254  			configservice.ConfigRuleStateDeleting,
   255  			configservice.ConfigRuleStateDeletingResults,
   256  			configservice.ConfigRuleStateEvaluating,
   257  		},
   258  		Target:  []string{""},
   259  		Timeout: 5 * time.Minute,
   260  		Refresh: func() (interface{}, string, error) {
   261  			out, err := conn.DescribeConfigRules(&configservice.DescribeConfigRulesInput{
   262  				ConfigRuleNames: []*string{aws.String(d.Id())},
   263  			})
   264  			if err != nil {
   265  				if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoSuchConfigRuleException" {
   266  					return 42, "", nil
   267  				}
   268  				return 42, "", fmt.Errorf("Failed to describe config rule %q: %s", d.Id(), err)
   269  			}
   270  			if len(out.ConfigRules) < 1 {
   271  				return 42, "", nil
   272  			}
   273  			rule := out.ConfigRules[0]
   274  			return out, *rule.ConfigRuleState, nil
   275  		},
   276  	}
   277  	_, err = conf.WaitForState()
   278  	if err != nil {
   279  		return err
   280  	}
   281  
   282  	log.Printf("[DEBUG] AWS Config config rule %q deleted", name)
   283  
   284  	d.SetId("")
   285  	return nil
   286  }
   287  
   288  func configRuleSourceDetailsHash(v interface{}) int {
   289  	var buf bytes.Buffer
   290  	m := v.(map[string]interface{})
   291  	if v, ok := m["message_type"]; ok {
   292  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   293  	}
   294  	if v, ok := m["event_source"]; ok {
   295  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   296  	}
   297  	if v, ok := m["maximum_execution_frequency"]; ok {
   298  		buf.WriteString(fmt.Sprintf("%s-", v.(string)))
   299  	}
   300  	return hashcode.String(buf.String())
   301  }