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 }