github.com/nathanielks/terraform@v0.6.1-0.20170509030759-13e1a62319dc/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 Default: "aws.config", 114 }, 115 "maximum_execution_frequency": { 116 Type: schema.TypeString, 117 Optional: true, 118 ValidateFunc: validateConfigExecutionFrequency, 119 }, 120 "message_type": { 121 Type: schema.TypeString, 122 Optional: true, 123 }, 124 }, 125 }, 126 }, 127 "source_identifier": { 128 Type: schema.TypeString, 129 Required: true, 130 ValidateFunc: validateMaxLength(256), 131 }, 132 }, 133 }, 134 }, 135 }, 136 } 137 } 138 139 func resourceAwsConfigConfigRulePut(d *schema.ResourceData, meta interface{}) error { 140 conn := meta.(*AWSClient).configconn 141 142 name := d.Get("name").(string) 143 ruleInput := configservice.ConfigRule{ 144 ConfigRuleName: aws.String(name), 145 Source: expandConfigRuleSource(d.Get("source").([]interface{})), 146 } 147 148 scopes := d.Get("scope").([]interface{}) 149 if len(scopes) > 0 { 150 ruleInput.Scope = expandConfigRuleScope(scopes[0].(map[string]interface{})) 151 } 152 153 if v, ok := d.GetOk("description"); ok { 154 ruleInput.Description = aws.String(v.(string)) 155 } 156 if v, ok := d.GetOk("input_parameters"); ok { 157 ruleInput.InputParameters = aws.String(v.(string)) 158 } 159 if v, ok := d.GetOk("maximum_execution_frequency"); ok { 160 ruleInput.MaximumExecutionFrequency = aws.String(v.(string)) 161 } 162 163 input := configservice.PutConfigRuleInput{ 164 ConfigRule: &ruleInput, 165 } 166 log.Printf("[DEBUG] Creating AWSConfig config rule: %s", input) 167 err := resource.Retry(2*time.Minute, func() *resource.RetryError { 168 _, err := conn.PutConfigRule(&input) 169 if err != nil { 170 if awsErr, ok := err.(awserr.Error); ok { 171 if awsErr.Code() == "InsufficientPermissionsException" { 172 // IAM is eventually consistent 173 return resource.RetryableError(err) 174 } 175 } 176 177 return resource.NonRetryableError(fmt.Errorf("Failed to create AWSConfig rule: %s", err)) 178 } 179 180 return nil 181 }) 182 if err != nil { 183 return err 184 } 185 186 d.SetId(name) 187 188 log.Printf("[DEBUG] AWSConfig config rule %q created", name) 189 190 return resourceAwsConfigConfigRuleRead(d, meta) 191 } 192 193 func resourceAwsConfigConfigRuleRead(d *schema.ResourceData, meta interface{}) error { 194 conn := meta.(*AWSClient).configconn 195 196 out, err := conn.DescribeConfigRules(&configservice.DescribeConfigRulesInput{ 197 ConfigRuleNames: []*string{aws.String(d.Id())}, 198 }) 199 if err != nil { 200 if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoSuchConfigRuleException" { 201 log.Printf("[WARN] Config Rule %q is gone (NoSuchConfigRuleException)", d.Id()) 202 d.SetId("") 203 return nil 204 } 205 return err 206 } 207 208 numberOfRules := len(out.ConfigRules) 209 if numberOfRules < 1 { 210 log.Printf("[WARN] Config Rule %q is gone (no rules found)", d.Id()) 211 d.SetId("") 212 return nil 213 } 214 215 if numberOfRules > 1 { 216 return fmt.Errorf("Expected exactly 1 Config Rule, received %d: %#v", 217 numberOfRules, out.ConfigRules) 218 } 219 220 log.Printf("[DEBUG] AWS Config config rule received: %s", out) 221 222 rule := out.ConfigRules[0] 223 d.Set("arn", rule.ConfigRuleArn) 224 d.Set("rule_id", rule.ConfigRuleId) 225 d.Set("name", rule.ConfigRuleName) 226 d.Set("description", rule.Description) 227 d.Set("input_parameters", rule.InputParameters) 228 d.Set("maximum_execution_frequency", rule.MaximumExecutionFrequency) 229 230 if rule.Scope != nil { 231 d.Set("scope", flattenConfigRuleScope(rule.Scope)) 232 } 233 234 d.Set("source", flattenConfigRuleSource(rule.Source)) 235 236 return nil 237 } 238 239 func resourceAwsConfigConfigRuleDelete(d *schema.ResourceData, meta interface{}) error { 240 conn := meta.(*AWSClient).configconn 241 242 name := d.Get("name").(string) 243 244 log.Printf("[DEBUG] Deleting AWS Config config rule %q", name) 245 err := resource.Retry(2*time.Minute, func() *resource.RetryError { 246 _, err := conn.DeleteConfigRule(&configservice.DeleteConfigRuleInput{ 247 ConfigRuleName: aws.String(name), 248 }) 249 if err != nil { 250 if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "ResourceInUseException" { 251 return resource.RetryableError(err) 252 } 253 return resource.NonRetryableError(err) 254 } 255 return nil 256 }) 257 if err != nil { 258 return fmt.Errorf("Deleting Config Rule failed: %s", err) 259 } 260 261 conf := resource.StateChangeConf{ 262 Pending: []string{ 263 configservice.ConfigRuleStateActive, 264 configservice.ConfigRuleStateDeleting, 265 configservice.ConfigRuleStateDeletingResults, 266 configservice.ConfigRuleStateEvaluating, 267 }, 268 Target: []string{""}, 269 Timeout: 5 * time.Minute, 270 Refresh: func() (interface{}, string, error) { 271 out, err := conn.DescribeConfigRules(&configservice.DescribeConfigRulesInput{ 272 ConfigRuleNames: []*string{aws.String(d.Id())}, 273 }) 274 if err != nil { 275 if awsErr, ok := err.(awserr.Error); ok && awsErr.Code() == "NoSuchConfigRuleException" { 276 return 42, "", nil 277 } 278 return 42, "", fmt.Errorf("Failed to describe config rule %q: %s", d.Id(), err) 279 } 280 if len(out.ConfigRules) < 1 { 281 return 42, "", nil 282 } 283 rule := out.ConfigRules[0] 284 return out, *rule.ConfigRuleState, nil 285 }, 286 } 287 _, err = conf.WaitForState() 288 if err != nil { 289 return err 290 } 291 292 log.Printf("[DEBUG] AWS Config config rule %q deleted", name) 293 294 d.SetId("") 295 return nil 296 } 297 298 func configRuleSourceDetailsHash(v interface{}) int { 299 var buf bytes.Buffer 300 m := v.(map[string]interface{}) 301 if v, ok := m["message_type"]; ok { 302 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 303 } 304 if v, ok := m["event_source"]; ok { 305 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 306 } 307 if v, ok := m["maximum_execution_frequency"]; ok { 308 buf.WriteString(fmt.Sprintf("%s-", v.(string))) 309 } 310 return hashcode.String(buf.String()) 311 }